import * as esbuild from 'esbuild'; import { mkdir, rm, writeFile } from 'node:fs/promises'; import path from 'node:path'; export const outdir = 'dist/assets'; export function buildOptions({ dev = false } = {}) { return { entryPoints: [ { in: 'client/js/main.js', out: 'app' }, { in: 'client/css/main.css', out: 'app' }, ], outdir, bundle: true, format: 'esm', minify: !dev, sourcemap: dev ? 'linked' : false, metafile: true, entryNames: '[name]-[hash]', assetNames: '[name]-[hash]', loader: { '.woff2': 'file', '.woff': 'file' }, // Old enough that esbuild lowers CSS nesting for Safari 15/16 target: ['chrome109', 'firefox115', 'safari15.4'], logLevel: 'info', }; } // Maps "app.js" -> "/assets/app-HASH.js" so templates don't need to know the hash. export async function writeManifest(metafile) { const manifest = {}; for (const [file, output] of Object.entries(metafile.outputs)) { if (!output.entryPoint) continue; const base = path.basename(file); const key = base.replace(/-[A-Z0-9]{8}(\.\w+)$/, '$1'); manifest[key] = '/assets/' + base; } await writeFile('dist/manifest.json', JSON.stringify(manifest, null, 2)); } if (import.meta.url === `file://${process.argv[1]}`) { await rm('dist', { recursive: true, force: true }); await mkdir(outdir, { recursive: true }); const result = await esbuild.build(buildOptions()); await writeManifest(result.metafile); }