mirror of
https://github.com/fabro-sh/fabro.git
synced 2026-09-06 08:18:58 +00:00
In --watch-web dev mode the server silently fell back to the embedded SPA snapshot whenever the disk dist/ was missing or partial, so edits to the web app appeared not to take effect with no error anywhere. This change makes the dev loop visible and quick: - static_files plumbs a dev_disk_only flag from RouterOptions.watch_web into the fallback handler. When set, embedded fallback is skipped and a miss returns 503 with a "build in progress" auto-refresh page. - The web build script writes each rebuild into apps/fabro-web/.dist-builds/<id>/ and atomically replaces the dist symlink via rename(2), so requests never observe a partially-populated dist tree. - Tailwind is invoked through node_modules/.bin/tailwindcss directly instead of bunx, removing a per-rebuild bun add @latest --force round- trip and dropping rebuild time from ~10s to ~250ms. - load_asset no longer falls through to the workspace dist/ when an explicit asset_root is provided, restoring test isolation when a real dev build is sitting next door. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
94 lines
2.6 KiB
TypeScript
94 lines
2.6 KiB
TypeScript
import { test, expect } from "bun:test";
|
|
import { existsSync } from "node:fs";
|
|
import { lstat, readdir, readlink } from "node:fs/promises";
|
|
import { basename, join } from "node:path";
|
|
|
|
const root = Bun.fileURLToPath(new URL("..", import.meta.url));
|
|
|
|
async function runBuild() {
|
|
const process = Bun.spawn(["bun", "run", "scripts/build.ts"], {
|
|
cwd: root,
|
|
stdout: "pipe",
|
|
stderr: "pipe",
|
|
});
|
|
|
|
const code = await process.exited;
|
|
if (code !== 0) {
|
|
const stderr = await new Response(process.stderr).text();
|
|
const stdout = await new Response(process.stdout).text();
|
|
throw new Error(
|
|
`build failed with code ${code}\nstdout:\n${stdout}\nstderr:\n${stderr}`,
|
|
);
|
|
}
|
|
}
|
|
|
|
test("production build copies Pierre worker assets", async () => {
|
|
await runBuild();
|
|
|
|
const workerDist = join(root, "dist", "assets", "pierre-diffs-worker");
|
|
expect(existsSync(join(workerDist, "worker-portable.js"))).toBe(true);
|
|
|
|
const upstreamWorkerDir = join(
|
|
root,
|
|
"node_modules",
|
|
"@pierre",
|
|
"diffs",
|
|
"dist",
|
|
"worker",
|
|
);
|
|
const wasmFiles = (await readdir(upstreamWorkerDir))
|
|
.filter((file) => /^wasm-.*\.js$/.test(file))
|
|
.map((file) => basename(file));
|
|
|
|
for (const wasmFile of wasmFiles) {
|
|
expect(existsSync(join(workerDist, wasmFile))).toBe(true);
|
|
}
|
|
});
|
|
|
|
test("dist is a symlink into .dist-builds and old builds are pruned", async () => {
|
|
await runBuild();
|
|
await runBuild();
|
|
|
|
const distPath = join(root, "dist");
|
|
const stat = await lstat(distPath);
|
|
expect(stat.isSymbolicLink()).toBe(true);
|
|
|
|
const target = await readlink(distPath);
|
|
expect(target.startsWith(".dist-builds/")).toBe(true);
|
|
|
|
const buildId = target.slice(".dist-builds/".length);
|
|
const buildsRoot = join(root, ".dist-builds");
|
|
const remaining = await readdir(buildsRoot);
|
|
expect(remaining).toEqual([buildId]);
|
|
|
|
expect(existsSync(join(distPath, "index.html"))).toBe(true);
|
|
});
|
|
|
|
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([0, 130]).toContain(await process.exited);
|
|
});
|