73 lines
2.8 KiB
JavaScript
73 lines
2.8 KiB
JavaScript
import { Command } from "commander";
|
|
import path from "path";
|
|
import grabDirNames from "../../utils/grab-dir-names";
|
|
import writeErrorFile from "../../functions/write-error-file";
|
|
import { existsSync, rmSync } from "fs";
|
|
const { BUNDLER_CTX_MAP_JSON, SSR_BUNDLER_CTX_MAP_JSON, BUNX_BUNDLER_ERROR_EXIT_FILE, } = grabDirNames();
|
|
const MAX_RETRIES = 5;
|
|
const RETRY_RESET_AFTER_MS = 10000;
|
|
export default function () {
|
|
return new Command("dev")
|
|
.description("Run development server")
|
|
.action(async () => {
|
|
try {
|
|
rmSync(SSR_BUNDLER_CTX_MAP_JSON, { recursive: true });
|
|
rmSync(BUNDLER_CTX_MAP_JSON, { recursive: true });
|
|
// A stale error file from a previous session makes the bundler
|
|
// run in "silent" mode and pages fail with misleading
|
|
// "Application Error" messages until the first rebuild.
|
|
rmSync(BUNX_BUNDLER_ERROR_EXIT_FILE, { force: true });
|
|
}
|
|
catch (error) { }
|
|
await dev();
|
|
});
|
|
}
|
|
async function dev() {
|
|
// A loop, not recursion: each restart would otherwise keep the previous
|
|
// call (and its subprocess) alive for the supervisor's whole lifetime.
|
|
let retries = 0;
|
|
while (true) {
|
|
if (retries >= MAX_RETRIES) {
|
|
console.error(`Dev server crashed ${MAX_RETRIES} times. Exiting.`);
|
|
process.exit(1);
|
|
}
|
|
const dev_spawn_file = path.resolve(__dirname, "dev-spawn.ts");
|
|
const dev_spawn_js_file = path.resolve(__dirname, "dev-spawn.js");
|
|
const final_spawn_file = existsSync(dev_spawn_js_file)
|
|
? dev_spawn_js_file
|
|
: dev_spawn_file;
|
|
const spawn_options = {
|
|
cmd: ["bun", final_spawn_file],
|
|
stdio: ["inherit", "inherit", "inherit"],
|
|
async onExit(subprocess, exitCode, signalCode, error) {
|
|
writeErrorFile({ exitCode, error });
|
|
},
|
|
env: {
|
|
...process.env,
|
|
NODE_ENV: "development",
|
|
},
|
|
};
|
|
const started_at = Date.now();
|
|
let child_process;
|
|
try {
|
|
child_process = Bun.spawn(spawn_options);
|
|
}
|
|
catch (error) {
|
|
console.error(`Failed to start dev process:`, error);
|
|
retries++;
|
|
continue;
|
|
}
|
|
const exited = await child_process.exited;
|
|
// A null exit means the child was killed by a signal (e.g. Ctrl+C
|
|
// in the shared terminal), which we must not restart.
|
|
if (exited == null) {
|
|
return;
|
|
}
|
|
// Restart on any numeric exit (0 included: the server should never
|
|
// exit cleanly). Only consecutive quick crashes count toward the
|
|
// limit; a child that ran for a while starts the count over.
|
|
retries =
|
|
Date.now() - started_at >= RETRY_RESET_AFTER_MS ? 1 : retries + 1;
|
|
}
|
|
}
|