Electron Forge 在 macOS M4 打包踩坑:Node.js 26 导致 make 异常中断
最近在 macOS M4 上使用 Electron Forge 打包 Electron 44 项目时,遇到了一个比较隐蔽的问题。
最开始的表现是:
electron-forge make一直停在打包阶段,看起来像是卡住了。
后来打开完整 Debug 才发现,它其实不是单纯"卡住",而是在 Electron 解压过程中提前结束,而且退出码还是 0。
最后尝试切换 Node.js 版本后,打包恢复正常。
记录一下完整过程。
一、macOS DMG 打包配置
如果 Electron Forge 需要生成 macOS 的 .dmg 安装包,可以使用:
bash
@electron-forge/maker-dmg
安装:
css
npm install --save-dev @electron-forge/maker-dmg
然后在 Forge 配置中加入:
arduino
{
name: '@electron-forge/maker-dmg',
platforms: ['darwin'],
config: {},
}
如果只需要生成 DMG,也可以指定 maker:
css
npx electron-forge make --targets=@electron-forge/maker-dmg
官方文档:
www.electronforge.io/config/make...
二、当前环境
当时的开发环境:
macOS:Apple Silicon M4 / arm64
Electron:44.0.0
Electron Forge:7.11.2
Node.js:26.5.0
npm:11.17.0
确认 Node、npm 和 Forge 版本:
css
node -v
npm -v
npx electron-forge --version
输出:
v26.5.0
11.17.0
7.11.2
确认当前架构:
arduino
node -p "process.arch + ' ' + process.platform"
输出:
arm64 darwin
三、最开始的问题:electron-forge make 一直等待
直接执行:
go
electron-forge make
前面的流程都正常:
sql
✔ Checking your system
✔ Loading configuration
✔ Resolving make targets
✔ Preparing to package application
✔ Running generateAssets hook
✔ Running prePackage hook
然后进入:
java
❯ Packaging application
❯ Packaging for arm64 on darwin
❯ Copying files
❯ Preparing native dependencies
❯ Finalizing package
最后一直停在:
go
Finalizing package
从表面来看,很像 Electron Forge 在最终打包阶段卡死了。
而且没有任何 Error 信息,所以很难判断到底是:
- Electron 下载问题
- 原生依赖问题
- Forge 配置问题
- macOS 打包问题
- Electron 本身的问题
四、第一次排查:打开 Electron Forge Debug
先尝试:
ini
DEBUG=electron-forge:* electron-forge make
这时候能够看到 Forge 内部更多信息,例如:
csharp
electron-forge:packager packaging with options {
arch: 'arm64',
platform: 'darwin',
out: '/Users/user/IdeaProjects/my-app/out',
electronVersion: '44.0.0'
}
可以确认当前目标是:
darwin
arm64
Electron 44.0.0
但是日志依然停在:
go
❯ Finalizing package
还不足以定位问题。
五、继续使用 DEBUG=* 查看完整日志
于是进一步执行:
ini
DEBUG=* electron-forge make
这次可以看到:
- electron-forge
- electron-packager
- @electron/get
- extract-zip
- sumchecker
等更底层的日志。
其中能够确认 Electron Packager 的运行环境:
perl
Electron Packager 18.4.4
Node v26.5.0
Host Operating system: darwin 25.5.0 (arm64)
Electron 版本:
yaml
Target Electron version: 44.0.0
目标平台:
yaml
Target Platforms: darwin
Target Architectures: arm64
这时候已经可以确定,问题发生在 Electron Packager 的实际打包阶段。
六、排除 Electron 下载和缓存问题
日志中可以看到:
csharp
electron-packager Downloading Electron with options {
"platform":"darwin",
"arch":"arm64",
"version":"44.0.0",
"artifactName":"electron"
}
紧接着:
kotlin
@electron/get:index Cache hit
说明 Electron 44 的 macOS ARM64 安装包已经存在本地缓存。
继续往下还能看到 checksum 校验:
yaml
Expected checksum:
076d79742986e1b100b69ebecc691cb07368045e54c9087cef631b8622b76a80
Actual:
076d79742986e1b100b69ebecc691cb07368045e54c9087cef631b8622b76a80
两个值完全一致。
因此当时基本排除了:
- Electron 下载失败
- GitHub 下载问题
- Electron 缓存损坏
- Electron ZIP 文件损坏
- checksum 校验失败
Electron 安装包本身没有异常。
七、真正异常发生在 Electron 解压阶段
接下来日志进入:
python
electron-packager Extracting electron-v44.0.0-darwin-arm64.zip
然后 extract-zip 开始正常解压:
python
extract-zip zipfile entry Electron.app/
extract-zip extracting entry ...
extract-zip finished processing ...
包括各种 Electron 资源目录:
bash
Electron.app/Contents/Resources/de.lproj/
Electron.app/Contents/Resources/ja.lproj/
Electron.app/Contents/Resources/zh_CN.lproj/
最后可以看到类似:
bash
extract-zip zipfile entry Electron.app/Contents/Resources/electron.icns
以及:
bash
extract-zip opening read stream
.../Electron.app/Contents/Resources/electron.icns
然后终端直接回到了:
perl
user@mac my-app %
这里最奇怪的是:
没有:
javascript
Error
没有:
Failed
也没有正常结束时应该出现的:
✔ Packaging application
✔ Making distributables
也就是说,最开始看起来像:
go
Finalizing package 卡住
但打开完整 Debug 后才发现实际情况更像:
go
Finalizing package
↓
Electron Packager 开始解压 Electron
↓
extract-zip 正常执行
↓
流程中途直接结束
八、检查退出码
为了判断是不是进程崩溃或者被 macOS 杀掉,继续执行:
ini
DEBUG=* electron-forge make
echo "EXIT_CODE=$?"
结果:
ini
EXIT_CODE=0
这个结果很反常。
一般来说:
0
代表程序正常退出。
如果是被 SIGKILL,通常会出现类似:
137
如果发生 segmentation fault,也通常不会是 0。
但这里的情况却是:
diff
Electron Forge 打包没有真正完成
+
没有 Error
+
EXIT_CODE=0
所以这也是为什么最开始会误以为它只是"卡住"。
实际上进程已经结束了,只是整个 Electron Forge make 流程没有完整执行到最后。
九、开始排查 Node.js 版本
继续检查版本后,当前组合是:
Node.js 26.5.0
npm 11.17.0
Electron Forge 7.11.2
Electron Packager 18.4.4
Electron 44.0.0
macOS M4 / arm64
由于:
- Electron 下载正常
- checksum 正常
- Electron ZIP 能正常开始解压
- 没有 Forge Error
- 没有普通 Node Error
- 退出码还是 0
于是开始把排查方向转向 Node.js 运行环境本身。
十、尝试切换到 Node.js 22
将 Node.js:
26.5.0
切换为 Node.js 22。
然后重新安装项目依赖:
bash
rm -rf node_modules
npm ci
清理之前的打包目录:
bash
rm -rf out
重新执行:
go
electron-forge make
这次 Electron Forge 可以正常继续执行后续流程,打包完成。
整个项目本身没有为了这个问题修改 Electron 代码,主要调整就是:
Node.js 26
↓
Node.js 22
十一、给项目固定 Node.js 版本
对于 Electron 项目,建议固定开发和打包使用的 Node.js 版本,避免系统 Node 升级后再次出现类似问题。
项目根目录可以增加:
.nvmrc
内容:
22
以后进入项目后执行:
perl
nvm use
即可切换到对应 Node.js 版本。
也可以在 package.json 中增加:
json
{
"engines": {
"node": ">=22 <23"
}
}
对于 Electron Forge 这类涉及:
java
Node.js
Electron Forge
Electron Packager
Electron
native modules
asar
macOS 打包工具链
的项目,Node.js 版本也是打包环境的一部分。
如果以后再遇到类似:
go
electron-forge make
↓
Finalizing package
↓
没有 Error
↓
DEBUG 日志执行到一半结束
↓
EXIT_CODE=0
除了检查 Forge 配置和 Electron 本身,也值得第一时间对比一下 Node.js 版本。