diff --git a/README.md b/README.md index 89fb287..e7536c2 100644 --- a/README.md +++ b/README.md @@ -26,6 +26,7 @@ the new project as `docs/conventions.md`; it is the house style. Run the demo locally from a new project: + npm run dev:all # server and site together; Ctrl-C stops both npm run server # the game server on its port npm run dev -- --host diff --git a/template/package.json b/template/package.json index 4917684..b04fe4b 100644 --- a/template/package.json +++ b/template/package.json @@ -5,6 +5,7 @@ "type": "module", "scripts": { "dev": "vite dev", + "dev:all": "node scripts/dev-all.mjs", "build": "vite build", "preview": "vite preview", "prepare": "svelte-kit sync || echo ''", diff --git a/template/scripts/dev-all.mjs b/template/scripts/dev-all.mjs new file mode 100644 index 0000000..ac793ec --- /dev/null +++ b/template/scripts/dev-all.mjs @@ -0,0 +1,31 @@ +// 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) 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}`); + }); + } + 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));