jevstrudel.git / tools / dev / preview.mjs
1#!/usr/bin/env node
2// `buck2 run //:preview`: what `nix run .#deploy` would publish, served
3// locally on http://localhost:4324/ for a last listen before deploying.
4//
5// It is the deploy's own inputs: the flake's `static` build (the same
6// derivation the deploy uploads as assets) and worker/ in its production
7// environment (`--env ""`: the Jev relay, no MCP hub), under `wrangler dev`
8// and supervised like the dev server's Worker (supervise.mjs). No hot
9// reload: rerun it after a change.
10import { execFileSync } from 'node:child_process';
11import { migrateLocal } from './migrate.mjs';
12import { has, superviseWorker } from './supervise.mjs';
13
14// The one place the preview's port is set. Not 4322/4323 (the dev server)
15// or 8080 (Gerrit on this host).
16export const PREVIEW_PORT = 4324;
17
18process.chdir(execFileSync('git', ['rev-parse', '--show-toplevel'], { encoding: 'utf8' }).trim());
19
20for (const tool of ['nix', 'pnpm', 'wrangler', 'setpriv']) {
21  if (!has(tool)) {
22    console.error(`preview: ${tool} is not on PATH; run inside the devshell (nix develop, or direnv)`);
23    process.exit(1);
24  }
25}
26
27// worker/ is a workspace package with dependencies of its own (the
28// WebAuthn library); the deploy bundles them from the same lockfile
29// (nix/worker-closure.mjs).
30execFileSync('pnpm', ['install', '--frozen-lockfile', '--prefer-offline', '--filter', '@jevstrudel/worker'], {
31  stdio: 'inherit',
32});
33
34console.error('preview: building .#static, the site the deploy uploads');
35const assets = execFileSync('nix', ['build', '-L', '.#static', '--no-link', '--print-out-paths'], {
36  encoding: 'utf8',
37  stdio: ['ignore', 'pipe', 'inherit'],
38}).trim();
39
40// its own local state, apart from the dev server's Worker
41const PERSIST = 'worker/.wrangler/preview';
42migrateLocal({ env: '', persistTo: PERSIST });
43
44const worker = superviseWorker({
45  name: 'preview',
46  port: PREVIEW_PORT,
47  args: [
48    '--env',
49    '',
50    '--assets',
51    assets,
52    '--port',
53    String(PREVIEW_PORT),
54    '--persist-to',
55    PERSIST,
56  ],
57});
58console.error(`preview: ${assets} with the production Worker on http://localhost:${PREVIEW_PORT}/`);
59
60for (const signal of ['SIGINT', 'SIGTERM'])
61  process.on(signal, () => {
62    worker.stop();
63    setTimeout(() => process.exit(0), 500).unref();
64  });