本地 RAG 知识库
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 
 
 

103 lines
3.1 KiB

/**
* 前端并行构建脚本
*
* 并行执行 client/ (SDK) 和 frontend/ (管理后台) 的 npm install + build,
* 替代 pom.xml 中两个串行的 frontend-maven-plugin。
*
* 用法: node build-all.mjs [--skip-install]
* --skip-install 跳过 npm install(仅执行 build),热构建加速
*/
import { spawn } from 'node:child_process';
import { resolve, dirname } from 'node:path';
import { fileURLToPath } from 'node:url';
import { existsSync } from 'node:fs';
const __dirname = dirname(fileURLToPath(import.meta.url));
const ROOT = resolve(__dirname);
// 优先使用 Maven 安装的本地 Node.js/npm,保持版本一致
const isWindows = process.platform === 'win32';
const LOCAL_NPM = isWindows
? resolve(ROOT, 'node', 'npm.cmd')
: resolve(ROOT, 'node', 'npm');
const NPM_EXE = existsSync(LOCAL_NPM) ? LOCAL_NPM : 'npm';
const SKIP_INSTALL = process.argv.includes('--skip-install');
const PROJECTS = [
{ name: 'client', dir: resolve(ROOT, 'client') },
{ name: 'frontend', dir: resolve(ROOT, 'frontend') },
];
/**
* 在指定目录执行 npm 命令,返回 Promise。
* 将 stdout/stderr 实时转发到控制台,带项目前缀。
*/
function runNpm(cwd, args, label) {
return new Promise((resolvePromise, reject) => {
const child = spawn(NPM_EXE, args, {
cwd,
shell: isWindows, // Windows 需要 shell 才能找到 npm.cmd
stdio: ['ignore', 'pipe', 'pipe'],
env: { ...process.env },
});
child.stdout.on('data', (data) => {
process.stdout.write(`[${label}] ${data}`);
});
child.stderr.on('data', (data) => {
process.stderr.write(`[${label}] ${data}`);
});
child.on('close', (code) => {
if (code === 0) {
console.log(`[${label}] ✓ 完成`);
resolvePromise();
} else {
reject(new Error(`[${label}] 失败,退出码: ${code}`));
}
});
child.on('error', (err) => {
reject(new Error(`[${label}] 启动失败: ${err.message}`));
});
});
}
async function main() {
const startTime = Date.now();
// ===== Phase 1: npm install(两个项目并行) =====
if (!SKIP_INSTALL) {
console.log('\n=== Phase 1: npm install ===');
const installResults = await Promise.allSettled(
PROJECTS.map((p) =>
runNpm(p.dir, ['install', '--prefer-offline', '--no-audit', '--no-fund'], p.name)
)
);
for (const r of installResults) {
if (r.status === 'rejected') throw r.reason;
}
} else {
console.log('\n=== Phase 1: 跳过 npm install(--skip-install) ===');
}
// ===== Phase 2: npm run build(两个项目并行) =====
console.log('\n=== Phase 2: npm run build ===');
const buildResults = await Promise.allSettled(
PROJECTS.map((p) => runNpm(p.dir, ['run', 'build'], p.name))
);
for (const r of buildResults) {
if (r.status === 'rejected') throw r.reason;
}
const elapsed = ((Date.now() - startTime) / 1000).toFixed(1);
console.log(`\n✓ 全部前端构建完成 (${elapsed}s)`);
}
main().catch((err) => {
console.error(`\n✗ 前端构建失败: ${err.message}`);
process.exit(1);
});