/** * 根目录一键打包:web-antd 生产构建 + 桌面端 Electron 安装包 * * 为什么不能真正并行 pack: * electron-builder 会把 apps/web-antd/dist 拷进安装包(extraResources), * 所以必须先有 web dist,再打桌面包。turbo 构建阶段可按依赖图并行。 * * 用法(在仓库根目录): * node build-antd-desktop.mjs * node build-antd-desktop.mjs --only=web * node build-antd-desktop.mjs --only=desktop * pnpm build:antd-desktop */ import { spawn } from 'node:child_process'; import { existsSync } from 'node:fs'; import { dirname, join } from 'node:path'; import { fileURLToPath } from 'node:url'; const __dirname = dirname(fileURLToPath(import.meta.url)); const rootDir = __dirname; const webDistDir = join(rootDir, 'apps/web-antd/dist'); const desktopReleaseDir = join(rootDir, 'apps/desktop/release'); /** 解析 --only=web|desktop|all,默认 all */ function parseOnly() { const arg = process.argv.find((item) => item.startsWith('--only=')); if (!arg) { return 'all'; } const value = arg.slice('--only='.length).trim().toLowerCase(); if (value === 'web' || value === 'antd' || value === 'web-antd') { return 'web'; } if (value === 'desktop' || value === 'electron') { return 'desktop'; } if (value === 'all') { return 'all'; } console.error(`未知 --only 取值: ${value}(支持 web / desktop / all)`); process.exit(1); } /** * 在仓库根目录执行命令;Windows 下 pnpm 是 .cmd,必须 shell:true * @param {string} label 日志步骤名 * @param {string} command 完整 shell 命令 */ function run(label, command) { const startedAt = Date.now(); console.log(`\n========== ${label} ==========`); console.log(`$ ${command}\n`); return new Promise((resolve, reject) => { const child = spawn(command, { cwd: rootDir, env: { ...process.env, // web / electron 构建都偏吃内存,对齐根 package.json 的 build 配置 NODE_OPTIONS: process.env.NODE_OPTIONS || '--max-old-space-size=8192', }, shell: true, stdio: 'inherit', }); child.on('error', reject); child.on('close', (code) => { const seconds = ((Date.now() - startedAt) / 1000).toFixed(1); if (code === 0) { console.log(`\n✅ ${label} 完成(${seconds}s)`); resolve(); return; } reject(new Error(`${label} 失败,退出码 ${code}`)); }); }); } /** 仅打 web-antd(产物:apps/web-antd/dist) */ async function buildWebOnly() { await run('构建 Web(@vben/web-antd)', 'pnpm run build:antd'); assertWebDist(); } /** * 仅打桌面:依赖已有 web dist(turbo ^build 仍可能按缓存跳过 web) * 对应根脚本 build:desktop */ async function buildDesktopOnly() { assertWebDist( `桌面端打包需要 web 产物,但未找到 ${webDistDir}。请先执行 web 构建,或去掉 --only=desktop`, ); await run('构建并打包桌面端(@vben/desktop)', 'pnpm run build:desktop'); } /** * Web + 桌面一次搞定:turbo 同时 filter 两端(共享包只编一次),再 pack 安装包 * 避免「先 build:antd 再 build:desktop」导致 web 被无必要打两遍 */ async function buildAll() { await run( '构建 Web + 桌面主进程(turbo)', 'pnpm run build --filter=@vben/web-antd --filter=@vben/desktop', ); assertWebDist(); await run( '打包桌面安装包(electron-builder)', 'pnpm -F @vben/desktop run pack', ); } /** @param {string} [message] */ function assertWebDist(message) { if (!existsSync(webDistDir)) { throw new Error(message || `未找到 web 产物目录: ${webDistDir}`); } } function printSummary(only) { console.log('\n========== 打包结果 =========='); if (only === 'web' || only === 'all') { console.log(`Web 产物: ${webDistDir}`); } if (only === 'desktop' || only === 'all') { console.log(`桌面安装包: ${desktopReleaseDir}`); } console.log(''); } async function main() { const only = parseOnly(); const totalStartedAt = Date.now(); console.log('萧康云医一键打包'); console.log(`模式: ${only}`); console.log(`根目录: ${rootDir}`); if (only === 'web') { await buildWebOnly(); } else if (only === 'desktop') { await buildDesktopOnly(); } else { await buildAll(); } printSummary(only); const totalSeconds = ((Date.now() - totalStartedAt) / 1000).toFixed(1); console.log(`全部完成,总耗时 ${totalSeconds}s`); } main().catch((error) => { console.error(`\n❌ ${error.message || error}`); process.exit(1); });