MMHXYZ 技术笔记

Electron 桌面工具的覆盖式打包:几个反复咬人的坑

2026-10-27 · Electron · 约 4 分钟

我维护的一个 Windows 桌面工具,目录结构是固定的两个:02_唯一源代码 存源码,01_程序运行 存打包好的程序(resources/app.asar)。改完源码跑一个批处理,把新 asar 覆盖过去,双击启动脚本就能看到效果。

比每次重新 electron-builder 出一个安装包快得多,双击即可验证。但代价是所有"构建系统本该帮你处理的事",都得自己在脚本里补上。下面是反复踩到的几个。

一、文件被占用,覆盖静默失败

最典型的一次:改完代码跑构建,提示成功,启动一看还是旧界面。原因很简单——上次的 Electron 进程没完全退出,app.asar 还被句柄占着,copy 写不进去。

批处理里 copy 失败不会中断脚本,后面的"完成"照样打印,于是"构建成功"是假的。

修法两条一起上:

taskkill /F /IM "YourApp.exe" >nul 2>&1
timeout /t 2 /nobreak >nul
copy /Y "%SRC%\app.asar" "%DST%\resources\app.asar"
if errorlevel 1 (
  echo [ERROR] asar 覆盖失败,检查进程是否占用
  pause
  exit /b 1
)

errorlevel 判断不能省。没有失败分支的构建脚本,等于没有构建脚本。

二、asar 不是文件夹,别把它当文件夹改

app.asar 是个归档。有人图省事用解包工具拆开、改一个文件、再打回去,这个过程很容易把权限位和路径搞乱,特别是路径里带中文或空格的时候。

正确的做法永远是从源码目录整体重新打包:

npx asar pack "02_唯一源代码" "%DST%\resources\app.asar"

来源统一,产物才可复现。

三、原生模块不能进 asar

如果依赖里有 .node 文件(比如某些图像处理、加密库),它必须保持真实文件路径,不能被打进归档。Electron 对 asar 内的原生模块会加载失败。

处理方式是 asarUnpack,或者在打包后单独把 node_modules/xxx/*.node 拷到 app.asar.unpacked 对应位置。这个问题在开发机上不一定暴露——因为开发时是直接从源码目录加载的,只有打包后才崩。

四、端口固定值带来的"幽灵进程"

桌面工具通常会起一个本地 HTTP 服务(我这套默认 8794)。如果上一次的进程没死干净,新启动的实例会绑不上端口,表现是"界面打开了但所有请求都超时"。

启动脚本里加一层占用检测:

netstat -ano | findstr ":8794" | findstr "LISTENING" >nul
if not errorlevel 1 (
  echo [WARN] 8794 已被占用,可能上次没退出
  echo 请先结束占用进程,或关闭已运行的实例
  pause
  exit /b 1
)

比让用户对着白屏猜要友好得多。

五、批处理 + 中文路径的编码问题

.bat 默认按系统 ANSI 代码页解释。文件里写了中文路径、或者路径含中文,在某些机器上会变成乱码导致找不到目录。

稳妥做法是脚本开头切 UTF-8:

chcp 65001 >nul

但 chcp 只管控制台输出编码,如果脚本本身是 UTF-8 保存的而系统是 GBK,读取阶段就已经错了。所以更根本的办法是尽量让脚本里不出现非 ASCII 字符——路径用变量拼接,提示信息用英文,中文名目录通过 %~dp0 相对定位绕开。

六、源码和产物必须能明确区分

这套流程最大的风险不是技术问题,是人会搞混哪个是源头。一旦在运行时目录里直接改过东西,下次覆盖就把它冲掉了,而且没有任何提示。

我的做法是给两个目录加不同的标记文件,并且让构建脚本每次都打印来源和产物的绝对路径、大小、时间戳:

SRC: D:\app\02_唯一源代码      app.asar  18,442,112 B
DST: D:\app\01_程序运行\...    app.asar  18,442,112 B

两边大小对不上就是没打包成功。这个"看一眼数字"的习惯,比任何自动化都先救过我几次。

小结

覆盖式打包省掉的正是构建工具的检查环节,所以要自己把检查补回来:进程有没有退、文件有没有写成、端口有没有被占、包是不是真的变大了。

一句话:凡是脚本打印"成功"但没验证过的地方,迟早会骗你一次。

← 返回全部笔记