const { spawn } = require('child_process'); const path = require('path'); const express = require('express'); const fs = require('fs'); // 加载生产环境配置文件 require('dotenv').config({ path: path.join(__dirname, '.env.production') }); // 生产环境配置 - 宝塔面板兼容 const API_PORT = process.env.PORT || 4001; const FRONTEND_PORT = process.env.FRONTEND_PORT || 4002; const NODE_ENV = 'production'; const DOMAIN = process.env.DOMAIN || 'ggl.xi.plus'; // 验证端口范围 (4001-4010) if (API_PORT < 4001 || API_PORT > 4010) { console.warn(`警告: API端口 ${API_PORT} 不在推荐范围 4001-4010 内`); } if (FRONTEND_PORT < 4001 || FRONTEND_PORT > 4010) { console.warn(`警告: 前端端口 ${FRONTEND_PORT} 不在推荐范围 4001-4010 内`); } // 设置环境变量 process.env.NODE_ENV = NODE_ENV; process.env.PORT = API_PORT; process.env.DOMAIN = DOMAIN; console.log(`=== 梦回高句丽 - 生产环境启动 ===`); console.log(`域名: ${DOMAIN}`); console.log(`后端API端口: ${API_PORT}`); console.log(`前端静态文件端口: ${FRONTEND_PORT}`); console.log(`工作目录: ${process.cwd()}`); console.log(`Node.js版本: ${process.version}`); console.log(`启动时间: ${new Date().toLocaleString('zh-CN')}`); // 检查dist目录是否存在 const distPath = path.join(__dirname, 'dist'); if (!fs.existsSync(distPath)) { console.error(`错误: dist目录不存在 (${distPath})`); console.log('请先运行 npm run build 构建前端项目'); process.exit(1); } // 启动前端静态文件服务 const app = express(); // 安全头设置 app.use((req, res, next) => { res.setHeader('X-Content-Type-Options', 'nosniff'); res.setHeader('X-Frame-Options', 'DENY'); res.setHeader('X-XSS-Protection', '1; mode=block'); next(); }); // 静态文件服务 app.use(express.static(distPath, { maxAge: '1y', etag: true, lastModified: true })); // SPA路由处理 app.get('*', (req, res) => { res.sendFile(path.join(distPath, 'index.html')); }); const frontendServer = app.listen(FRONTEND_PORT, '0.0.0.0', () => { console.log(`✅ 前端静态文件服务已启动`); console.log(` - 端口: ${FRONTEND_PORT}`); console.log(` - 访问地址: http://${DOMAIN}:${FRONTEND_PORT}`); }); // 检查API服务器文件是否存在 const apiServerPath = path.join(__dirname, 'api', 'server.ts'); if (!fs.existsSync(apiServerPath)) { console.error(`错误: API服务器文件不存在 (${apiServerPath})`); process.exit(1); } // 启动后端API服务器 console.log(`🚀 启动后端API服务器...`); const apiServer = spawn('node', ['--import', 'tsx/esm', 'api/server.ts'], { stdio: 'inherit', env: { ...process.env, NODE_ENV: NODE_ENV, PORT: API_PORT, DOMAIN: DOMAIN }, cwd: __dirname }); // 处理API服务器进程退出 apiServer.on('close', (code) => { console.log(`❌ API服务器进程退出,退出码: ${code}`); frontendServer.close(); process.exit(code); }); // 处理API服务器错误 apiServer.on('error', (err) => { console.error('❌ 启动API服务器时发生错误:', err); frontendServer.close(); process.exit(1); }); // API服务器启动成功提示 setTimeout(() => { console.log(`✅ 后端API服务已启动`); console.log(` - 端口: ${API_PORT}`); console.log(` - API地址: http://${DOMAIN}:${API_PORT}/api`); console.log(`\n🌐 服务器已完全启动,可通过宝塔面板管理`); }, 2000); // 优雅关闭 process.on('SIGINT', () => { console.log('\n收到 SIGINT 信号,正在关闭服务器...'); frontendServer.close(); apiServer.kill('SIGINT'); }); process.on('SIGTERM', () => { console.log('\n收到 SIGTERM 信号,正在关闭服务器...'); frontendServer.close(); apiServer.kill('SIGTERM'); }); // 处理前端服务器错误 frontendServer.on('error', (err) => { console.error('前端静态文件服务器错误:', err); });