Exe builder binary 与 executable binary 模型

为什么要区分两个 binary

experiments.exe 基于 Node SEA。生成可执行程序时有两个角色:

角色含义
builder binary在当前机器上执行 --build-sea 的 Node
executable binary最终被注入 SEA blob 的目标 Node 模板

这两个 binary 可能是同一个,也可能不同。

如果目标平台、架构、Node 版本都等于当前运行时,直接用 process.execPath 即可。

如果目标是另一个平台或版本,就需要下载目标 binary,同时还要确保 builder binary 能在当前机器运行。

为什么版本必须一致

Node SEA 要求生成 blob 和注入模板使用兼容的 Node 版本。Rslib 会确保 builder binary 和 executable binary 的 Node 版本一致。

如果用户传 custom binary,Rslib 还会读取它的版本,并选择同版本的当前平台 builder binary。

Cross target 为什么禁用 snapshot/code cache

useSnapshotuseCodeCache 与宿主运行时强绑定。跨平台或跨架构生成时,当前机器生成的 snapshot/code cache 不能安全用于目标平台。

因此 Rslib 在 cross target 时自动设置:

useCodeCache: false;
useSnapshot: false;

这不是功能缺失,而是避免生成看似成功但不可运行的二进制。

下载流程

当需要下载 Node binary 时,Rslib 会:

  1. 构造 Node release archive 名称。
  2. 下载 SHASUMS256.txt
  3. 找到目标 archive 的 checksum。
  4. 下载 archive。
  5. 校验 sha256。
  6. 解压 archive。
  7. chmod 可执行文件。
  8. 缓存路径供后续复用。

inFlightBinaryDownloads 避免并发重复下载同一个 archive。

custom binary

用户可以把 target 写成字符串路径:

experiments: {
  exe: {
    targets: ['./node-custom'],
  },
}

这表示 executable binary 使用用户提供的模板。但 --build-sea 仍必须由当前平台可执行的 Node 运行。如果 custom binary 版本不同于当前 Node,Rslib 会下载同版本的当前平台 Node 作为 builder。

输出路径

多 target 时,Rslib 会给 target 加 suffix:

darwin-arm64-v25.7.0
linux-x64-v25.7.0

这样避免多个 target 输出互相覆盖。

Windows 还要处理 .exe 后缀。

构建流程

buildExecutable 会创建临时目录,写:

{
  "main": "dist/index.js",
  "mainFormat": "module",
  "output": "dist/my-cli",
  "executable": "/path/to/node",
  "disableExperimentalSEAWarning": true
}

然后运行:

node --build-sea sea-config.json

macOS 下会尝试签名。最后清理临时目录。

修改风险

Exe binary 模型改动要检查:

  • 当前平台默认 target。
  • 指定 nodeVersion。
  • custom binary。
  • cross platform。
  • 多 target suffix。
  • checksum mismatch。
  • macOS 签名。
  • Windows .exe

这类问题通常很慢,适合放在 integration-exe 单独项目。