diff --git a/apps/fabro-web/scripts/build.test.ts b/apps/fabro-web/scripts/build.test.ts new file mode 100644 index 000000000..5a038cdcb --- /dev/null +++ b/apps/fabro-web/scripts/build.test.ts @@ -0,0 +1,32 @@ +import { test, expect } from "bun:test"; + +const root = Bun.fileURLToPath(new URL("..", import.meta.url)); + +test("watch mode keeps running until interrupted", async () => { + const process = Bun.spawn([ + "bun", + "run", + "scripts/build.ts", + "--watch", + ], { + cwd: root, + stdout: "pipe", + stderr: "pipe", + }); + + const result = await Promise.race([ + process.exited.then((code) => ({ kind: "exited" as const, code })), + Bun.sleep(1000).then(() => ({ kind: "running" as const })), + ]); + + if (result.kind === "exited") { + const stderr = await new Response(process.stderr).text(); + const stdout = await new Response(process.stdout).text(); + throw new Error( + `watch process exited unexpectedly with code ${result.code}\nstdout:\n${stdout}\nstderr:\n${stderr}`, + ); + } + + process.kill("SIGINT"); + expect(await process.exited).toBe(0); +}); diff --git a/apps/fabro-web/scripts/build.ts b/apps/fabro-web/scripts/build.ts index 707de22c5..292e78567 100644 --- a/apps/fabro-web/scripts/build.ts +++ b/apps/fabro-web/scripts/build.ts @@ -1,3 +1,4 @@ +import { watch as fsWatch } from "node:fs"; import { cp, mkdir, readFile, rm, writeFile } from "node:fs/promises"; import { join, relative } from "node:path"; @@ -79,19 +80,37 @@ async function main() { } await buildOnce(); - const watcher = Bun.watch({ - paths: [join(rootPath, "app"), publicDir, templatePath], - async onChange() { + let building = false; + let rebuildQueued = false; + + async function rebuild() { + if (building) { + rebuildQueued = true; + return; + } + + building = true; + do { + rebuildQueued = false; try { await buildOnce(); } catch (error) { console.error(error); } - }, - }); + } while (rebuildQueued); + building = false; + } + + const watchers = [ + fsWatch(join(rootPath, "app"), { recursive: true }, rebuild), + fsWatch(publicDir, { recursive: true }, rebuild), + fsWatch(templatePath, rebuild), + ]; process.on("SIGINT", () => { - watcher.stop(); + for (const watcher of watchers) { + watcher.close(); + } process.exit(0); }); }