// The game server and the site together, for playing locally: one terminal, // each line marked with its side, and Ctrl-C (or either one stopping or // failing to get its port) stops both. import { spawn } from 'node:child_process'; const sides = [ ['server', ['run', 'server']], ['site', ['run', 'dev', '--', ...process.argv.slice(2)]] ]; const children = sides.map(([name, args]) => { const child = spawn('npm', args, { stdio: ['inherit', 'pipe', 'pipe'] }); for (const stream of [child.stdout, child.stderr]) { let rest = ''; stream.on('data', (chunk) => { const lines = (rest + chunk).split('\n'); rest = lines.pop(); for (const line of lines) { console.log(`[${name}] ${line}`); // A watcher outlives the crash it watches, so a port already taken would leave one side running alone. if (line.includes('EADDRINUSE')) { console.log(`[${name}] its port is taken: is another copy already running?`); stop(1); } } }); } child.on('exit', (code) => stop(code ?? 0)); return child; }); let stopping = false; function stop(code) { if (stopping) return; stopping = true; for (const c of children) if (c.exitCode === null) c.kill('SIGTERM'); process.exitCode = code; } process.on('SIGINT', () => stop(0)); process.on('SIGTERM', () => stop(0));