feat: 修复Mac打包编译
This commit is contained in:
File diff suppressed because it is too large
Load Diff
File diff suppressed because one or more lines are too long
Binary file not shown.
@@ -1,99 +1 @@
|
||||
"use strict";
|
||||
const electron = require("electron");
|
||||
var IPC_EVENTS = /* @__PURE__ */ ((IPC_EVENTS2) => {
|
||||
IPC_EVENTS2["EXTERNAL_OPEN"] = "external-open";
|
||||
IPC_EVENTS2["WINDOW_MINIMIZE"] = "window-minimize";
|
||||
IPC_EVENTS2["WINDOW_MAXIMIZE"] = "window-maximize";
|
||||
IPC_EVENTS2["WINDOW_CLOSE"] = "window-close";
|
||||
IPC_EVENTS2["IS_WINDOW_MAXIMIZED"] = "is-window-maximized";
|
||||
IPC_EVENTS2["APP_SET_FRAMELESS"] = "app:set-frameless";
|
||||
IPC_EVENTS2["APP_LOAD_PAGE"] = "app:load-page";
|
||||
IPC_EVENTS2["TAB_CREATE"] = "tab:create";
|
||||
IPC_EVENTS2["TAB_LIST"] = "tab:list";
|
||||
IPC_EVENTS2["TAB_NAVIGATE"] = "tab:navigate";
|
||||
IPC_EVENTS2["TAB_RELOAD"] = "tab:reload";
|
||||
IPC_EVENTS2["TAB_BACK"] = "tab:back";
|
||||
IPC_EVENTS2["TAB_FORWARD"] = "tab:forward";
|
||||
IPC_EVENTS2["TAB_SWITCH"] = "tab:switch";
|
||||
IPC_EVENTS2["TAB_CLOSE"] = "tab:close";
|
||||
IPC_EVENTS2["LOG_TO_MAIN"] = "log-to-main";
|
||||
IPC_EVENTS2["READ_FILE"] = "read-file";
|
||||
IPC_EVENTS2["INVOKE"] = "ipc:invoke";
|
||||
IPC_EVENTS2["INVOKE_ASYNC"] = "ipc:invokeAsync";
|
||||
IPC_EVENTS2["APP_MINIMIZE"] = "app:minimize";
|
||||
IPC_EVENTS2["APP_MAXIMIZE"] = "app:maximize";
|
||||
IPC_EVENTS2["APP_QUIT"] = "app:quit";
|
||||
IPC_EVENTS2["FILE_READ"] = "file:read";
|
||||
IPC_EVENTS2["FILE_WRITE"] = "file:write";
|
||||
IPC_EVENTS2["GET_WINDOW_ID"] = "get-window-id";
|
||||
IPC_EVENTS2["CUSTOM_EVENT"] = "custom:event";
|
||||
IPC_EVENTS2["TIME_UPDATE"] = "time:update";
|
||||
IPC_EVENTS2["RENDERER_IS_READY"] = "renderer-ready";
|
||||
IPC_EVENTS2["SHOW_CONTEXT_MENU"] = "show-context-menu";
|
||||
IPC_EVENTS2["START_A_DIALOGUE"] = "start-a-dialogue";
|
||||
IPC_EVENTS2["OPEN_WINDOW"] = "open-window";
|
||||
IPC_EVENTS2["LOG_DEBUG"] = "log-debug";
|
||||
IPC_EVENTS2["LOG_INFO"] = "log-info";
|
||||
IPC_EVENTS2["LOG_WARN"] = "log-warn";
|
||||
IPC_EVENTS2["LOG_ERROR"] = "log-error";
|
||||
IPC_EVENTS2["CONFIG_UPDATED"] = "config-updated";
|
||||
IPC_EVENTS2["SET_CONFIG"] = "set-config";
|
||||
IPC_EVENTS2["GET_CONFIG"] = "get-config";
|
||||
IPC_EVENTS2["UPDATE_CONFIG"] = "update-config";
|
||||
IPC_EVENTS2["SET_THEME_MODE"] = "set-theme-mode";
|
||||
IPC_EVENTS2["GET_THEME_MODE"] = "get-theme-mode";
|
||||
IPC_EVENTS2["IS_DARK_THEME"] = "is-dark-theme";
|
||||
IPC_EVENTS2["THEME_MODE_UPDATED"] = "theme-mode-updated";
|
||||
IPC_EVENTS2["EXECUTE_SCRIPT"] = "execute-script";
|
||||
IPC_EVENTS2["OPEN_CHANNEL"] = "open-channel";
|
||||
IPC_EVENTS2["UPDATE_CHECK"] = "update:check";
|
||||
IPC_EVENTS2["UPDATE_DOWNLOAD"] = "update:download";
|
||||
IPC_EVENTS2["UPDATE_INSTALL"] = "update:install";
|
||||
IPC_EVENTS2["UPDATE_VERSION"] = "update:version";
|
||||
IPC_EVENTS2["UPDATE_STATUS_CHANGED"] = "update:status-changed";
|
||||
return IPC_EVENTS2;
|
||||
})(IPC_EVENTS || {});
|
||||
const api = {
|
||||
versions: process.versions,
|
||||
external: {
|
||||
open: (url) => electron.ipcRenderer.invoke("external-open", url)
|
||||
},
|
||||
closeWindow: () => electron.ipcRenderer.send(IPC_EVENTS.WINDOW_CLOSE),
|
||||
minimizeWindow: () => electron.ipcRenderer.send(IPC_EVENTS.WINDOW_MINIMIZE),
|
||||
maximizeWindow: () => electron.ipcRenderer.send(IPC_EVENTS.WINDOW_MAXIMIZE),
|
||||
onWindowMaximized: (callback) => electron.ipcRenderer.on(IPC_EVENTS.WINDOW_MAXIMIZE + "back", (_, isMaximized) => callback(isMaximized)),
|
||||
isWindowMaximized: () => electron.ipcRenderer.invoke(IPC_EVENTS.IS_WINDOW_MAXIMIZED),
|
||||
viewIsReady: () => electron.ipcRenderer.send(IPC_EVENTS.RENDERER_IS_READY),
|
||||
app: {
|
||||
setFrameless: (route) => electron.ipcRenderer.invoke(IPC_EVENTS.APP_SET_FRAMELESS, route),
|
||||
loadPage: (page) => electron.ipcRenderer.invoke(IPC_EVENTS.APP_LOAD_PAGE, page)
|
||||
},
|
||||
// 通过 IPC 调用主进程
|
||||
readFile: (filePath) => electron.ipcRenderer.invoke(IPC_EVENTS.READ_FILE, filePath),
|
||||
// 异步调用(映射为 electron 的 invoke)
|
||||
invoke: (channel, ...args) => electron.ipcRenderer.invoke(channel, ...args),
|
||||
// 异步调用(为了兼容老代码)
|
||||
invokeAsync: (channel, ...args) => electron.ipcRenderer.invoke(channel, ...args),
|
||||
// 监听主进程消息
|
||||
on: (event, callback) => {
|
||||
const subscription = (_event, ...args) => callback(...args);
|
||||
electron.ipcRenderer.on(event, subscription);
|
||||
return () => electron.ipcRenderer.removeListener(event, subscription);
|
||||
},
|
||||
// 发送消息到主进程
|
||||
send: (channel, ...args) => electron.ipcRenderer.send(channel, ...args),
|
||||
// 获取窗口ID
|
||||
getCurrentWindowId: () => electron.ipcRenderer.sendSync(IPC_EVENTS.GET_WINDOW_ID),
|
||||
// 发送日志
|
||||
logger: {
|
||||
debug: (message, ...meta) => electron.ipcRenderer.send(IPC_EVENTS.LOG_DEBUG, message, ...meta),
|
||||
info: (message, ...meta) => electron.ipcRenderer.send(IPC_EVENTS.LOG_INFO, message, ...meta),
|
||||
warn: (message, ...meta) => electron.ipcRenderer.send(IPC_EVENTS.LOG_WARN, message, ...meta),
|
||||
error: (message, ...meta) => electron.ipcRenderer.send(IPC_EVENTS.LOG_ERROR, message, ...meta)
|
||||
},
|
||||
// 执行脚本
|
||||
executeScript: (params) => electron.ipcRenderer.invoke(IPC_EVENTS.EXECUTE_SCRIPT, params),
|
||||
// 打开渠道
|
||||
openChannel: (channels) => electron.ipcRenderer.invoke(IPC_EVENTS.OPEN_CHANNEL, channels)
|
||||
};
|
||||
electron.contextBridge.exposeInMainWorld("api", api);
|
||||
"use strict";const n=require("electron");var i=(e=>(e.EXTERNAL_OPEN="external-open",e.WINDOW_MINIMIZE="window-minimize",e.WINDOW_MAXIMIZE="window-maximize",e.WINDOW_CLOSE="window-close",e.IS_WINDOW_MAXIMIZED="is-window-maximized",e.APP_SET_FRAMELESS="app:set-frameless",e.APP_LOAD_PAGE="app:load-page",e.TAB_CREATE="tab:create",e.TAB_LIST="tab:list",e.TAB_NAVIGATE="tab:navigate",e.TAB_RELOAD="tab:reload",e.TAB_BACK="tab:back",e.TAB_FORWARD="tab:forward",e.TAB_SWITCH="tab:switch",e.TAB_CLOSE="tab:close",e.LOG_TO_MAIN="log-to-main",e.READ_FILE="read-file",e.INVOKE="ipc:invoke",e.INVOKE_ASYNC="ipc:invokeAsync",e.APP_MINIMIZE="app:minimize",e.APP_MAXIMIZE="app:maximize",e.APP_QUIT="app:quit",e.FILE_READ="file:read",e.FILE_WRITE="file:write",e.GET_WINDOW_ID="get-window-id",e.CUSTOM_EVENT="custom:event",e.TIME_UPDATE="time:update",e.RENDERER_IS_READY="renderer-ready",e.SHOW_CONTEXT_MENU="show-context-menu",e.START_A_DIALOGUE="start-a-dialogue",e.OPEN_WINDOW="open-window",e.LOG_DEBUG="log-debug",e.LOG_INFO="log-info",e.LOG_WARN="log-warn",e.LOG_ERROR="log-error",e.CONFIG_UPDATED="config-updated",e.SET_CONFIG="set-config",e.GET_CONFIG="get-config",e.UPDATE_CONFIG="update-config",e.SET_THEME_MODE="set-theme-mode",e.GET_THEME_MODE="get-theme-mode",e.IS_DARK_THEME="is-dark-theme",e.THEME_MODE_UPDATED="theme-mode-updated",e.EXECUTE_SCRIPT="execute-script",e.OPEN_CHANNEL="open-channel",e.UPDATE_CHECK="update:check",e.UPDATE_DOWNLOAD="update:download",e.UPDATE_INSTALL="update:install",e.UPDATE_VERSION="update:version",e.UPDATE_STATUS_CHANGED="update:status-changed",e))(i||{});const a={versions:process.versions,external:{open:e=>n.ipcRenderer.invoke("external-open",e)},closeWindow:()=>n.ipcRenderer.send(i.WINDOW_CLOSE),minimizeWindow:()=>n.ipcRenderer.send(i.WINDOW_MINIMIZE),maximizeWindow:()=>n.ipcRenderer.send(i.WINDOW_MAXIMIZE),onWindowMaximized:e=>n.ipcRenderer.on(i.WINDOW_MAXIMIZE+"back",(r,d)=>e(d)),isWindowMaximized:()=>n.ipcRenderer.invoke(i.IS_WINDOW_MAXIMIZED),viewIsReady:()=>n.ipcRenderer.send(i.RENDERER_IS_READY),app:{setFrameless:e=>n.ipcRenderer.invoke(i.APP_SET_FRAMELESS,e),loadPage:e=>n.ipcRenderer.invoke(i.APP_LOAD_PAGE,e)},readFile:e=>n.ipcRenderer.invoke(i.READ_FILE,e),invoke:(e,...r)=>n.ipcRenderer.invoke(e,...r),invokeAsync:(e,...r)=>n.ipcRenderer.invoke(e,...r),on:(e,r)=>{const d=(t,...o)=>r(...o);return n.ipcRenderer.on(e,d),()=>n.ipcRenderer.removeListener(e,d)},send:(e,...r)=>n.ipcRenderer.send(e,...r),getCurrentWindowId:()=>n.ipcRenderer.sendSync(i.GET_WINDOW_ID),logger:{debug:(e,...r)=>n.ipcRenderer.send(i.LOG_DEBUG,e,...r),info:(e,...r)=>n.ipcRenderer.send(i.LOG_INFO,e,...r),warn:(e,...r)=>n.ipcRenderer.send(i.LOG_WARN,e,...r),error:(e,...r)=>n.ipcRenderer.send(i.LOG_ERROR,e,...r)},executeScript:e=>n.ipcRenderer.invoke(i.EXECUTE_SCRIPT,e),openChannel:e=>n.ipcRenderer.invoke(i.OPEN_CHANNEL,e)};n.contextBridge.exposeInMainWorld("api",a);
|
||||
|
||||
1
dist/assets/index-CvK9ZwFP.css
vendored
1
dist/assets/index-CvK9ZwFP.css
vendored
@@ -1 +0,0 @@
|
||||
[data-v-eceb1c86] .el-steps--simple{background:0 0}[data-v-eceb1c86] .el-step.is-simple .el-step__arrow:before{background:#525866;width:2px}[data-v-eceb1c86] .el-step.is-simple .el-step__arrow:after{background:#525866;width:2px}[data-v-eceb1c86] .el-step__head.is-process .el-step__icon.is-text{border-color:#2b7fff}[data-v-eceb1c86] .el-step__head.is-success{color:#1fc16b}[data-v-eceb1c86] .el-step__head.is-success .el-step__icon.is-text{background:#1fc16b}[data-v-eceb1c86] .el-step__head.is-success .el-step__icon.is-text{color:#fff;border-color:#1fc16b}[data-v-eceb1c86] .el-step__title.is-success{color:#525866;font-size:14px;font-weight:500}[data-v-eceb1c86] .el-textarea .el-input__count.is-outside{top:auto;bottom:10px;right:15px}[data-v-6ab79709] .el-button.button{background:linear-gradient(#4a8ff9,#0000),#2b7fff;border:1px solid #1447e6;border-radius:8px;padding-top:18px;padding-bottom:18px;box-shadow:0 1px 1px #0000000d,inset 0 0 0 1px #ffffff3d}[data-v-84bf9ea3] .el-table tr td:nth-of-type(1){background:#eff6ff!important}[data-v-84bf9ea3] .el-tag{color:#525866;background:#fff!important;border:1px solid #e5e8ee!important;border-radius:6px!important}[data-v-4c31200f] .el-tabs__item{color:#99a0ae}[data-v-4c31200f] .el-tabs__item.is-active{color:#2b7fff}[data-v-4c31200f] .el-tabs__active-bar{background-color:#2b7fff}
|
||||
1
dist/assets/index-tccZ5UIk.css
vendored
1
dist/assets/index-tccZ5UIk.css
vendored
@@ -1 +0,0 @@
|
||||
.task[data-v-74ff89ed]{z-index:1;transition:all .2s linear;position:relative}.task .success[data-v-74ff89ed]{color:#1fc16b;background-color:#e0faec}.task .error[data-v-74ff89ed]{color:#fb3748;background-color:#ffebec}.task .warning[data-v-74ff89ed]{color:#fa7319;background-color:#fff3eb}.task[data-v-74ff89ed]:hover{z-index:2;transform:translateY(-2px);box-shadow:0 10px 20px #0000001a}.task-tab .text[data-v-be5e193a]{color:#525866;cursor:pointer;font-size:14px}.task-tab .active[data-v-be5e193a]{color:#2b7fff;background:#fff;border-radius:8px;position:relative}.task-tab .active[data-v-be5e193a]:after{content:"";border:1px solid #2b7fff;border-radius:8px;width:100%;height:100%;position:absolute;top:0;left:0}.task-tab .text[data-v-33324fcc]{color:#525866;cursor:pointer;font-size:14px}.task-tab .active[data-v-33324fcc]{color:#2b7fff;background:#fff;border-radius:8px;position:relative}.task-tab .active[data-v-33324fcc]:after{content:"";border:1px solid #2b7fff;border-radius:8px;width:100%;height:100%;position:absolute;top:0;left:0}pre code.hljs{padding:1em;display:block;overflow-x:auto}code.hljs{padding:3px 5px}.hljs{color:#24292e;background:#fff}.hljs-doctag,.hljs-keyword,.hljs-meta .hljs-keyword,.hljs-template-tag,.hljs-template-variable,.hljs-type,.hljs-variable.language_{color:#d73a49}.hljs-title,.hljs-title.class_,.hljs-title.class_.inherited__,.hljs-title.function_{color:#6f42c1}.hljs-attr,.hljs-attribute,.hljs-literal,.hljs-meta,.hljs-number,.hljs-operator,.hljs-variable,.hljs-selector-attr,.hljs-selector-class,.hljs-selector-id{color:#005cc5}.hljs-regexp,.hljs-string,.hljs-meta .hljs-string{color:#032f62}.hljs-built_in,.hljs-symbol{color:#e36209}.hljs-comment,.hljs-code,.hljs-formula{color:#6a737d}.hljs-name,.hljs-quote,.hljs-selector-tag,.hljs-selector-pseudo{color:#22863a}.hljs-subst{color:#24292e}.hljs-section{color:#005cc5;font-weight:700}.hljs-bullet{color:#735c0f}.hljs-emphasis{color:#24292e;font-style:italic}.hljs-strong{color:#24292e;font-weight:700}.hljs-addition{color:#22863a;background-color:#f0fff4}.hljs-deletion{color:#b31d28;background-color:#ffeef0}.wave[data-v-5b734189]{text-align:center;width:30px;position:relative}.dot[data-v-5b734189]{background:#333;border-radius:50%;width:3px;height:3px;margin-right:3px;animation:1.3s linear infinite wave-5b734189;display:inline-block}.dot[data-v-5b734189]:nth-child(2){animation-delay:-1.1s}.dot[data-v-5b734189]:nth-child(3){animation-delay:-.9s}@keyframes wave-5b734189{0%,60%,to{transform:initial}30%{transform:translateY(-5px)}}
|
||||
4
dist/index.html
vendored
4
dist/index.html
vendored
@@ -8,8 +8,8 @@
|
||||
http-equiv="Content-Security-Policy"
|
||||
content="default-src 'self'; script-src 'self'; style-src 'self' 'unsafe-inline'; img-src 'self' http://8.138.234.141 https://one-feel-bucket.oss-cn-guangzhou.aliyuncs.com; connect-src 'self' http://8.138.234.141 https://api.iconify.design wss://onefeel.brother7.cn"
|
||||
/>
|
||||
<script type="module" crossorigin src="./assets/index-C4Gb4VF1.js"></script>
|
||||
<link rel="stylesheet" crossorigin href="./assets/index-CZoyThnd.css">
|
||||
<script type="module" crossorigin src="./assets/index-BmjJNchE.js"></script>
|
||||
<link rel="stylesheet" crossorigin href="./assets/index-BjlT3-UA.css">
|
||||
</head>
|
||||
<body>
|
||||
<div id="app"></div>
|
||||
|
||||
14
package.json
14
package.json
@@ -9,7 +9,7 @@
|
||||
"start": "vite",
|
||||
"build": "vite build && electron-builder",
|
||||
"build:vite": "vite build",
|
||||
"package": "electron-builder",
|
||||
"package": "vite build",
|
||||
"icons": "zx scripts/generate-icons.mjs",
|
||||
"uv:download": "zx scripts/download-bundled-uv.mjs",
|
||||
"uv:download:mac": "zx scripts/download-bundled-uv.mjs --platform=mac",
|
||||
@@ -18,10 +18,14 @@
|
||||
"uv:download:all": "zx scripts/download-bundled-uv.mjs --all",
|
||||
"node:download:win": "zx scripts/download-bundled-node.mjs --platform=win",
|
||||
"prep:win-binaries": "pnpm run uv:download:win && pnpm run node:download:win",
|
||||
"package:win": "pnpm run prep:win-binaries && vite build && electron-builder --win --publish never",
|
||||
"package:mac": "vite build && electron-builder --mac --publish never",
|
||||
"package:linux": "vite build && electron-builder --linux --publish never",
|
||||
"release": "vite build && electron-builder --publish always",
|
||||
"package:win": "pnpm run prep:win-binaries && pnpm run package && electron-builder --win --publish never",
|
||||
"package:mac": "pnpm run package && electron-builder --mac --publish never",
|
||||
"package:mac:local": "SKIP_AFTERPACK_CLEANUP=1 pnpm run package && electron-builder --mac --publish never",
|
||||
"package:mac:x64": "pnpm run package && electron-builder --mac --x64 --publish never",
|
||||
"package:mac:arm64": "pnpm run package && electron-builder --mac --arm64 --publish never",
|
||||
"package:mac:fast": "pnpm run package && electron-builder --mac --publish never --config.compression=normal",
|
||||
"package:linux": "pnpm run package && electron-builder --linux --publish never",
|
||||
"release": "pnpm run package && electron-builder --publish always",
|
||||
"lint": "eslint --ext .ts,.tsx .",
|
||||
"typecheck": "tsc --noEmit",
|
||||
"openapi": "dotenv -e .env -- openapi-ts",
|
||||
|
||||
145
package_mac_diagnosis_report.md
Normal file
145
package_mac_diagnosis_report.md
Normal file
@@ -0,0 +1,145 @@
|
||||
# package:mac 打包诊断报告
|
||||
|
||||
**诊断时间**: 2026-04-11
|
||||
**项目路径**: `/Users/duanshuwen/Documents/workspace/electron/zn-ai`
|
||||
**执行命令**: `pnpm run package:mac`
|
||||
|
||||
---
|
||||
|
||||
## 1. 结论摘要
|
||||
|
||||
**本次打包失败不是因为项目源码缺少文件或 `electron-builder.yml` 配置项缺失,而是因为**
|
||||
|
||||
1. **网络下载中断**:`electron-builder` 在构建 DMG 时需要下载 `dmgbuild-bundle-x86_64`,该请求被服务器中断(`ReadError: The server aborted pending request`)。
|
||||
2. **并发锁竞争**:`mac.target` 同时配置了 `x64` 与 `arm64` 两种架构,`electron-builder` 并行打包时两个进程争抢 `proper-lockfile` 的缓存锁,导致下载失败后的清理阶段抛出 `Lock file is already being held` 错误。
|
||||
3. **(非致命)代码签名证书已过期**:本地唯一的 `Apple Development` 证书状态为 `CSSMERR_TP_CERT_EXPIRED`,因此 `electron-builder` 跳过了正式签名,仅做了 ad-hoc 签名。这不会导致打包中断,但会影响最终 app 在 macOS Gatekeeper 下的可运行性。
|
||||
|
||||
---
|
||||
|
||||
## 2. 关键错误日志
|
||||
|
||||
```text
|
||||
• downloading release=dmg-builder@1.2.0 file=dmgbuild-bundle-x86_64-75c8a6c.tar.gz
|
||||
...
|
||||
ReadError: The server aborted pending request
|
||||
...
|
||||
Error: Lock file is already being held
|
||||
at /Users/duanshuwen/Documents/workspace/electron/zn-ai/node_modules/proper-lockfile/lib/lockfile.js:68:47
|
||||
...
|
||||
ELIFECYCLE Command failed with exit code 1.
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 3. 配置与文件检查结果
|
||||
|
||||
| 检查项 | 状态 | 说明 |
|
||||
|--------|------|------|
|
||||
| `package.json` | 正常 | 存在且 `package:mac` 脚本定义正确 |
|
||||
| `electron-builder.yml` | 正常 | 配置完整,`mac` / `dmg` / `win` / `linux` 分平台配置齐全 |
|
||||
| `resources/icons/icon.icns` | 正常 | `mac.icon` 指向的文件存在 |
|
||||
| `entitlements.mac.plist` | 正常 | 文件存在并已配置 |
|
||||
| `dist` / `dist-electron` | 正常 | `vite build` 阶段成功通过,产物已生成 |
|
||||
| 发布产物 | 部分生成 | `zip`(x64 / arm64)已成功生成,但 DMG(x64 / arm64)因下载失败未完成 |
|
||||
|
||||
---
|
||||
|
||||
## 4. 详细原因分析
|
||||
|
||||
### 4.1 网络问题导致 dmg-builder 下载中断
|
||||
`electron-builder` 在首次构建 DMG 时需要拉取预编译的 `dmg-builder` bundle(`dmgbuild-bundle-x86_64-75c8a6c.tar.gz`)。由于该资源托管在 GitHub / AWS CDN 上,在国内网络环境下极易出现连接被重置或请求被服务器中断的情况。
|
||||
|
||||
### 4.2 并发构建加剧锁竞争
|
||||
`electron-builder.yml` 中配置了同时打包两种架构:
|
||||
|
||||
```yaml
|
||||
mac:
|
||||
target:
|
||||
- target: dmg
|
||||
arch:
|
||||
- x64
|
||||
- arm64
|
||||
- target: zip
|
||||
arch:
|
||||
- x64
|
||||
- arm64
|
||||
```
|
||||
|
||||
这导致 `electron-builder` 会并行启动多个打包任务。当它们同时尝试下载/解压同一个 `dmg-builder` 缓存时,`proper-lockfile` 产生竞争;一旦其中一个下载失败,另一个在清理阶段也会因无法获取锁而报错,最终整体构建失败。
|
||||
|
||||
### 4.3 代码签名证书过期(仅提示,不中断构建)
|
||||
日志中出现的:
|
||||
|
||||
```text
|
||||
skipped macOS application code signing reason=cannot find valid "Developer ID Application" identity ...
|
||||
"Apple Development: 562304744@qq.com (Z27TQS657B)" (CSSMERR_TP_CERT_EXPIRED)
|
||||
```
|
||||
|
||||
这说明本地证书已过期,不会影响打包流程本身,但生成的 `.app` 没有有效的开发者签名,分发后用户打开时会遇到 "已损坏,无法打开" 的 Gatekeeper 提示。
|
||||
|
||||
---
|
||||
|
||||
## 5. 解决方案与建议
|
||||
|
||||
### 方案 A:分架构单独打包(推荐,最稳定)
|
||||
先避免并发锁竞争,同时降低单次构建对网络的敏感度:
|
||||
|
||||
```bash
|
||||
# 仅打包 arm64(Apple Silicon)
|
||||
cd zn-ai
|
||||
npx electron-builder --mac --arm64 --publish never
|
||||
|
||||
# 仅打包 x64(Intel)
|
||||
npx electron-builder --mac --x64 --publish never
|
||||
```
|
||||
|
||||
若网络仍不稳定,可配置代理或手动下载缓存(见方案 B)。
|
||||
|
||||
### 方案 B:配置 electron-builder 缓存
|
||||
如果网络受限,可预先设置缓存目录并手动下载所需 bundle:
|
||||
|
||||
```bash
|
||||
export ELECTRON_BUILDER_CACHE="$HOME/.electron-builder-cache"
|
||||
```
|
||||
|
||||
然后手动将 `dmgbuild-bundle-x86_64-75c8a6c.tar.gz` 放置到缓存目录的 `cache/dmg-builder` 子目录下,再执行打包。
|
||||
|
||||
### 方案 C:修改 `electron-builder.yml` 降低并发
|
||||
在 `mac.target` 里先只保留当前常用架构(如 `arm64`),需要时再切换:
|
||||
|
||||
```yaml
|
||||
mac:
|
||||
target:
|
||||
- target: dmg
|
||||
arch:
|
||||
- arm64
|
||||
- target: zip
|
||||
arch:
|
||||
- arm64
|
||||
```
|
||||
|
||||
### 方案 D:修复代码签名(分发前必须)
|
||||
若计划将应用分发给其他用户,需要:
|
||||
1. 在 Apple Developer 后台续期或重新申请 **Developer ID Application** 证书;
|
||||
2. 将 `notarize` 改为 `true` 并配置正确的 `teamId`;
|
||||
3. 在构建机器上安装新证书后重新打包。
|
||||
|
||||
---
|
||||
|
||||
## 6. 附录:构建产物现状
|
||||
|
||||
截至诊断时,`release/` 目录下已生成:
|
||||
|
||||
- `NIANXX-1.0.0-mac-x64.zip` (133 MB)
|
||||
- `NIANXX-1.0.0-mac-arm64.zip` (129 MB)
|
||||
- 对应的 `.blockmap` 文件
|
||||
|
||||
**未生成**:
|
||||
- `NIANXX-1.0.0-mac-x64.dmg`
|
||||
- `NIANXX-1.0.0-mac-arm64.dmg`
|
||||
|
||||
原因即上述网络下载中断 + 并发锁竞争。
|
||||
|
||||
---
|
||||
|
||||
*报告结束*
|
||||
@@ -142,7 +142,8 @@ module.exports = async function afterPack(context) {
|
||||
await ensureDependency(dep);
|
||||
}
|
||||
|
||||
// 3. Clean up unnecessary development files from node_modules
|
||||
// 3. Clean up unnecessary development files from node_modules (skip if SKIP_AFTERPACK_CLEANUP is set)
|
||||
if (!process.env.SKIP_AFTERPACK_CLEANUP) {
|
||||
const nodeModulesDest = path.join(appOutDir, 'node_modules');
|
||||
if (await fs.pathExists(nodeModulesDest)) {
|
||||
console.log('Cleaning up development files in node_modules...');
|
||||
@@ -156,6 +157,9 @@ module.exports = async function afterPack(context) {
|
||||
const removedScripts = cleanupUnnecessaryFiles(scriptsDest);
|
||||
console.log(`Removed ${removedScripts} unnecessary files/directories from scripts.`);
|
||||
}
|
||||
} else {
|
||||
console.log('Skipping afterPack cleanup (SKIP_AFTERPACK_CLEANUP is set)');
|
||||
}
|
||||
|
||||
// 5. Optional: platform-specific native package cleanup
|
||||
// cleanupNativePlatformPackages(nodeModulesDest, platform, arch);
|
||||
|
||||
Reference in New Issue
Block a user