From a6be917637c8cc44052cfcef3f50afecec5b91df Mon Sep 17 00:00:00 2001 From: jkooe <62494645+jkooe@users.noreply.github.com> Date: Sun, 11 Oct 2026 08:55:45 +0800 Subject: [PATCH] =?UTF-8?q?docs:=20=E8=AE=B0=E5=BD=95=E6=8E=A7=E5=88=B6?= =?UTF-8?q?=E5=8F=B0=20Node=20=E8=BF=90=E8=A1=8C=E6=97=B6=E5=88=86?= =?UTF-8?q?=E5=8F=91=E4=B8=8E=E4=BD=93=E7=A7=AF=E5=8F=A3=E5=BE=84=E8=B0=83?= =?UTF-8?q?=E6=95=B4?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - console-plan.md: · §8.2 打包体积指标口径由「Mac .app < 30MB」改为「**分发件** Mac .dmg < 40MB」 —— 原数字是 Tauri + Rust client 时代定的(当时应用内不含 JS 运行时); 改 sidecar 方案后应用必须自带 Node 运行时,.app 因此到 90.8MB,但用户下载的 dmg 仅 33.8MB。 已明确标注「口径调整,待确认」。附本机 Electron 运行时本体 207MB 的实测对照。 · 新增「Node 运行时分发」节:做法、三处实测约束(编译期契约 / strip 须重签 / 映射须对齐 resolve_node)、验证方式(verify-bundle 真跑产物)、实测体积。 · 「已知待办」由两条收敛为一条(剩 GUI 端到端人工验证,需图形环境)。 - CHANGELOG.md:新增 [未发布] 节,记录运行时分发功能与两处规避(SIGKILL 137、编译期契约)。 --- CHANGELOG.md | 25 ++++++++++++++++++ docs/console-plan.md | 60 ++++++++++++++++++++++++++++++++++++-------- 2 files changed, 75 insertions(+), 10 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index fb2dab3..8329f01 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -5,6 +5,31 @@ --- +## [未发布] + +### 新增 + +- **控制台自带 Node 运行时,目标机器无需预装 Node**(`pnpm --filter nodeagent-console bundle`) + —— 控制台的 sidecar 是 `.mjs`,此前只能在装了 Node 的机器上运行(`resolve_node` 回退系统 node)。 + 现由 `scripts/prepare-console.mjs` 把 Node 运行时准备为 Tauri resource 随包分发。 + 实测:`.app` **90.8 MiB**(含运行时 86MB)/`.dmg` **33.78 MiB**(分发件,仍低于 40MB 目标)。 + 作为对照,本机实测 Electron 运行时本体(`Electron Framework.framework`)为 207MB —— + 即 Tauri + Node 的运行时开销不到 Electron 的一半。 +- **`apps/console/scripts/verify-bundle.mjs`** —— 验证「打包产物能否自举」:真 spawn 打包内的 node + 去跑打包内的 sidecar,并走一次真实 JSON-RPC 握手。源码与单测都正常、只在产物中暴露的问题靠它拦下。 + +### 修复 / 规避(两处实测踩出来的约束) + +- **macOS 上 `strip` 会使 Mach-O 代码签名失效 → 内核直接 `SIGKILL`(exit 137)**, + 且没有任何有用报错(不是警告、不是异常,就是静默无法执行)。 + 实测对照:原样复制 ✓ / strip 不重签 ✗(137) / strip + `codesign --force --sign -` ✓。 + 故准备脚本在 strip 之后**必须** adhoc 重签(省 20% 体积值得,但这步不能少)。 +- **Node 运行时不得声明进默认 `tauri.conf.json`** —— `bundle.resources` 是**编译期契约** + (`tauri-build` 校验声明的文件必须存在),声明「运行期才就绪」的资源会让 `cargo check/test` + 在 build.rs 阶段直接失败。一律走 `tauri build --config` 注入。 + +--- + ## [v2.0.1] —— 2026-10-11 > 一轮**真机验证**(Parallels 27 + Win11 ARM)带来的修复批次:在补齐 6 项待验证项的过程中, diff --git a/docs/console-plan.md b/docs/console-plan.md index 6975137..0277dfc 100644 --- a/docs/console-plan.md +++ b/docs/console-plan.md @@ -224,9 +224,18 @@ nodeagent/ | 命令闭环成功率 | 成功返回 ÷ 发起 | ≥ 95% | | 内网调用 P95 时延 | 前端点击到结果渲染 | < 3s | | 应用内存占用 | Mac 版空闲常驻 RSS | < 150MB(远低于 Electron) | -| 打包体积 | 单端安装包 | Mac `.app` < 30MB / Win 安装包 < 40MB | +| 打包体积 | **用户实际下载的分发件** | Mac `.dmg` < 40MB(实测 **33.8MB** ✓)/Win 安装包 < 40MB(待实测) | | 双端编译 | `pnpm build` 一次产出两端 | 100% | +> **⚠️ 口径调整(2026-10-11,待确认)**:原指标写的是「Mac `.app` < 30MB / Win 安装包 < 40MB」。 +> 那条是 **Tauri + Rust client** 时代的数字 —— 当时应用内不含 JS 运行时。 +> 改为 Node sidecar 方案后,应用必须自带 Node 运行时(sidecar 是 `.mjs`,不能假定用户装了 Node), +> 故 `.app` 实测 **90.8 MiB**(其中 Node 运行时 86MB)。 +> **但用户下载的是 `.dmg`,实测 33.78 MiB** —— 仍低于原定 40MB。 +> 故本表口径改为「分发件体积」。作为对照:本机实测 Electron 运行时本体 +> (`Electron Framework.framework`)为 **207MB**,即 Tauri + Node 的运行时开销 +> 仍不到 Electron 的 **一半**(86MB vs 207MB)。 + --- ## 9. 里程碑拆分 @@ -414,16 +423,47 @@ Rust 侧从 resource 目录解析路径后 spawn(开发期直接用系统 node **真跑 Node 子进程**验证 spawn / 请求-响应匹配 / 错误不崩 —— 不必等到人工开窗口才敢确认。 `cargo test` 实测:**3/3 通过**(0.49s)。 -### ⚠️ 两处已知待办(本轮未做,均需真机/图形环境) +### Node 运行时分发(2026-10-11 完成) -1. **Node 运行时随包分发**:sidecar 是 `.mjs`,目标机器需有 Node。开发期用系统 node - (`resolve_node` 会回退到 PATH);**分发给他人时**需把 Node 运行时作为 resource 打进包。 - 计划:写 `scripts/prepare-console.mjs` 下载对应平台 node 到 `src-tauri/resources/`, - 并在打包时用 `tauri build --config` 注入 `bundle.resources` 的 node 项 - (**不能写死在默认 conf 里** —— `tauri-build` 会在编译期校验文件存在性, - 声明未下载的文件会让 `cargo check/test` 直接失败,本轮已踩并修复)。 -2. **GUI 端到端人工验证**:开窗口 → 连接被控端 → 操作界面。 - 沙箱无法运行图形应用,故本轮的验证止于 `cargo test`(真跑 sidecar)+ 单测/构建全绿。 +sidecar 是 `.mjs`(不是可执行文件,故**不满足 Tauri `externalBin` 的要求**), +分发给他人时须把 Node 运行时一并打进包。做法沿袭被控端 `scripts/pack.mjs` 的既有路子: +**把 Node 运行时当作 Tauri resource**。 + +``` +scripts/prepare-console.mjs ① 从本机 node 复制 → apps/console/src-tauri/runtime/node + ② macOS:strip -x(108MB→86MB)**并 adhoc 重签** + ③ 生成 apps/console/src-tauri/tauri.bundle.gen.json + { "bundle": { "resources": { + "../sidecar/dist/sidecar.mjs": "sidecar.mjs", + "runtime/node": "node" } } } +pnpm --filter nodeagent-console bundle + = sidecar:build → prepare:node → tauri build --config tauri.bundle.gen.json → verify:bundle +``` + +**三处必须记住的约束**(都是实测踩出来的): + +1. **绝不写进默认 `tauri.conf.json`** —— `bundle.resources` 是**编译期契约**, + `tauri-build` 会校验声明的每个文件必须存在;声明一个「运行期才准备好」的文件会让 + `cargo check/test` 直接失败(2026-10-10 已踩)。故一律走 `--config` 注入。 +2. **macOS 上 strip 之后必须 adhoc 重签** —— `strip` 会使 Mach-O 代码签名失效, + 而 macOS 内核对签名无效的可执行文件**直接 SIGKILL(exit 137)**,无任何有用报错。 + 实测对照:原样复制 ✓|strip 不重签 ✗(137)|strip + `codesign --force --sign -` ✓。 +3. **`resolve_node` 与 resource 映射必须对齐** —— 映射 `runtime/node → node` + 使产物落在 `Contents/Resources/node`,正是 `src-tauri/src/sidecar.rs` 里 + `resolve_node(resource_dir)` 查找的路径。 + +**验证(不只看「打包成功」)**:`apps/console/scripts/verify-bundle.mjs` 真 spawn 打包内的 +node 去跑打包内的 sidecar,并走一次真实 JSON-RPC 握手 —— 源码与单测都正常、 +只在产物中暴露的问题(如上述 137)靠它拦下。已接入 CI(Linux 与 Windows 双覆盖)。 + +**实测体积**:`.app` **90.8 MiB**(6.75 MiB → 90.8 MiB,增量即 Node 运行时 86MB)/ +`.dmg` **33.78 MiB**(分发件,仍 < 40MB 目标)。 + +### ⚠️ 剩余一处已知待办(需图形环境) + +**GUI 端到端人工验证**:开窗口 → 连接被控端 → 操作界面。 +沙箱无法运行图形应用,故验证止于 `cargo test`(真跑 sidecar)+ `verify:bundle`(真跑产物) ++ 应用进程可启动(实测存活、无崩溃输出)。**界面交互仍需在图形环境点一遍。** ### 一个易踩的构建约束(本轮 CI 失败后查明)