320 lines
8.7 KiB
JavaScript
320 lines
8.7 KiB
JavaScript
#!/usr/bin/env node
|
||
import { execSync } from 'child_process';
|
||
import { copyFileSync, mkdirSync, existsSync, readFileSync, writeFileSync, rmSync } from 'fs';
|
||
import { join, dirname } from 'path';
|
||
import { fileURLToPath } from 'url';
|
||
|
||
const __dirname = dirname(fileURLToPath(import.meta.url));
|
||
const rootDir = join(__dirname, '..');
|
||
|
||
// 辅助函数:执行命令
|
||
function exec(command, options = {}) {
|
||
console.log(`\n📦 执行: ${command}`);
|
||
try {
|
||
execSync(command, { stdio: 'inherit', cwd: rootDir, ...options });
|
||
} catch (error) {
|
||
console.error(`❌ 命令失败: ${command}`);
|
||
process.exit(1);
|
||
}
|
||
}
|
||
|
||
// 辅助函数:确保目录存在
|
||
function ensureDir(dir) {
|
||
if (!existsSync(dir)) {
|
||
mkdirSync(dir, { recursive: true });
|
||
}
|
||
}
|
||
|
||
// 辅助函数:读取和写入 JSON
|
||
function readJSON(path) {
|
||
return JSON.parse(readFileSync(path, 'utf-8'));
|
||
}
|
||
|
||
function writeJSON(path, data) {
|
||
writeFileSync(path, JSON.stringify(data, null, 2));
|
||
}
|
||
|
||
// 获取命令行参数
|
||
const args = process.argv.slice(2);
|
||
const command = args[0];
|
||
|
||
// 构建任务
|
||
const tasks = {
|
||
// 清理所有构建产物
|
||
clean() {
|
||
console.log('🧹 清理构建产物...');
|
||
const dirs = [
|
||
'packages/web/build',
|
||
'packages/web/dist',
|
||
'packages/core/dist',
|
||
'packages/core/web-build',
|
||
'packages/electron/dist',
|
||
'packages/electron/web-build'
|
||
];
|
||
|
||
dirs.forEach(dir => {
|
||
const path = join(rootDir, dir);
|
||
if (existsSync(path)) {
|
||
rmSync(path, { recursive: true, force: true });
|
||
console.log(` ✅ 已删除: ${dir}`);
|
||
}
|
||
});
|
||
},
|
||
|
||
// 构建 Web 前端
|
||
async buildWeb() {
|
||
console.log('\n🌐 构建 Web 前端...');
|
||
exec('npm run build', { cwd: join(rootDir, 'packages/web') });
|
||
},
|
||
|
||
// 构建 Shared 包
|
||
async buildShared() {
|
||
console.log('\n📦 构建 Shared 包...');
|
||
exec('npm run build', { cwd: join(rootDir, 'packages/shared') });
|
||
},
|
||
|
||
// 构建 Shared 包 (用于发布)
|
||
async buildSharedForPublish() {
|
||
console.log('\n📦 构建 Shared 包 (发布版)...');
|
||
const sharedDir = join(rootDir, 'packages/shared');
|
||
|
||
// 先构建
|
||
await tasks.buildShared();
|
||
|
||
// 处理 package.json(用于发布)
|
||
const pkgPath = join(sharedDir, 'package.json');
|
||
let pkg = readJSON(pkgPath);
|
||
|
||
// 更新版本号
|
||
const rootPkg = readJSON(join(rootDir, 'package.json'));
|
||
pkg.version = rootPkg.version;
|
||
|
||
writeJSON(pkgPath, pkg);
|
||
console.log(' ✅ 已处理 Shared 包发布配置');
|
||
},
|
||
|
||
// 构建 Core(Node.js 核心)
|
||
async buildCore() {
|
||
console.log('\n🎯 构建 Core 包...');
|
||
const coreDir = join(rootDir, 'packages/core');
|
||
const distDir = join(coreDir, 'dist');
|
||
|
||
// 创建输出目录
|
||
ensureDir(distDir);
|
||
|
||
// 先确保 Web 已构建
|
||
if (!existsSync(join(rootDir, 'packages/web/build'))) {
|
||
await tasks.buildWeb();
|
||
}
|
||
|
||
// 使用完整构建流程(包含web构建)
|
||
exec('npm run build:full', { cwd: coreDir });
|
||
|
||
// 复制必要文件
|
||
const filesToCopy = ['README.md'];
|
||
filesToCopy.forEach(file => {
|
||
const src = join(rootDir, file);
|
||
const dest = join(distDir, file);
|
||
if (existsSync(src)) {
|
||
copyFileSync(src, dest);
|
||
console.log(` ✅ 复制: ${file}`);
|
||
}
|
||
});
|
||
|
||
// 处理 package.json(用于发布)
|
||
if (args.includes('--publish')) {
|
||
const corePkgPath = join(coreDir, 'package.json');
|
||
let pkg = readJSON(corePkgPath);
|
||
|
||
// 更新版本号
|
||
const rootPkg = readJSON(join(rootDir, 'package.json'));
|
||
pkg.version = rootPkg.version;
|
||
|
||
// 替换 file: 依赖为实际的包版本
|
||
if (pkg.dependencies && pkg.dependencies['@dadigua/hyperchat-shared']) {
|
||
pkg.dependencies['@dadigua/hyperchat-shared'] = `^${rootPkg.version}`;
|
||
console.log(` ✅ 更新 @dadigua/hyperchat-shared 依赖版本: ^${rootPkg.version}`);
|
||
}
|
||
|
||
writeJSON(corePkgPath, pkg);
|
||
console.log(' ✅ 已处理 Core 包发布配置');
|
||
}
|
||
},
|
||
|
||
|
||
|
||
// 构建 Electron
|
||
async buildElectron() {
|
||
console.log('\n💻 构建 Electron 应用...');
|
||
const electronDir = join(rootDir, 'packages/electron');
|
||
|
||
// 先确保 Web 已构建
|
||
if (!existsSync(join(rootDir, 'packages/web/build'))) {
|
||
await tasks.buildWeb();
|
||
}
|
||
|
||
// 使用 Electron 包的完整构建流程
|
||
exec('npm run build:electron', { cwd: electronDir });
|
||
},
|
||
|
||
// 构建所有
|
||
async buildAll() {
|
||
console.log('🚀 开始完整构建...\n');
|
||
|
||
// 清理
|
||
tasks.clean();
|
||
|
||
// 构建各包 (不再需要shared,使用路径别名替换)
|
||
await tasks.buildCore(); // Core 构建现在包含web构建
|
||
await tasks.buildElectron();
|
||
|
||
console.log('\n✨ 所有构建已完成!');
|
||
},
|
||
|
||
// 发布准备:构建并配置发布用的包
|
||
async buildForPublish() {
|
||
console.log('📦 准备发布构建...\n');
|
||
|
||
// 清理
|
||
tasks.clean();
|
||
|
||
// 构建 core 包 (发布版)
|
||
args.push('--publish'); // 确保传递 --publish 参数
|
||
await tasks.buildCore();
|
||
|
||
console.log('\n✨ 发布构建已完成!');
|
||
console.log('\n📝 下一步:');
|
||
console.log('1. 运行: npm run publish:core');
|
||
},
|
||
|
||
|
||
// 发布 core 包
|
||
async publishCore() {
|
||
console.log('📤 发布 Core 包...');
|
||
const coreDir = join(rootDir, 'packages/core');
|
||
|
||
// 检查是否已经构建
|
||
if (!existsSync(join(coreDir, 'dist'))) {
|
||
console.log('⚠️ 检测到 Core 包未构建,先进行构建...');
|
||
if (!args.includes('--publish')) {
|
||
args.push('--publish'); // 确保传递 --publish 参数
|
||
}
|
||
await tasks.buildCore();
|
||
}
|
||
|
||
const publishTag = process.env.NPM_PUBLISH_TAG || 'latest';
|
||
const tagFlag = publishTag === 'latest' ? '' : ` --tag ${publishTag}`;
|
||
console.log(`📦 发布标签: ${publishTag}`);
|
||
exec(`npm publish --access public${tagFlag}`, { cwd: coreDir });
|
||
console.log('✅ Core 包发布完成!');
|
||
},
|
||
|
||
// 完整发布流程
|
||
async publishAll() {
|
||
console.log('🚀 开始完整发布流程...\n');
|
||
|
||
// 1. 构建发布版本
|
||
await tasks.buildForPublish();
|
||
|
||
// 2. 发布 core 包
|
||
await tasks.publishCore();
|
||
|
||
console.log('\n🎉 Core 包发布完成!');
|
||
},
|
||
|
||
// 开发模式
|
||
dev() {
|
||
const target = args[1] || 'web';
|
||
console.log(`🔧 启动开发模式: ${target}`);
|
||
|
||
switch (target) {
|
||
case 'shared':
|
||
exec('npm run dev', { cwd: join(rootDir, 'packages/shared') });
|
||
break;
|
||
case 'web':
|
||
exec('npm run start', { cwd: join(rootDir, 'packages/web') });
|
||
break;
|
||
case 'core':
|
||
exec('npm run start', { cwd: join(rootDir, 'packages/core') });
|
||
break;
|
||
case 'cli':
|
||
exec('npm run start', { cwd: join(rootDir, 'packages/cli') });
|
||
break;
|
||
case 'electron':
|
||
exec('npm run start', { cwd: join(rootDir, 'packages/electron') });
|
||
break;
|
||
case 'all':
|
||
// 使用 concurrently 同时运行多个开发服务器
|
||
exec('npx concurrently "npm run start --prefix packages/web" "npm run start --prefix packages/core"');
|
||
break;
|
||
default:
|
||
console.error(`❌ 未知的开发目标: ${target}`);
|
||
console.log('可用选项: shared, web, core, cli, electron, all');
|
||
process.exit(1);
|
||
}
|
||
},
|
||
|
||
// 帮助信息
|
||
help() {
|
||
console.log(`
|
||
HyperChat 构建脚本
|
||
|
||
使用方法:
|
||
node scripts/build.mjs <command> [options]
|
||
|
||
构建命令:
|
||
clean 清理所有构建产物
|
||
buildWeb 构建 Web 前端
|
||
buildCore 构建 Core 包 (包含Web前端)
|
||
buildElectron 构建 Electron 应用
|
||
buildAll 构建所有包
|
||
buildForPublish 构建Core包 (发布版)
|
||
|
||
发布命令:
|
||
publishCore 发布 Core 包到 npm
|
||
publishAll 完整发布流程 (推荐)
|
||
|
||
开发命令:
|
||
dev [target] 启动开发模式 (shared/web/core/cli/electron/all)
|
||
help 显示此帮助信息
|
||
|
||
选项:
|
||
--publish 为发布准备 Core 包(处理 package.json)
|
||
|
||
示例:
|
||
node scripts/build.mjs buildAll
|
||
node scripts/build.mjs dev web
|
||
node scripts/build.mjs buildForPublish
|
||
node scripts/build.mjs publishCore
|
||
|
||
发布流程:
|
||
1. node scripts/build.mjs publishAll # 推荐:一键发布
|
||
或者分步执行:
|
||
2a. node scripts/build.mjs buildForPublish
|
||
2b. node scripts/build.mjs publishCore
|
||
`);
|
||
}
|
||
};
|
||
|
||
// 执行命令
|
||
const taskName = command || 'help';
|
||
const task = tasks[taskName];
|
||
|
||
if (task) {
|
||
try {
|
||
const result = task();
|
||
if (result && typeof result.catch === 'function') {
|
||
result.catch(error => {
|
||
console.error('❌ 构建失败:', error);
|
||
process.exit(1);
|
||
});
|
||
}
|
||
} catch (error) {
|
||
console.error('❌ 构建失败:', error);
|
||
process.exit(1);
|
||
}
|
||
} else {
|
||
console.error(`❌ 未知命令: ${taskName}`);
|
||
tasks.help();
|
||
process.exit(1);
|
||
} |