core/coordinators/server.coordinator.ts
core/coordinators/server.coordinator.ts is a file in Bane's Lab Build Scripts. 73 lines of code and 13 definitions.
import type { DevServer, Supervisor } from "#types/server.types";
import type { Readable, Writable } from "node:stream";
import type { ChildProcess } from "node:child_process";
import { prefixLines } from "#core/formatters/server.formatter";
import process from "node:process";
import { serverExitLine } from "#configuration/strings/server.strings";
import spawn from "cross-spawn";
import { terminateTree } from "#core/adapters/server.adapter";
const WINDOWS = "win32";
const relay = function relay(source: Readable | null, target: Writable, label: string): void {
let carry = "";
source?.on("data", (chunk: unknown) => {
const prefixed = prefixLines(label, carry, String(chunk));
({ carry } = prefixed);
for (const line of prefixed.lines) {
target.write(line);
}
});
};
const pipeLabeled = function pipeLabeled(child: ChildProcess, label: string): void {
relay(child.stdout, process.stdout, label);
relay(child.stderr, process.stderr, label);
};
export const startServer = function startServer(server: DevServer): ChildProcess {
const child = spawn("npx", ["vite", "--config", server.config, ...server.args], {
detached: process.platform !== WINDOWS,
stdio: ["ignore", "pipe", "pipe"],
});
pipeLabeled(child, server.label);
return child;
};
export const stopAll = function stopAll(children: readonly ChildProcess[]): void {
for (const child of children) {
if (child.pid !== undefined && child.exitCode === null) {
terminateTree(child.pid);
}
}
};
export const createSupervisor = function createSupervisor(
children: readonly ChildProcess[],
exitWith: (code: number) => void,
): Supervisor {
const state = { stopped: false };
return {
stop: (code) => {
if (state.stopped) {
return;
}
state.stopped = true;
stopAll(children);
exitWith(code);
},
stopped: () => state.stopped,
};
};
export const superviseServers = function superviseServers(servers: readonly DevServer[]): Supervisor {
const started = servers.map((server) => ({ child: startServer(server), server }));
const supervisor = createSupervisor(
started.map(({ child }) => child),
(code) => {
process.exitCode = code;
},
);
for (const { child, server } of started) {
child.on("exit", (code) => {
if (!supervisor.stopped()) {
process.stderr.write(serverExitLine(server.label, code));
}
supervisor.stop(code ?? 1);
});
}
return supervisor;
};