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/electron

Electron 二进制修复(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>.apparm64 原生
安装包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 归档。