| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127 |
- const { execSync, spawn } = require('child_process')
- const path = require('path')
- const fs = require('fs')
- function runElectronBuilder(cwd) {
- const binName = process.platform === 'win32' ? 'electron-builder.cmd' : 'electron-builder'
- const electronBuilderBin = path.join(cwd, 'node_modules', '.bin', binName)
- if (!fs.existsSync(electronBuilderBin)) {
- return Promise.reject(new Error('未找到 electron-builder,请先在项目根目录执行 npm install。'))
- }
- const env = {
- ...process.env,
- DEBUG: 'electron-builder',
- // 使用国内镜像,避免 x64 Electron 下载不完整导致「缺少v8 startup snapshot」
- ELECTRON_MIRROR: process.env.ELECTRON_MIRROR || 'https://npmmirror.com/mirrors/electron/'
- }
- return new Promise((resolve, reject) => {
- const args = ['--win', '--x64']
- const opts = {
- cwd,
- stdio: ['inherit', 'inherit', 'inherit'],
- env,
- windowsHide: false
- }
- if (process.platform === 'win32') {
- opts.shell = true
- }
- const child = spawn(electronBuilderBin, args, opts)
- let elapsed = 0
- const progressInterval = setInterval(() => {
- elapsed += 10
- console.log(` → 打包进行中... (已等待 ${elapsed} 秒,请勿关闭)`)
- }, 10000)
- child.on('close', (code) => {
- clearInterval(progressInterval)
- if (code !== 0) {
- const err = new Error(`electron-builder 退出码: ${code}`)
- err.exitCode = code
- reject(err)
- } else resolve()
- })
- child.on('error', (err) => {
- clearInterval(progressInterval)
- reject(err)
- })
- })
- }
- const projectRoot = path.resolve(__dirname, '..')
- const distDir = path.join(projectRoot, 'dist')
- function cleanDist(keepDir) {
- if (!fs.existsSync(distDir)) return
- for (const name of fs.readdirSync(distDir)) {
- if (name === keepDir) continue
- const full = path.join(distDir, name)
- try {
- if (fs.statSync(full).isDirectory()) fs.rmSync(full, { recursive: true })
- else fs.unlinkSync(full)
- } catch (e) {
- console.warn('clean:', e.message)
- }
- }
- }
- async function main() {
- const keepDir = 'win-unpacked'
- try {
- console.log('[1/3] Vite build...')
- execSync('npm run build', { cwd: projectRoot, stdio: 'inherit' })
- } catch (e) {
- console.error('\n[错误] 第 1 步 Vite build 失败,已停止打包。')
- console.error(e.message || e)
- process.exit(1)
- }
- try {
- console.log('[2/3] Electron builder win x64...(每 10 秒会打印进度,请勿关闭)')
- console.log(' 若出现「缺少v8 startup snapshot」:请执行 rd /s /q "%LOCALAPPDATA%\\electron\\Cache" 后重试。')
- await runElectronBuilder(projectRoot)
- } catch (e) {
- console.error('\n[错误] 第 2 步 electron-builder 失败,已停止打包。')
- console.error(e.message || e)
- if (/v8|snapshot|startup/i.test(String(e.message))) {
- console.error('\n提示:可尝试清理 Electron 缓存后重试:')
- console.error(' rd /s /q "%LOCALAPPDATA%\\electron\\Cache"')
- }
- process.exit(1)
- }
- try {
- console.log('[3/3] 清理 dist,只保留 win-unpacked...')
- cleanDist(keepDir)
- const unpackedDir = path.join(distDir, keepDir)
- const readmePath = path.join(unpackedDir, '使用说明.txt')
- const readme = [
- 'AndroidRemoteController - 开包即用',
- '',
- '使用:直接双击运行 AndroidRemoteController.exe',
- '首次运行会在本目录自动创建 static 文件夹(用于存放运行时数据)。',
- '',
- '分发:可将本「win-unpacked」整个文件夹复制到任意 Windows 电脑使用,无需安装。',
- '请勿单独只复制 .exe,必须复制整个文件夹。',
- ''
- ].join('\r\n')
- try {
- fs.writeFileSync(readmePath, readme, 'utf8')
- console.log(' 已写入 使用说明.txt')
- } catch (e) {
- console.warn(' 写入使用说明.txt 失败:', e.message)
- }
- console.log('')
- console.log('Done. 输出目录: dist\\win-unpacked')
- console.log(' 可将该文件夹整体复制到任意 Windows 电脑,直接运行其中的 .exe 即可(开包即用)。')
- } catch (e) {
- console.error('\n[错误] 第 3 步 清理 dist 失败。')
- console.error(e.message || e)
- process.exit(1)
- }
- }
- if (require.main === module) {
- main().catch((e) => {
- console.error(e)
- process.exit(1)
- })
- } else {
- module.exports = { cleanDist }
- }
|