/** * 统一构建脚本 * * 整合环境设置、API生成和Next.js构建的完整构建流程 * 支持多环境构建:dev, test, uat, prod */ const fs = require('fs'); const path = require('path'); const { execSync, spawn } = require('child_process'); // ANSI 颜色代码 const colors = { reset: '\x1b[0m', red: '\x1b[31m', green: '\x1b[32m', yellow: '\x1b[33m', blue: '\x1b[34m', cyan: '\x1b[36m', white: '\x1b[37m' }; // 日志函数 function log(message, color = 'white') { console.log(`${colors[color]}${message}${colors.reset}`); } function logSuccess(message) { log(`✓ ${message}`, 'green'); } function logError(message) { log(`✗ ${message}`, 'red'); } function logInfo(message) { log(`ℹ ${message}`, 'blue'); } function logStep(message) { log(`🔄 ${message}`, 'cyan'); } function logWarning(message) { log(`⚠ ${message}`, 'yellow'); } /** * 获取命令行参数中的环境 */ function getEnvironmentFromArgs() { const args = process.argv.slice(2); // 查找 --env 参数 const envArg = args.find(arg => arg.startsWith('--env=')); if (envArg) { return envArg.split('=')[1]; } // 查找直接的参数 const directEnv = args[0]; if (['dev', 'test', 'uat', 'prod'].includes(directEnv)) { return directEnv; } return null; } /** * 验证环境名称 */ function validateEnvironment(env) { const validEnvs = ['dev', 'test', 'uat', 'prod']; if (!validEnvs.includes(env)) { logError(`无效的环境名称: ${env}`); logInfo(`支持的环境: ${validEnvs.join(', ')}`); return false; } return true; } /** * 复制环境配置文件 */ function copyEnvironmentConfig(env) { logStep(`设置 ${env} 环境配置`); const envDir = path.join(process.cwd(), 'env'); const sourceFile = path.join(envDir, `.env.${env}`); const targetFile = path.join(process.cwd(), '.env.local'); // 检查源文件是否存在 if (!fs.existsSync(sourceFile)) { logError(`环境配置文件不存在: ${sourceFile}`); return false; } try { // 复制文件 fs.copyFileSync(sourceFile, targetFile); logSuccess(`已复制环境配置: ${env}`); return true; } catch (error) { logError(`复制环境配置文件失败: ${error.message}`); return false; } } /** * 清理缓存目录 */ function cleanCache() { logStep('清理缓存目录'); const dirsToClean = ['.next', 'node_modules/.cache']; dirsToClean.forEach(dir => { const dirPath = path.join(process.cwd(), dir); if (fs.existsSync(dirPath)) { try { fs.rmSync(dirPath, { recursive: true, force: true }); logSuccess(`已清理: ${dir}`); } catch (error) { logWarning(`清理 ${dir} 失败: ${error.message}`); } } }); } /** * 生成API客户端代码 */ function generateApi(env) { logStep('生成API客户端代码'); try { // 设置环境变量 const apiBaseUrl = getApiBaseUrl(env); process.env.API_BASE_URL = apiBaseUrl; logInfo(`API服务器: ${apiBaseUrl}`); // 执行API生成脚本 execSync('node scripts/generate-api.cjs', { stdio: 'inherit', cwd: process.cwd() }); logSuccess('API客户端代码生成完成'); return true; } catch (error) { logError(`API生成失败: ${error.message}`); return false; } } /** * 从环境配置文件中读取配置 */ function getEnvConfigFromFile(env) { try { // 读取对应环境配置文件 const envFilePath = path.join(process.cwd(), 'env', `.env.${env}`); if (!fs.existsSync(envFilePath)) { logWarning(`环境配置文件不存在: ${envFilePath}`); return { FRONTEND_BASE_URL: 'http://localhost:3000', BACKEND_BASE_URL: 'http://localhost:8080', ENV_DESCRIPTION: `${env}环境` }; } const envContent = fs.readFileSync(envFilePath, 'utf8'); const lines = envContent.split('\n'); const config = { FRONTEND_BASE_URL: 'http://localhost:3000', BACKEND_BASE_URL: 'http://localhost:8080', ENV_DESCRIPTION: `${env}环境` }; // 解析配置文件 for (const line of lines) { if (line.startsWith('FRONTEND_BASE_URL=')) { config.FRONTEND_BASE_URL = line.split('=')[1].trim(); } else if (line.startsWith('BACKEND_BASE_URL=')) { config.BACKEND_BASE_URL = line.split('=')[1].trim(); logInfo(`从 ${envFilePath} 读取到后端地址: ${config.BACKEND_BASE_URL}`); } else if (line.startsWith('ENV_DESCRIPTION=')) { config.ENV_DESCRIPTION = line.split('=')[1].trim(); } } return config; } catch (error) { logError(`读取环境配置失败: ${error.message}`); return { FRONTEND_BASE_URL: 'http://localhost:3000', BACKEND_BASE_URL: 'http://localhost:8080', ENV_DESCRIPTION: `${env}环境` }; } } /** * 获取API基础URL - 从环境配置文件中读取 */ function getApiBaseUrl(env) { const config = getEnvConfigFromFile(env); return config.BACKEND_BASE_URL; } /** * 获取前端基础URL - 从环境配置文件中读取 */ function getFrontendUrl(env) { const config = getEnvConfigFromFile(env); return config.FRONTEND_BASE_URL; } /** * Next.js 构建 */ function buildNext(env) { logStep('执行 Next.js 构建'); try { // 设置环境变量 process.env.NODE_ENV = 'production'; // 所有构建都使用 production 模式 process.env.NEXT_PUBLIC_ENV = env; // 执行构建 execSync('npm run build', { stdio: 'inherit', cwd: process.cwd() }); logSuccess('Next.js 构建完成'); return true; } catch (error) { logError(`Next.js 构建失败: ${error.message}`); return false; } } /** * 显示构建信息 */ function showBuildInfo(env, totalTime) { const envConfig = getEnvConfigFromFile(env); log('='.repeat(60), 'green'); logSuccess(`构建完成!总耗时: ${totalTime}ms`); logSuccess(`环境: ${envConfig.ENV_DESCRIPTION} (${env})`); logSuccess(`前端地址: ${envConfig.FRONTEND_BASE_URL}`); logSuccess(`后端地址: ${envConfig.BACKEND_BASE_URL}`); logSuccess('构建产物: .next 目录'); log('='.repeat(60), 'green'); logInfo('部署建议:'); logInfo(` 将 .next 目录和 package.json 部署到 ${envConfig.ENV_DESCRIPTION}`); if (env !== 'dev') { logInfo(` 确保环境变量 NODE_ENV=production 和 NEXT_PUBLIC_ENV=${env}`); } } /** * 显示帮助信息 */ function showHelp() { log('用法: node scripts/build.cjs [环境] [选项]', 'cyan'); log(''); log('环境:', 'yellow'); log(' dev 开发环境', 'white'); log(' test 测试环境', 'white'); log(' uat UAT 环境', 'white'); log(' prod 生产环境', 'white'); log(''); log('选项:', 'yellow'); log(' --env= 指定环境 (与直接指定环境等效)', 'white'); log(' --clean 构建前清理缓存', 'white'); log(' --skip-api 跳过API生成', 'white'); log(' --skip-build 跳过Next.js构建(仅设置环境)', 'white'); log(' --help 显示此帮助信息', 'white'); log(''); log('示例:', 'yellow'); log(' node scripts/build.cjs dev # 开发环境完整构建', 'white'); log(' node scripts/build.cjs test --clean # 测试环境清理缓存后构建', 'white'); log(' node scripts/build.cjs prod --skip-api # 生产环境跳过API生成构建', 'white'); log(' node scripts/build.cjs uat --skip-build # UAT环境仅设置环境和API生成', 'white'); log(''); } /** * 主函数 */ function main() { const startTime = Date.now(); log('='.repeat(60), 'cyan'); log('统一构建脚本', 'cyan'); log('整合环境设置、API生成和Next.js构建', 'cyan'); log('='.repeat(60), 'cyan'); // 检查帮助参数 if (process.argv.includes('--help') || process.argv.includes('-h')) { showHelp(); process.exit(0); } // 获取环境参数 let env = getEnvironmentFromArgs(); if (!env) { logError('请指定环境参数'); logInfo('使用 --help 查看帮助信息'); process.exit(1); } // 验证环境 if (!validateEnvironment(env)) { process.exit(1); } // 解析选项 const shouldClean = process.argv.includes('--clean'); const skipApi = process.argv.includes('--skip-api'); const skipBuild = process.argv.includes('--skip-build'); logInfo(`目标环境: ${env}`); logInfo(`工作目录: ${process.cwd()}`); try { // 1. 设置环境配置 const envSuccess = copyEnvironmentConfig(env); if (!envSuccess) { process.exit(1); } // 2. 清理缓存(可选) if (shouldClean) { cleanCache(); } // 3. 生成API客户端(可选) if (!skipApi) { const apiSuccess = generateApi(env); if (!apiSuccess) { process.exit(1); } } else { logInfo('跳过API生成'); } // 4. Next.js 构建(可选) if (!skipBuild) { const buildSuccess = buildNext(env); if (!buildSuccess) { process.exit(1); } } else { logInfo('跳过Next.js构建'); } const totalTime = Date.now() - startTime; showBuildInfo(env, totalTime); } catch (error) { const totalTime = Date.now() - startTime; logError(`构建失败 (${totalTime}ms): ${error.message}`); process.exit(1); } } // 执行主函数 if (require.main === module) { main(); } module.exports = { copyEnvironmentConfig, generateApi, buildNext, validateEnvironment, getEnvironmentFromArgs };