mirror of
https://github.com/stack-auth/stack.git
synced 2026-06-04 21:04:37 +08:00
Make demo dev resilient to dashboard build failures (#1542)
This commit is contained in:
parent
338f3ce60c
commit
cda1510e93
@ -7,7 +7,7 @@
|
||||
"scripts": {
|
||||
"typecheck": "tsc --noEmit",
|
||||
"clean": "rimraf .next && rimraf node_modules",
|
||||
"dev": "NEXT_PUBLIC_HEXCLAVE_LOCAL_DASHBOARD_PORT=${NEXT_PUBLIC_HEXCLAVE_PORT_PREFIX:-81}42 pnpm -w run cli -- dev --config-file=./hexclave.config.ts -- pnpm --dir examples/demo run dev:inner",
|
||||
"dev": "NEXT_PUBLIC_HEXCLAVE_LOCAL_DASHBOARD_PORT=${NEXT_PUBLIC_HEXCLAVE_PORT_PREFIX:-81}42 node scripts/dev-with-retry.mjs",
|
||||
"dev:inner": "next dev --turbopack --port ${NEXT_PUBLIC_HEXCLAVE_PORT_PREFIX:-81}03",
|
||||
"build": "next build",
|
||||
"start": "next start --port ${NEXT_PUBLIC_HEXCLAVE_PORT_PREFIX:-81}03",
|
||||
|
||||
119
examples/demo/scripts/dev-with-retry.mjs
Normal file
119
examples/demo/scripts/dev-with-retry.mjs
Normal file
@ -0,0 +1,119 @@
|
||||
#!/usr/bin/env node
|
||||
|
||||
// Resilient wrapper for the demo dev command.
|
||||
//
|
||||
// The demo dev flow runs `pnpm -w run cli`, which internally builds the CLI
|
||||
// package (and its dependency, dashboard build:rde-standalone). If that build
|
||||
// fails, this process would normally exit, and because the root dev script uses
|
||||
// `concurrently -k`, the entire dev server would die.
|
||||
//
|
||||
// This wrapper catches non-zero exits and watches for file changes in the
|
||||
// dashboard and packages directories before retrying, so a transient build
|
||||
// failure doesn't tear down the whole dev server.
|
||||
|
||||
import { spawn } from "node:child_process";
|
||||
import { watch } from "node:fs";
|
||||
import { join, resolve } from "node:path";
|
||||
import { setTimeout as sleep } from "node:timers/promises";
|
||||
|
||||
const scriptDir = import.meta.dirname;
|
||||
const demoRoot = resolve(scriptDir, "..");
|
||||
const repoRoot = resolve(demoRoot, "../..");
|
||||
|
||||
const LOG_PREFIX = "[Hexclave dev-retry] ";
|
||||
const RETRY_DEBOUNCE_MS = 2_000;
|
||||
|
||||
function log(message) {
|
||||
console.error(`${LOG_PREFIX}${message}`);
|
||||
}
|
||||
|
||||
function runCliDev() {
|
||||
return new Promise((resolvePromise, reject) => {
|
||||
const child = spawn("pnpm", [
|
||||
"-w", "run", "cli", "--",
|
||||
"dev",
|
||||
"--config-file=./hexclave.config.ts",
|
||||
"--",
|
||||
"pnpm", "--dir", "examples/demo", "run", "dev:inner",
|
||||
], {
|
||||
stdio: "inherit",
|
||||
env: process.env,
|
||||
});
|
||||
|
||||
let signalled = false;
|
||||
|
||||
const forwardSigint = () => { signalled = true; child.kill("SIGINT"); };
|
||||
const forwardSigterm = () => { signalled = true; child.kill("SIGTERM"); };
|
||||
process.on("SIGINT", forwardSigint);
|
||||
process.on("SIGTERM", forwardSigterm);
|
||||
|
||||
child.on("close", (code) => {
|
||||
process.off("SIGINT", forwardSigint);
|
||||
process.off("SIGTERM", forwardSigterm);
|
||||
resolvePromise({ code: code ?? 1, signalled });
|
||||
});
|
||||
child.on("error", (err) => {
|
||||
process.off("SIGINT", forwardSigint);
|
||||
process.off("SIGTERM", forwardSigterm);
|
||||
reject(err);
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
function waitForFileChanges() {
|
||||
return new Promise((resolvePromise) => {
|
||||
const watchDirs = [
|
||||
join(repoRoot, "apps", "dashboard"),
|
||||
join(repoRoot, "packages"),
|
||||
];
|
||||
const watchers = [];
|
||||
let resolved = false;
|
||||
|
||||
const done = () => {
|
||||
if (resolved) return;
|
||||
resolved = true;
|
||||
for (const w of watchers) {
|
||||
try { w.close(); } catch { /* ignore */ }
|
||||
}
|
||||
resolvePromise();
|
||||
};
|
||||
|
||||
for (const dir of watchDirs) {
|
||||
try {
|
||||
const w = watch(dir, { recursive: true }, done);
|
||||
w.on("error", () => { /* ignore watch errors */ });
|
||||
watchers.push(w);
|
||||
} catch {
|
||||
// directory might not exist yet
|
||||
}
|
||||
}
|
||||
|
||||
// Fallback: if no watchers could be set up, resolve after a timeout so we
|
||||
// don't block forever.
|
||||
if (watchers.length === 0) {
|
||||
log("Could not set up file watchers. Will retry after a delay.");
|
||||
setTimeout(done, 10_000);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
async function main() {
|
||||
// eslint-disable-next-line @typescript-eslint/no-unnecessary-condition
|
||||
while (true) {
|
||||
const { code, signalled } = await runCliDev();
|
||||
|
||||
if (signalled || code === 0) {
|
||||
process.exit(code);
|
||||
}
|
||||
|
||||
log(`Dev command exited with code ${code}. Watching for file changes before retrying...`);
|
||||
await waitForFileChanges();
|
||||
log(`Change detected. Retrying in ${RETRY_DEBOUNCE_MS / 1000}s...`);
|
||||
await sleep(RETRY_DEBOUNCE_MS);
|
||||
}
|
||||
}
|
||||
|
||||
main().catch((err) => {
|
||||
console.error(err);
|
||||
process.exit(1);
|
||||
});
|
||||
Loading…
Reference in New Issue
Block a user