wait-for-vite.js 3.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124
  1. #!/usr/bin/env node
  2. /**
  3. * 等待 Vite 开发服务器启动的脚本
  4. * 从配置文件读取端口,并等待服务器就绪
  5. * 如果配置端口被占用,Vite 会自动尝试下一个端口,此脚本会检测实际使用的端口
  6. */
  7. const path = require('path');
  8. const http = require('http');
  9. // 获取配置文件
  10. const configPath = path.join(__dirname, 'config.js');
  11. const config = require(configPath);
  12. const startPort = config.vite?.port || 5173;
  13. const viteHost = config.vite?.host || 'localhost';
  14. const maxWaitTime = 20; // 最多等待 20 秒
  15. const maxPortAttempts = 10; // 最多尝试 10 个连续端口
  16. const checkInterval = 500; // 每 500ms 检查一次
  17. /**
  18. * 检查指定端口是否有 Vite 服务器响应
  19. * 不仅检查端口是否响应,还要确认是 Vite 服务器(通过检查响应头)
  20. */
  21. function checkPort(port) {
  22. return new Promise((resolve) => {
  23. const req = http.get(`http://${viteHost}:${port}`, (res) => {
  24. // 检查状态码
  25. if (res.statusCode !== 200) {
  26. resolve(false);
  27. return;
  28. }
  29. // 读取响应数据以确认是否是 Vite 服务器
  30. let data = '';
  31. let resolved = false;
  32. res.on('data', (chunk) => {
  33. if (resolved) return;
  34. data += chunk.toString();
  35. // 如果响应包含 Vite 的特征(如 vite/client 或 Vite),确认是 Vite 服务器
  36. if (data.length > 100 && (data.includes('/vite') || data.includes('Vite') || data.includes('vite/client'))) {
  37. resolved = true;
  38. resolve(true);
  39. }
  40. });
  41. res.on('end', () => {
  42. if (resolved) return;
  43. // 如果响应结束,检查是否包含 Vite 特征
  44. // Vite 的 HTML 通常包含 vite/client 或类似的引用
  45. if (data.includes('/vite') || data.includes('Vite') || data.includes('vite/client')) {
  46. resolve(true);
  47. } else {
  48. resolve(false);
  49. }
  50. });
  51. });
  52. req.on('error', () => {
  53. resolve(false);
  54. });
  55. req.setTimeout(2000, () => {
  56. req.destroy();
  57. resolve(false);
  58. });
  59. });
  60. }
  61. /**
  62. * 查找 Vite 实际使用的端口
  63. */
  64. async function findVitePort() {
  65. // 从配置的端口开始,尝试最多 maxPortAttempts 个连续端口
  66. for (let offset = 0; offset < maxPortAttempts; offset++) {
  67. const port = startPort + offset;
  68. const isReady = await checkPort(port);
  69. if (isReady) {
  70. return port;
  71. }
  72. }
  73. return null;
  74. }
  75. async function waitForServer() {
  76. console.log(`Waiting for Vite dev server (starting from port ${startPort})...`);
  77. const startTime = Date.now();
  78. let lastFoundPort = null;
  79. let consecutiveChecks = 0;
  80. while (Date.now() - startTime < maxWaitTime * 1000) {
  81. const port = await findVitePort();
  82. if (port) {
  83. // 如果找到的端口和上次一样,连续检查几次确保稳定
  84. if (port === lastFoundPort) {
  85. consecutiveChecks++;
  86. if (consecutiveChecks >= 3) {
  87. // 连续3次检查到同一个端口,确认服务器稳定运行
  88. console.log(`\n[OK] Vite dev server is ready at http://${viteHost}:${port}`);
  89. process.exit(0);
  90. }
  91. } else {
  92. // 端口变化了,重置计数器
  93. lastFoundPort = port;
  94. consecutiveChecks = 1;
  95. }
  96. } else {
  97. // 没找到服务器,重置计数器
  98. lastFoundPort = null;
  99. consecutiveChecks = 0;
  100. }
  101. // 显示进度
  102. process.stdout.write('.');
  103. await new Promise(resolve => setTimeout(resolve, checkInterval));
  104. }
  105. console.log(`\n[ERROR] Vite dev server did not start within ${maxWaitTime} seconds`);
  106. process.exit(1);
  107. }
  108. waitForServer();