jevstrudel.git / tools / dev / preview.mjs
1#!/usr/bin/env node

buck2 run //:preview: what nix run .#deploy would publish, served locally on http://localhost:4324/ for a last listen before deploying.

It is the deploy's own inputs: the flake's static build (the same derivation the deploy uploads as assets) and worker/ in its production environment (--env "": the Jev relay, no MCP hub), under wrangler dev and supervised like the dev server's Worker (supervise.mjs). No hot reload: rerun it after a change.

10import { execFileSync } from 'node:child_process';
11import { migrateLocal } from './migrate.mjs';
12import { has, superviseWorker } from './supervise.mjs';

The one place the preview's port is set. Not 4322/4323 (the dev server) or 8080 (Gerrit on this host).

16export const PREVIEW_PORT = 4324;
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}

worker/ is a workspace package with dependencies of its own (the WebAuthn library); the deploy bundles them from the same lockfile (nix/worker-closure.mjs).

30execFileSync('pnpm', ['install', '--frozen-lockfile', '--prefer-offline', '--filter', '@jevstrudel/worker'], {
31  stdio: 'inherit',
32});
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();

its own local state, apart from the dev server's Worker

41const PERSIST = 'worker/.wrangler/preview';
42migrateLocal({ env: '', persistTo: PERSIST });
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  });