Squashed 'crop-x-new/' changes from 62f9221..5feb24e

5feb24e 子仓库提交

git-subtree-dir: crop-x-new
git-subtree-split: 5feb24e4e221308e6e146bb0fce87f1fb3e152e8
This commit is contained in:
2025-11-10 10:56:39 +08:00
parent 131a88fd22
commit f6b253e6ef
733 changed files with 141413 additions and 0 deletions

387
scripts/build.cjs Normal file
View File

@@ -0,0 +1,387 @@
/**
* 统一构建脚本
*
* 整合环境设置、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=<environment> 指定环境 (与直接指定环境等效)', '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
};