macOS 构建
构建分两步:先安装依赖并在开发态运行(`npx electron .`),再用 electron-builder 产出分架构的 `.app`。干净目录没有 lockfile,首次必须 `npm install`(不是 `npm ci`)。
前置检查
Shell
node -v && npm -v
xcode-select -p
ls node_modules/electron/dist/Electron.app # Electron 二进制已下载
npx electron --version # v35.x安装依赖
Shell
# 干净目录首次构建(无 package-lock.json 时不要用 npm ci)
npm install
npm install -D electron-builder@24
# SDK 当前未发布到 npm(@0.1.0 远程 404),从仓库本地安装:
npm install @ni-paas-im/electron@file:../sdk/electronElectron 二进制修复(npm 11 / Node 26 必需兜底)
先判定是否真的缺二进制,再按下述顺序修复;不要只删除 node_modules/electron 重装——npm 11 下 postinstall 仍可能被拦截,node install.js 也可能 exit 0 但未解压。
Shell
# 1) 判定:有输出 v35.x 即正常;报 “Electron failed to install correctly” 则缺失
test -x node_modules/electron/dist/Electron.app/Contents/MacOS/Electron && npx electron --version
# 2) 尝试前台执行 postinstall
npm install --foreground-scripts electron@35
# 3) 缓存 zip 手工兜底(最可靠;npm 静默失败也能修)
CACHE="${ELECTRON_CACHE:-$HOME/Library/Caches/electron}"
ZIP=$(find "$CACHE" -name 'electron-v*-darwin-*.zip' 2>/dev/null | sort | tail -1)
test -n "$ZIP" || { echo "未找到缓存 zip:先设置 ELECTRON_MIRROR 后重装"; exit 1; }
rm -rf node_modules/electron/dist
mkdir -p node_modules/electron/dist
unzip -q -o "$ZIP" -d node_modules/electron/dist
printf 'Electron.app/Contents/MacOS/Electron' > node_modules/electron/path.txt
# 4) 验证
npx electron --version # 期望:v35.7.5
npx electron . # 能打开窗口即修复完成
# 5) 缓存里没有 zip:设置镜像后重装,再回到第 3 步
export ELECTRON_MIRROR=https://npmmirror.com/mirrors/electron/
export ELECTRON_CACHE="$HOME/Library/Caches/electron"
rm -rf node_modules/electron && npm install --foreground-scripts electron@35| 判定 | 现象 | 结论 |
|---|---|---|
| 成功 | npx electron --version 输出 v35.x,且 dist/Electron.app 存在 | 可继续 npx electron . |
| 失败 | 报 Electron failed to install correctly / dist/ 只有 LICENSE、version | 按上面的缓存 zip 兜底 |
| 失败 | node_modules/electron/path.txt 缺失或内容不是 Electron.app/Contents/MacOS/Electron | 写入正确内容后重试 |
| 失败 | 缓存目录无 electron-v*-darwin-*.zip | 设置 ELECTRON_MIRROR/ELECTRON_CACHE 后重装再解压 |
版本兼容建议
优先 Node 22 LTS + npm 10;Node 26 / npm 11 的 allow-scripts 拦截是已知问题,缓存 zip 兜底可绕过。团队可用共享 ELECTRON_CACHE 避免重复下载。
开发构建
Shell
npx electron . # 开发态启动(加载 main.mjs)
# 需要调试时
ELECTRON_ENABLE_LOGGING=1 npx electron . --remote-debugging-port=9333生产打包
Shell
# 分架构:Intel + Apple Silicon(推荐,产物目录清晰)
npx electron-builder --mac --x64
npx electron-builder --mac --arm64
# 或一次产出 universal 包(体积约翻倍,构建更慢)
npx electron-builder --mac --universal| 产物 | 路径 | 说明 |
|---|---|---|
| 应用 | dist/mac/<ProductName>.app | 可双击运行;ad-hoc 或 Developer ID 签名 |
| Apple Silicon 应用 | dist/mac-arm64/<ProductName>.app | arm64 原生 |
| 安装包 | dist/<ProductName>-<version>.dmg | 拖入 Applications 安装 |
| 解包目录 | dist/mac/<ProductName>.app/Contents/ | Info.plist、Frameworks、Resources、MacOS |
| 符号 | *.dSYM(如启用) | 崩溃符号化,发布时一并归档 |
构建失败排查
| 现象 | 原因 | 处理 |
|---|---|---|
| `npm ci` 报 `package-lock.json` 缺失 | 干净目录首次构建 | 改用 `npm install` |
| `Electron failed to install correctly` | postinstall 被拦截或镜像不可达 | 按「Electron 二进制修复」解压缓存 zip + 写 `path.txt`;不要只删目录重装 |
| `Cannot find module .../main` | 入口路径与 `package.json.main` 不一致 | 核对 `main` 字段与构建产物目录 |
| `code signature invalid` | 签名后修改了包内容 | 重新签名;不要手改 `.app` 内文件 |
| `notarytool` 认证失败 | Apple ID / Team ID / 专用密码不匹配 | 见「公证」页的凭据检查 |
| 打出的包闪退 | 主进程异常(缺环境变量 / 服务端不可达) | `Console.app` 或 `log stream --predicate` 查看主进程日志 |
构建可复现
`npm install` + 固定 Electron / electron-builder 版本 + 锁定 Node 版本;CI 上把 `dist/` 与 `*.dSYM` 作为 artifact 归档。