impress_asr_input/scripts/build-windows.js

233 lines
6.6 KiB
JavaScript
Raw Permalink Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

/**
* Windows x64 自动打包脚本
* 功能:
* 1. 自动下载 Electron 并缓存到用户目录
* 2. 编译 TypeScript 并复制 UI 文件
* 3. 打包成 ZIP 文件
* 4. 支持增量打包(使用缓存的 Electron
*/
import { existsSync, mkdirSync, rmSync, writeFileSync, readFileSync, cpSync } from 'fs';
import { join } from 'path';
import { execSync } from 'child_process';
import { homedir } from 'os';
// 路径配置
const rootDir = process.cwd();
const userCacheDir = join(homedir(), '.impress-asr-input', 'cache');
const electronCacheDir = join(userCacheDir, 'electron');
const releaseDir = join(rootDir, 'release');
const distDir = join(rootDir, 'dist');
// Electron 版本
const ELECTRON_VERSION = '28.3.3';
const ELECTRON_ZIP_NAME = `electron-v${ELECTRON_VERSION}-win32-x64.zip`;
const ELECTRON_ZIP_PATH = join(electronCacheDir, ELECTRON_ZIP_NAME);
const ELECTRON_URL = `https://npmmirror.com/mirrors/electron/${ELECTRON_VERSION}/${ELECTRON_ZIP_NAME}`;
// 颜色输出
const colors = {
reset: '\x1b[0m',
green: '\x1b[32m',
yellow: '\x1b[33m',
blue: '\x1b[34m',
red: '\x1b[31m',
};
function log(color, message) {
console.log(`${color}${message}${colors.reset}`);
}
/**
* 创建必要的目录
*/
function ensureDirs() {
log(colors.blue, '📁 创建目录...');
if (!existsSync(userCacheDir)) {
mkdirSync(userCacheDir, { recursive: true });
log(colors.green, ` ✅ 缓存目录:${userCacheDir}`);
}
if (!existsSync(electronCacheDir)) {
mkdirSync(electronCacheDir, { recursive: true });
}
if (!existsSync(releaseDir)) {
mkdirSync(releaseDir, { recursive: true });
}
}
/**
* 下载 Electron
*/
function downloadElectron() {
if (existsSync(ELECTRON_ZIP_PATH)) {
log(colors.green, `✅ Electron 已缓存:${ELECTRON_ZIP_NAME}`);
return;
}
log(colors.yellow, `📥 下载 Electron ${ELECTRON_VERSION}...`);
log(colors.blue, ` URL: ${ELECTRON_URL}`);
try {
const proxy = process.env.http_proxy || process.env.https_proxy || '';
const curlCmd = proxy
? `curl -L -o "${ELECTRON_ZIP_PATH}" --proxy "${proxy}" "${ELECTRON_URL}"`
: `curl -L -o "${ELECTRON_ZIP_PATH}" "${ELECTRON_URL}"`;
execSync(curlCmd, { stdio: 'inherit' });
if (existsSync(ELECTRON_ZIP_PATH)) {
const size = Math.round(readFileSync(ELECTRON_ZIP_PATH).length / 1024 / 1024 * 100) / 100;
log(colors.green, `✅ 下载完成:${size}MB`);
}
} catch (error) {
log(colors.red, '❌ 下载失败,请检查网络连接或代理设置');
throw error;
}
}
/**
* 编译 TypeScript
*/
function compileTypeScript() {
log(colors.blue, '📝 编译 TypeScript...');
execSync('npm run build', { stdio: 'inherit' });
log(colors.green, '✅ 编译完成');
}
/**
* 解压 Electron
*/
function unzipElectron(outputDir) {
if (existsSync(outputDir)) {
rmSync(outputDir, { recursive: true, force: true });
}
mkdirSync(outputDir, { recursive: true });
log(colors.blue, '📦 解压 Electron...');
execSync(`unzip -o "${ELECTRON_ZIP_PATH}" -d "${outputDir}"`, { stdio: 'inherit' });
log(colors.green, '✅ 解压完成');
}
/**
* 复制应用文件
*/
function copyAppFiles(appDir) {
log(colors.blue, '📋 复制应用文件...');
const resourcesAppDir = join(appDir, 'resources', 'app');
mkdirSync(resourcesAppDir, { recursive: true });
// 复制 dist 目录
const distFiles = ['core', 'utils', 'ui', 'electron-main.js', 'preload.js', 'main.js', 'package.json'];
for (const file of distFiles) {
const src = join(distDir, file);
const dest = join(resourcesAppDir, file);
if (existsSync(src)) {
cpSync(src, dest, { recursive: true });
log(colors.green, `${file}`);
}
}
// 复制 node_modules
const nodeModulesDir = join(resourcesAppDir, 'node_modules');
mkdirSync(nodeModulesDir, { recursive: true });
const deps = ['onnxruntime-web', 'clipboardy', 'commander'];
for (const dep of deps) {
const src = join(rootDir, 'node_modules', dep);
const dest = join(nodeModulesDir, dep);
if (existsSync(src)) {
cpSync(src, dest, { recursive: true });
log(colors.green, ` ✅ node_modules/${dep}`);
}
}
// 创建空的 models 目录
mkdirSync(join(resourcesAppDir, 'models'), { recursive: true });
log(colors.green, ' ✅ models/');
}
/**
* 打包成 ZIP
*/
function createZip(packageName) {
log(colors.blue, '📦 打包 ZIP...');
const zipPath = join(releaseDir, packageName);
const appName = 'impress-asr-input-win-x64';
execSync(`zip -rq "${zipPath}" "${appName}"`, {
cwd: releaseDir,
stdio: 'inherit'
});
const size = Math.round(readFileSync(zipPath).length / 1024 / 1024 * 100) / 100;
log(colors.green, `✅ 打包完成:${packageName} (${size}MB)`);
}
/**
* 清理临时目录
*/
function cleanup() {
log(colors.blue, '🧹 清理临时文件...');
const tempDir = join(releaseDir, 'impress-asr-input-win-x64');
if (existsSync(tempDir)) {
rmSync(tempDir, { recursive: true, force: true });
}
log(colors.green, '✅ 清理完成');
}
/**
* 主函数
*/
function main() {
console.log('');
log(colors.green, '╔════════════════════════════════════════════╗');
log(colors.green, '║ Impress ASR Input - Windows x64 打包工具 ║');
log(colors.green, '╚════════════════════════════════════════════╝');
console.log('');
try {
// 1. 创建目录
ensureDirs();
// 2. 下载 Electron
downloadElectron();
// 3. 编译 TypeScript
compileTypeScript();
// 4. 解压 Electron 到临时目录
const tempDir = join(releaseDir, 'impress-asr-input-win-x64');
unzipElectron(tempDir);
// 5. 复制应用文件
copyAppFiles(tempDir);
// 6. 打包
const version = '0.1.0';
const packageName = `Impress_ASR_Input-${version}-win-x64.zip`;
createZip(packageName);
// 7. 清理
cleanup();
console.log('');
log(colors.green, '═══════════════════════════════════════');
log(colors.green, '✅ Windows x64 版本打包完成!');
log(colors.green, '═══════════════════════════════════════');
log(colors.blue, `📦 输出文件release/${packageName}`);
log(colors.blue, `💾 缓存目录:${userCacheDir}`);
console.log('');
} catch (error) {
console.log('');
log(colors.red, '❌ 打包失败!');
throw error;
}
}
// 运行
main();