dev.js 1.7 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465
  1. #!/usr/bin/env node
  2. /**
  3. * 开发启动器:先启动 server (tsx watch),等它就绪,再启动 client (vite)。
  4. * Ctrl+C 时同时关闭两个进程。启动前自动清理旧进程。
  5. */
  6. const { spawn, execSync } = require("child_process");
  7. const http = require("http");
  8. const ROOT = __dirname + "/..";
  9. const SERVER_PORT = 3001;
  10. const CLIENT_PORT = 9527;
  11. function killPort(port) {
  12. try { execSync(`lsof -ti :${port} | xargs kill -9 2>/dev/null`, { stdio: "ignore" }); } catch {}
  13. }
  14. function startProcess(label, cwd, ...args) {
  15. const child = spawn(...args, { cwd, stdio: "inherit" });
  16. child.on("exit", (code) => {
  17. console.log(`[${label}] exited (${code})`);
  18. process.exit(code || 0);
  19. });
  20. return child;
  21. }
  22. function waitForServer(url, maxRetries = 30) {
  23. return new Promise((resolve, reject) => {
  24. let tries = 0;
  25. function check() {
  26. http.get(url, (res) => {
  27. if (res.statusCode === 200) resolve();
  28. else retry();
  29. }).on("error", retry);
  30. }
  31. function retry() {
  32. if (++tries >= maxRetries) {
  33. reject(new Error(`Server did not start within ${maxRetries}s`));
  34. return;
  35. }
  36. setTimeout(check, 1000);
  37. }
  38. check();
  39. });
  40. }
  41. async function main() {
  42. // 清理旧进程
  43. killPort(SERVER_PORT);
  44. killPort(CLIENT_PORT);
  45. console.log("[dev] Starting server...");
  46. startProcess("server", ROOT, "npm", ["run", "dev:server"]);
  47. console.log("[dev] Waiting for server...");
  48. await waitForServer(`http://localhost:${SERVER_PORT}/api/v1/templates`);
  49. console.log("[dev] Server ready.");
  50. console.log("[dev] Starting client...");
  51. startProcess("client", ROOT, "npm", ["run", "dev:client"]);
  52. }
  53. main().catch((err) => {
  54. console.error(err.message);
  55. process.exit(1);
  56. });