| 1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465 |
- #!/usr/bin/env node
- /**
- * 开发启动器:先启动 server (tsx watch),等它就绪,再启动 client (vite)。
- * Ctrl+C 时同时关闭两个进程。启动前自动清理旧进程。
- */
- const { spawn, execSync } = require("child_process");
- const http = require("http");
- const ROOT = __dirname + "/..";
- const SERVER_PORT = 3001;
- const CLIENT_PORT = 9527;
- function killPort(port) {
- try { execSync(`lsof -ti :${port} | xargs kill -9 2>/dev/null`, { stdio: "ignore" }); } catch {}
- }
- function startProcess(label, cwd, ...args) {
- const child = spawn(...args, { cwd, stdio: "inherit" });
- child.on("exit", (code) => {
- console.log(`[${label}] exited (${code})`);
- process.exit(code || 0);
- });
- return child;
- }
- function waitForServer(url, maxRetries = 30) {
- return new Promise((resolve, reject) => {
- let tries = 0;
- function check() {
- http.get(url, (res) => {
- if (res.statusCode === 200) resolve();
- else retry();
- }).on("error", retry);
- }
- function retry() {
- if (++tries >= maxRetries) {
- reject(new Error(`Server did not start within ${maxRetries}s`));
- return;
- }
- setTimeout(check, 1000);
- }
- check();
- });
- }
- async function main() {
- // 清理旧进程
- killPort(SERVER_PORT);
- killPort(CLIENT_PORT);
- console.log("[dev] Starting server...");
- startProcess("server", ROOT, "npm", ["run", "dev:server"]);
- console.log("[dev] Waiting for server...");
- await waitForServer(`http://localhost:${SERVER_PORT}/api/v1/templates`);
- console.log("[dev] Server ready.");
- console.log("[dev] Starting client...");
- startProcess("client", ROOT, "npm", ["run", "dev:client"]);
- }
- main().catch((err) => {
- console.error(err.message);
- process.exit(1);
- });
|