Refactor start and dev commands. Start in child processes. Handle errors better
This commit is contained in:
@@ -7,9 +7,11 @@ import grabClientHydrationScript from "./grab-client-hydration-script";
|
||||
import path from "path";
|
||||
import virtualFilesPlugin from "./plugins/virtual-files-plugin";
|
||||
import esbuildCTXArtifactTracker from "./plugins/esbuild-ctx-artifact-tracker";
|
||||
const { HYDRATION_DST_DIR, BUNX_HYDRATION_SRC_DIR } = grabDirNames();
|
||||
import { existsSync } from "fs";
|
||||
const { HYDRATION_DST_DIR, BUNX_HYDRATION_SRC_DIR, BUNX_BUNDLER_ERROR_EXIT_FILE, } = grabDirNames();
|
||||
export default async function allPagesESBuildContextBundler(params) {
|
||||
try {
|
||||
const did_process_exit_because_of_bundler_error = existsSync(BUNX_BUNDLER_ERROR_EXIT_FILE);
|
||||
const pages = grabAllPages({ exclude_api: true });
|
||||
global.PAGE_FILES = pages;
|
||||
const dev = isDevelopment();
|
||||
@@ -59,6 +61,9 @@ export default async function allPagesESBuildContextBundler(params) {
|
||||
"react/jsx-runtime",
|
||||
"react/jsx-dev-runtime",
|
||||
],
|
||||
logLevel: did_process_exit_because_of_bundler_error
|
||||
? "silent"
|
||||
: undefined,
|
||||
});
|
||||
await global.BUNDLER_CTX.rebuild();
|
||||
}
|
||||
|
||||
@@ -4,9 +4,15 @@ import grabArtifactsFromBundledResults from "../grab-artifacts-from-bundled-resu
|
||||
import buildOnstartErrorHandler from "../build-on-start-error-handler";
|
||||
import _ from "lodash";
|
||||
import pagesSSRBundler from "../pages-ssr-bundler";
|
||||
import grabDirNames from "../../../utils/grab-dir-names";
|
||||
import { cpSync, existsSync, mkdirSync, rmSync } from "fs";
|
||||
import fullRebuild from "../../server/full-rebuild";
|
||||
import path from "path";
|
||||
import cleanupLogsDirs from "../../cleanup-logs-dir";
|
||||
const { BUNX_BUNDLER_ERROR_EXIT_FILE, BUNX_ERROR_LOGS_DIR } = grabDirNames();
|
||||
let build_start = 0;
|
||||
let build_starts = 0;
|
||||
const MAX_BUILD_STARTS = 5;
|
||||
const MAX_BUILD_STARTS = 2;
|
||||
export default function esbuildCTXArtifactTracker({ entryToPage, post_build_fn, }) {
|
||||
const artifactTracker = {
|
||||
name: "artifact-tracker",
|
||||
@@ -14,8 +20,11 @@ export default function esbuildCTXArtifactTracker({ entryToPage, post_build_fn,
|
||||
build.onStart(async () => {
|
||||
build_starts++;
|
||||
build_start = performance.now();
|
||||
if (build_starts == MAX_BUILD_STARTS) {
|
||||
const does_error_file_exist = existsSync(BUNX_BUNDLER_ERROR_EXIT_FILE);
|
||||
if (build_starts == MAX_BUILD_STARTS &&
|
||||
!does_error_file_exist) {
|
||||
await buildOnstartErrorHandler();
|
||||
process.exit(1);
|
||||
}
|
||||
});
|
||||
build.onEnd((result) => {
|
||||
@@ -41,7 +50,17 @@ export default function esbuildCTXArtifactTracker({ entryToPage, post_build_fn,
|
||||
global.RECOMPILING = false;
|
||||
global.IS_SERVER_COMPONENT = false;
|
||||
build_starts = 0;
|
||||
pagesSSRBundler();
|
||||
const does_error_file_exist = existsSync(BUNX_BUNDLER_ERROR_EXIT_FILE);
|
||||
if (does_error_file_exist) {
|
||||
mkdirSync(BUNX_ERROR_LOGS_DIR, { recursive: true });
|
||||
cpSync(BUNX_BUNDLER_ERROR_EXIT_FILE, path.join(BUNX_ERROR_LOGS_DIR, `${Date.now()}.log`));
|
||||
rmSync(BUNX_BUNDLER_ERROR_EXIT_FILE, { force: true });
|
||||
cleanupLogsDirs();
|
||||
fullRebuild();
|
||||
}
|
||||
else {
|
||||
pagesSSRBundler();
|
||||
}
|
||||
// if (global.SSR_BUNDLER_CTX) {
|
||||
// global.SSR_BUNDLER_CTX.rebuild();
|
||||
// } else {
|
||||
|
||||
Vendored
+6
-6
@@ -48,9 +48,9 @@ export default async function bunextInit() {
|
||||
cron();
|
||||
}
|
||||
}
|
||||
process.on("exit", (code) => {
|
||||
Bun.spawn([process.execPath, ...process.argv.slice(1)], {
|
||||
stdio: ["inherit", "inherit", "inherit"],
|
||||
env: process.env,
|
||||
});
|
||||
});
|
||||
// process.on("exit", (code) => {
|
||||
// Bun.spawn([process.execPath, ...process.argv.slice(1)], {
|
||||
// stdio: ["inherit", "inherit", "inherit"],
|
||||
// env: process.env,
|
||||
// });
|
||||
// });
|
||||
|
||||
Vendored
+1
@@ -0,0 +1 @@
|
||||
export default function cleanupLogsDirs(): void;
|
||||
Vendored
+48
@@ -0,0 +1,48 @@
|
||||
import path from "path";
|
||||
import { mkdirSync, readdirSync, rmSync, statSync, writeFileSync } from "fs";
|
||||
import grabDirNames from "../utils/grab-dir-names";
|
||||
import grabConstants from "../utils/grab-constants";
|
||||
import { AppData } from "../data/app-data";
|
||||
const { BUNX_LOGS_DIR } = grabDirNames();
|
||||
export default function cleanupLogsDirs() {
|
||||
const logs_dirs = readdirSync(BUNX_LOGS_DIR);
|
||||
const { config } = grabConstants();
|
||||
const MAX_LOGS = config.max_logs || AppData["DefaultMaxLogs"];
|
||||
for (let i = 0; i < logs_dirs.length; i++) {
|
||||
const dir = logs_dirs[i];
|
||||
const full_path = path.join(BUNX_LOGS_DIR, dir);
|
||||
const path_stats = statSync(full_path);
|
||||
if (!path_stats.isDirectory()) {
|
||||
continue;
|
||||
}
|
||||
const sub_dir_files = readdirSync(full_path).sort((a, b) => {
|
||||
const timestamp_a = Number(a.split(".")[0]);
|
||||
const timestamp_b = Number(b.split(".")[0]);
|
||||
if (timestamp_a > timestamp_b)
|
||||
return 1;
|
||||
return -1;
|
||||
});
|
||||
for (let j = 0; j < sub_dir_files.length; j++) {
|
||||
const sub_dir_file = sub_dir_files[j];
|
||||
const sub_dir_file_full_path = path.join(full_path, sub_dir_file);
|
||||
const sub_dir_file_Stats = statSync(sub_dir_file_full_path);
|
||||
if (!sub_dir_file_Stats.isFile()) {
|
||||
rmSync(sub_dir_file_full_path, {
|
||||
force: true,
|
||||
recursive: true,
|
||||
});
|
||||
continue;
|
||||
}
|
||||
if (j > MAX_LOGS - 1) {
|
||||
rmSync(sub_dir_file_full_path, { force: true });
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
// log.info("Running development server ...");
|
||||
// try {
|
||||
// rmSync(HYDRATION_DST_DIR, { recursive: true });
|
||||
// rmSync(BUNX_CWD_PAGES_REWRITE_DIR, { recursive: true });
|
||||
// } catch (error) {}
|
||||
// await bunextInit();
|
||||
// await startServer();
|
||||
Vendored
+1
@@ -0,0 +1 @@
|
||||
export {};
|
||||
Vendored
+46
@@ -0,0 +1,46 @@
|
||||
import { spawn } from "bun";
|
||||
// Only the "supervisor" respawns. The child sets this env var so it won't respawn itself.
|
||||
const IS_CHILD = process.env.__RESPAWN_CHILD === "1";
|
||||
let shuttingDown = false;
|
||||
async function cleanup() {
|
||||
// Put real cleanup here: close DB handles, servers, file descriptors, timers, etc.
|
||||
// Must be awaitable — do NOT rely on process.on("exit") for this.
|
||||
}
|
||||
function respawn(code) {
|
||||
const child = spawn({
|
||||
cmd: [process.execPath, ...process.argv.slice(1)],
|
||||
stdio: ["inherit", "inherit", "inherit"],
|
||||
env: { ...process.env, __RESPAWN_CHILD: "1" },
|
||||
// Detach so the child survives independently and gets its own process group.
|
||||
// Without this, killing the parent's group can take the child with it.
|
||||
});
|
||||
// Let the child live on its own.
|
||||
child.unref?.();
|
||||
}
|
||||
async function shutdown(code) {
|
||||
if (shuttingDown)
|
||||
return;
|
||||
shuttingDown = true;
|
||||
try {
|
||||
await cleanup();
|
||||
}
|
||||
catch (e) {
|
||||
console.error("cleanup failed:", e);
|
||||
}
|
||||
// Only the supervisor respawns, and only on abnormal exit.
|
||||
if (!IS_CHILD && code !== 0) {
|
||||
respawn(code);
|
||||
}
|
||||
process.exit(code);
|
||||
}
|
||||
// Catch the things that actually fire *before* exit, where async works.
|
||||
process.on("SIGINT", () => shutdown(130));
|
||||
process.on("SIGTERM", () => shutdown(143));
|
||||
process.on("uncaughtException", (err) => {
|
||||
console.error(err);
|
||||
shutdown(1);
|
||||
});
|
||||
process.on("unhandledRejection", (err) => {
|
||||
console.error(err);
|
||||
shutdown(1);
|
||||
});
|
||||
+2
@@ -1,5 +1,6 @@
|
||||
import { log } from "../../utils/log";
|
||||
import allPagesESBuildContextBundler from "../bundler/all-pages-esbuild-context-bundler";
|
||||
import pagesSSRBundler from "../bundler/pages-ssr-bundler";
|
||||
import serverPostBuildFn from "./server-post-build-fn";
|
||||
import watcherEsbuildCTX from "./watcher-esbuild-ctx";
|
||||
export default async function fullRebuild(params) {
|
||||
@@ -14,6 +15,7 @@ export default async function fullRebuild(params) {
|
||||
global.BUNDLER_CTX = undefined;
|
||||
await global.SSR_BUNDLER_CTX?.dispose();
|
||||
global.SSR_BUNDLER_CTX = undefined;
|
||||
await pagesSSRBundler();
|
||||
allPagesESBuildContextBundler({
|
||||
post_build_fn: () => {
|
||||
serverPostBuildFn();
|
||||
|
||||
+5
-1
@@ -5,7 +5,7 @@ import fullRebuild from "./full-rebuild";
|
||||
import { AppData } from "../../data/app-data";
|
||||
import checkExcludedPatterns from "../../utils/check-excluded-patterns";
|
||||
import pagesSSRBundler from "../bundler/pages-ssr-bundler";
|
||||
const { ROOT_DIR } = grabDirNames();
|
||||
const { ROOT_DIR, BUNX_BUNDLER_ERROR_EXIT_FILE } = grabDirNames();
|
||||
export default async function watcherEsbuildCTX() {
|
||||
const pages_src_watcher = watch(ROOT_DIR, {
|
||||
recursive: true,
|
||||
@@ -13,6 +13,10 @@ export default async function watcherEsbuildCTX() {
|
||||
}, async (event, filename) => {
|
||||
if (!filename)
|
||||
return;
|
||||
if (existsSync(BUNX_BUNDLER_ERROR_EXIT_FILE)) {
|
||||
await fullRebuild();
|
||||
return;
|
||||
}
|
||||
if (filename.match(/^\.\w+/)) {
|
||||
return;
|
||||
}
|
||||
|
||||
Vendored
+4
@@ -0,0 +1,4 @@
|
||||
export default function writeErrorFile({ exitCode, error, }: {
|
||||
error?: Bun.ErrorLike;
|
||||
exitCode: number | null;
|
||||
}): void;
|
||||
Vendored
+21
@@ -0,0 +1,21 @@
|
||||
import path from "path";
|
||||
import { mkdirSync, writeFileSync } from "fs";
|
||||
import grabDirNames from "../utils/grab-dir-names";
|
||||
const { BUNX_BUNDLER_ERROR_EXIT_FILE } = grabDirNames();
|
||||
export default function writeErrorFile({ exitCode, error, }) {
|
||||
let txt = ``;
|
||||
txt += `Bunext Error\n`;
|
||||
txt += `============================================\n`;
|
||||
txt += `ERROR: ${error?.message}\n`;
|
||||
txt += `EXIT_CODE: ${exitCode || 0}\n`;
|
||||
txt += `CALL_STACK: ${error?.stack}\n`;
|
||||
mkdirSync(path.dirname(BUNX_BUNDLER_ERROR_EXIT_FILE), { recursive: true });
|
||||
writeFileSync(BUNX_BUNDLER_ERROR_EXIT_FILE, txt);
|
||||
}
|
||||
// log.info("Running development server ...");
|
||||
// try {
|
||||
// rmSync(HYDRATION_DST_DIR, { recursive: true });
|
||||
// rmSync(BUNX_CWD_PAGES_REWRITE_DIR, { recursive: true });
|
||||
// } catch (error) {}
|
||||
// await bunextInit();
|
||||
// await startServer();
|
||||
Reference in New Issue
Block a user