package-x64.js 4.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127
  1. const { execSync, spawn } = require('child_process')
  2. const path = require('path')
  3. const fs = require('fs')
  4. function runElectronBuilder(cwd) {
  5. const binName = process.platform === 'win32' ? 'electron-builder.cmd' : 'electron-builder'
  6. const electronBuilderBin = path.join(cwd, 'node_modules', '.bin', binName)
  7. if (!fs.existsSync(electronBuilderBin)) {
  8. return Promise.reject(new Error('未找到 electron-builder,请先在项目根目录执行 npm install。'))
  9. }
  10. const env = {
  11. ...process.env,
  12. DEBUG: 'electron-builder',
  13. // 使用国内镜像,避免 x64 Electron 下载不完整导致「缺少v8 startup snapshot」
  14. ELECTRON_MIRROR: process.env.ELECTRON_MIRROR || 'https://npmmirror.com/mirrors/electron/'
  15. }
  16. return new Promise((resolve, reject) => {
  17. const args = ['--win', '--x64']
  18. const opts = {
  19. cwd,
  20. stdio: ['inherit', 'inherit', 'inherit'],
  21. env,
  22. windowsHide: false
  23. }
  24. if (process.platform === 'win32') {
  25. opts.shell = true
  26. }
  27. const child = spawn(electronBuilderBin, args, opts)
  28. let elapsed = 0
  29. const progressInterval = setInterval(() => {
  30. elapsed += 10
  31. console.log(` → 打包进行中... (已等待 ${elapsed} 秒,请勿关闭)`)
  32. }, 10000)
  33. child.on('close', (code) => {
  34. clearInterval(progressInterval)
  35. if (code !== 0) {
  36. const err = new Error(`electron-builder 退出码: ${code}`)
  37. err.exitCode = code
  38. reject(err)
  39. } else resolve()
  40. })
  41. child.on('error', (err) => {
  42. clearInterval(progressInterval)
  43. reject(err)
  44. })
  45. })
  46. }
  47. const projectRoot = path.resolve(__dirname, '..')
  48. const distDir = path.join(projectRoot, 'dist')
  49. function cleanDist(keepDir) {
  50. if (!fs.existsSync(distDir)) return
  51. for (const name of fs.readdirSync(distDir)) {
  52. if (name === keepDir) continue
  53. const full = path.join(distDir, name)
  54. try {
  55. if (fs.statSync(full).isDirectory()) fs.rmSync(full, { recursive: true })
  56. else fs.unlinkSync(full)
  57. } catch (e) {
  58. console.warn('clean:', e.message)
  59. }
  60. }
  61. }
  62. async function main() {
  63. const keepDir = 'win-unpacked'
  64. try {
  65. console.log('[1/3] Vite build...')
  66. execSync('npm run build', { cwd: projectRoot, stdio: 'inherit' })
  67. } catch (e) {
  68. console.error('\n[错误] 第 1 步 Vite build 失败,已停止打包。')
  69. console.error(e.message || e)
  70. process.exit(1)
  71. }
  72. try {
  73. console.log('[2/3] Electron builder win x64...(每 10 秒会打印进度,请勿关闭)')
  74. console.log(' 若出现「缺少v8 startup snapshot」:请执行 rd /s /q "%LOCALAPPDATA%\\electron\\Cache" 后重试。')
  75. await runElectronBuilder(projectRoot)
  76. } catch (e) {
  77. console.error('\n[错误] 第 2 步 electron-builder 失败,已停止打包。')
  78. console.error(e.message || e)
  79. if (/v8|snapshot|startup/i.test(String(e.message))) {
  80. console.error('\n提示:可尝试清理 Electron 缓存后重试:')
  81. console.error(' rd /s /q "%LOCALAPPDATA%\\electron\\Cache"')
  82. }
  83. process.exit(1)
  84. }
  85. try {
  86. console.log('[3/3] 清理 dist,只保留 win-unpacked...')
  87. cleanDist(keepDir)
  88. const unpackedDir = path.join(distDir, keepDir)
  89. const readmePath = path.join(unpackedDir, '使用说明.txt')
  90. const readme = [
  91. 'AndroidRemoteController - 开包即用',
  92. '',
  93. '使用:直接双击运行 AndroidRemoteController.exe',
  94. '首次运行会在本目录自动创建 static 文件夹(用于存放运行时数据)。',
  95. '',
  96. '分发:可将本「win-unpacked」整个文件夹复制到任意 Windows 电脑使用,无需安装。',
  97. '请勿单独只复制 .exe,必须复制整个文件夹。',
  98. ''
  99. ].join('\r\n')
  100. try {
  101. fs.writeFileSync(readmePath, readme, 'utf8')
  102. console.log(' 已写入 使用说明.txt')
  103. } catch (e) {
  104. console.warn(' 写入使用说明.txt 失败:', e.message)
  105. }
  106. console.log('')
  107. console.log('Done. 输出目录: dist\\win-unpacked')
  108. console.log(' 可将该文件夹整体复制到任意 Windows 电脑,直接运行其中的 .exe 即可(开包即用)。')
  109. } catch (e) {
  110. console.error('\n[错误] 第 3 步 清理 dist 失败。')
  111. console.error(e.message || e)
  112. process.exit(1)
  113. }
  114. }
  115. if (require.main === module) {
  116. main().catch((e) => {
  117. console.error(e)
  118. process.exit(1)
  119. })
  120. } else {
  121. module.exports = { cleanDist }
  122. }