#!/usr/bin/env node // ============================================================ // build-client.mjs — Compiles client/**/*.ts to public/dist/. // // Strangler-fig pattern: TS modules live under client/, legacy // IIFE files stay under public/js/ until each is migrated. // Each top-level .ts file in client/ becomes one ES-module bundle // in public/dist/ that index.html can load via: // // // Run: // npm run build:client # one-shot // npm run build:client -- --watch # rebuild on change // ============================================================ import { build, context } from 'esbuild'; import { readdirSync, mkdirSync, existsSync } from 'node:fs'; import { resolve, dirname } from 'node:path'; import { fileURLToPath } from 'node:url'; const __dirname = dirname(fileURLToPath(import.meta.url)); const PROJECT_ROOT = resolve(__dirname, '..'); const SRC = resolve(PROJECT_ROOT, 'client'); const OUT = resolve(PROJECT_ROOT, 'public/dist'); const watch = process.argv.includes('--watch'); if (!existsSync(SRC)) { console.error(`[build-client] Source dir does not exist: ${SRC}`); process.exit(1); } mkdirSync(OUT, { recursive: true }); // Each top-level .ts/.tsx file in client/ is a separate entry point. // Sub-directories are imported by the entries via TS imports — they // are NOT separate entries, they get bundled into their parent. const entryFiles = readdirSync(SRC, { withFileTypes: true }) .filter(d => d.isFile() && /\.tsx?$/.test(d.name)) .map(d => resolve(SRC, d.name)); if (entryFiles.length === 0) { console.error(`[build-client] No .ts entry points found in ${SRC}`); process.exit(1); } const buildOpts = { entryPoints: entryFiles, outdir: OUT, bundle: true, format: 'esm', target: 'es2022', platform: 'browser', sourcemap: true, minify: !watch, // unminified in watch mode for easier debugging logLevel: 'info', }; if (watch) { const ctx = await context(buildOpts); await ctx.watch(); console.log('[build-client] Watching for changes…'); } else { await build(buildOpts); console.log(`[build-client] Built ${entryFiles.length} entry point(s) → ${OUT}`); }