// Copies the production build (app/dist) into the repository root, so the // webserver can serve the repo checkout directly as static files — no // server-side build step, no special MIME-type config, no reverse proxy // required. Run automatically as part of `npm run build`. // // node scripts/deploy.mjs // import { readdir, rm, cp, unlink, copyFile } from "node:fs/promises"; import { dirname, join, resolve } from "node:path"; import { fileURLToPath } from "node:url"; const __dirname = dirname(fileURLToPath(import.meta.url)); const DIST = resolve(__dirname, "../dist"); const REPO_ROOT = resolve(__dirname, "../../"); const entries = await readdir(DIST, { withFileTypes: true }); for (const entry of entries) { const src = join(DIST, entry.name); const dest = join(REPO_ROOT, entry.name); if (entry.isDirectory()) { // Directories (assets/, icons/) are pure build output — wipe and replace // so stale, superseded hashed filenames don't pile up. await rm(dest, { recursive: true, force: true }); await cp(src, dest, { recursive: true }); console.log(` dir ${entry.name}/`); continue; } // Hashed, content-addressed files (e.g. workbox-.js) change name // between builds — remove any previous versions before copying the new one. const hashedPrefixMatch = entry.name.match(/^(workbox-)[0-9a-f]+(\.js)$/); if (hashedPrefixMatch) { const [, prefix, ext] = hashedPrefixMatch; const siblings = await readdir(REPO_ROOT); for (const sibling of siblings) { if (sibling.startsWith(prefix) && sibling.endsWith(ext) && sibling !== entry.name) { await unlink(join(REPO_ROOT, sibling)); } } } await copyFile(src, dest); console.log(` file ${entry.name}`); } console.log(`\nDeployed build output from ${DIST} -> ${REPO_ROOT}`);