diff --git a/DECISIONS.md b/DECISIONS.md index 58b7f67..aecc526 100644 --- a/DECISIONS.md +++ b/DECISIONS.md @@ -182,6 +182,30 @@ hydrates when `#root` already has children (a real build/preview load) and falls `release-website.yml` needed no changes - `pnpm run build` still ends with static files in `website/dist`, just with real markup already in them. +**No-JS visitors get a warning banner, kept outside the React tree on purpose.** A ` diff --git a/website/package.json b/website/package.json index 9d68880..61d9b7f 100644 --- a/website/package.json +++ b/website/package.json @@ -7,6 +7,7 @@ "dev": "vite", "build": "tsc -b && vite build && vite build --config vite.ssr.config.ts --ssr src/entry-server.tsx --outDir dist-ssr && node scripts/prerender.mjs", "preview": "vite preview", + "preview:watch": "node scripts/watch-preview.mjs", "typecheck": "tsc -b --noEmit", "clean": "rm -rf dist dist-ssr .vite" }, diff --git a/website/scripts/watch-preview.mjs b/website/scripts/watch-preview.mjs new file mode 100644 index 0000000..117da6d --- /dev/null +++ b/website/scripts/watch-preview.mjs @@ -0,0 +1,52 @@ +// Rebuilds on every source change and serves the result, for debugging the +// prerendered/SSR output without a manual build+preview cycle each time. No +// hot reload: `vite preview` reads dist/ from disk per request, so a +// browser refresh after each rebuild is enough - see website/README.md for +// why this doesn't try to preserve HMR too. +import { spawn } from 'node:child_process'; +import { watch } from 'node:fs'; +import path from 'node:path'; +import { fileURLToPath } from 'node:url'; + +const websiteDir = path.dirname(path.dirname(fileURLToPath(import.meta.url))); + +function run(command, args) { + return new Promise((resolve, reject) => { + const child = spawn(command, args, { cwd: websiteDir, stdio: 'inherit', shell: true }); + child.on('exit', code => (code === 0 ? resolve() : reject(new Error(`${command} exited with code ${code}`)))); + }); +} + +let building = false; +let rebuildQueued = false; + +async function rebuild() { + if (building) { + rebuildQueued = true; + return; + } + + building = true; + console.log('\n[watch] building...'); + + try { + await run('pnpm', ['run', 'build']); + console.log('[watch] build done - refresh your browser'); + } catch (error) { + console.error('[watch] build failed:', error.message); + } + + building = false; + + if (rebuildQueued) { + rebuildQueued = false; + await rebuild(); + } +} + +await rebuild(); + +spawn('pnpm', ['run', 'preview'], { cwd: websiteDir, stdio: 'inherit', shell: true }); + +watch(path.join(websiteDir, 'src'), { recursive: true }, () => rebuild()); +watch(path.join(websiteDir, 'index.html'), () => rebuild());