mcpField
E
electron-node-upgrade

electron-node-upgrade

github.com/electron开发123.6k55 次安装今天更新
代码仓库

关于 electron-node-upgrade

这项 skill 指导 Electron 维护者升级 Node.js 依赖,涵盖补丁同步、构建和测试。它按阶段说明冲突处理及验证要求。

主要功能

  1. 01三阶段升级工作流
  2. 02补丁冲突处理指引
  3. 03构建与启动验证
  4. 04Node.js 测试套件指引
  5. 05补丁导出与提交规则

适用场景

  1. 01在 Electron 中升级 Node.js 版本
  2. 02解决 Node.js 补丁冲突
  3. 03适配 Node.js API 变更
  4. 04升级后检查构建和测试

安装

复制下面的命令,在终端中运行。

$npx skills add https://github.com/electron/electron --skill electron-node-upgrade

安装后在 Claude Code 中输入/electron-node-upgrade确认已加载。

包含的文件

除 SKILL.md 外,安装时一起下载的参考资料和脚本。

references/
patch-analysis.md
phase-one-commit-guidelines.md
phase-three-commit-guidelines.md
phase-two-commit-guidelines.md

详细介绍

Electron Node.js 升级:第一阶段

摘要

反复运行 e sync --3,并在出现补丁冲突时修复,直到命令成功。然后导出补丁,并以原子方式提交更改。

成功标准

满足以下条件时,第一阶段即告完成:

  • e sync --3 以代码 0 退出(没有补丁失败)
  • 按照提交指南提交所有更改

在满足这些条件之前,不要停止。

重要 除非百分之百确定某个补丁已不再需要,否则不要删除或跳过它。对于大版本升级,修补已弃用 V8 API 的补丁或回移上游更改的补丁通常可以删除,因为新版 Node.js 可能已包含这些更改,但删除前请务必确认。复杂冲突或难以解决的问题,应在穷尽其他所有选项后再提交给用户。不要仅仅因为无法解决就删除补丁。

重要 切勿使用 git am --skip,然后通过创建新提交手动重建补丁。这样会破坏原补丁的作者信息、提交消息以及在补丁序列中的位置。如果 git am --continue 报告“No changes”,请调查原因——这些更改可能已被之前冲突解决时的三方合并吸收。应将这种情况提交给用户处理,而不是跳过并重建补丁。

背景

roller/node/main 分支由自动化创建,用于更新 DEPS 中 Electron 的 Node.js 依赖版本。尚未进行任何工作来处理新旧版本之间的破坏性更改。

Node.js 版本更新有两种类型:

  • 升级(补丁版/次版本):由 electron-roller[bot] 自动执行,提交标题为 chore: bump node to v{version}。简单的补丁索引更新由 patchup[bot] 自动处理。这类更新通常可以顺利应用,但有时需要手动修复补丁。
  • 大版本升级(例如 v22 → v24):手动进行的大型 PR,提交标题为 chore: upgrade Node.js to v{X}.{Y}.{Z}。这类升级通常需要删除过时补丁、调整许多其他补丁,并更新 package.json 中的 @types/node。

关键目录:

  • 当前目录:Electron 仓库(始终在此处运行 e 命令)
  • ../third_party/electron_node:Node.js 仓库(补丁应用于此处)
  • patches/node/:Node.js 补丁文件
  • docs/development/patches.md:补丁系统文档

预检

在每次升级会话开始时运行以下检查:

  1. 清除 rerere 缓存(如果已启用):在 Electron 仓库和 ../third_party/electron_node 仓库中都运行 git rerere clear。之前尝试时记录的旧解决方案可能会悄悄应用错误的合并结果。
  2. 确保已安装 pre-commit 钩子:检查 .git/hooks/pre-commit 是否存在。如果不存在,运行 yarn husky 进行安装。该钩子会运行 lint-staged,为 C++ 文件处理 clang-format。
  3. 查找其他分支上相同的升级:获取 roller/node/main,以及任何针对相同 Node.js 版本的同级 roller/node/{N}-x-y 分支。如果这些分支已包含修复,请原样复用(补丁名称、内容、提交标题、Ref: 行),不要重新推导。请参阅 references/phase-one-commit-guidelines.md 中的“Reuse Fixes From Sibling Roller Branches”。

工作流

  1. 运行 e sync --3(--3 标志启用三方合并,始终必需)
  2. 如果成功 → 跳至第 5 步
  3. 如果补丁失败:
    • 根据错误输出确定目标仓库和补丁
    • 分析失败原因(请参阅 references/patch-analysis.md)
    • 在 ../third_party/electron_node 工作目录中修复冲突
    • 在 ../third_party/electron_node 中运行 git am --continue
    • 重复以上步骤,直到该仓库的所有补丁都应用成功
    • 重要:git am --continue 成功后,必须运行 e patches node 导出修复
    • 返回第 1 步
  4. e sync --3 成功后,运行 e patches all
  5. **现在阅读 references/phase-one-commit-guidelines.md,**然后严格按照其中的说明提交更改。

命令参考

命令用途
e sync --3克隆依赖项并通过三方合并应用补丁
git am --continue解决冲突后继续(在 node 仓库中运行)
e patches node将 node 仓库中的提交导出为补丁文件
e patches all从所有目标导出全部补丁
e patches node --commit-updates导出补丁并自动提交简单更改
e patches --list-targets列出目标和配置路径

补丁系统心智模型

patches/node/*.patch  →  [e sync --3]  →  ../third_party/electron_node commits
                      ←  [e patches]   ←

何时编辑补丁

情况操作
正在处理 git am 冲突在 node 仓库中修复,然后运行 git am --continue
在冲突之外修改补丁直接编辑 .patch 文件
创建新补丁(少见,应避免)在 node 仓库中提交,然后运行 e patches node

99% 的情况下都应修复现有补丁,而不是创建新补丁。

补丁修复规则

  1. 保留作者信息:在 TODO 注释中保留原始作者(取自补丁的 From: 字段)
  2. 绝不更改 TODO 负责人:TODO(name) 必须保留原始名称
  3. 更新描述:如果上游更改了 API 或宏,请更新补丁提交说明以反映当前状态
  4. 绝不跳过并重新创建补丁:如果 git am --continue 提示“No changes — did you forget to use 'git add'?”,不要运行 git am --skip 并创建替代提交。该补丁的更改已通过先前的三方合并冲突解决纳入代码。这意味着较早的冲突解决纳入了过多更改。请向用户说明情况并寻求指导——正确的修复方式可能需要更仔细地重新处理先前的冲突解决,以确保每个补丁的更改彼此分离。

Electron Node.js 升级:第二阶段

概述

反复运行 e build -k 999 -- --quiet,出现构建问题时逐一修复,直到构建成功。然后运行 e start --version,验证 Electron 能否启动,并以原子方式提交更改。

第一阶段完成后立即运行第二阶段。

成功标准

满足以下条件即表示第二阶段完成:

  • e build -k 999 -- --quiet 以代码 0 退出(没有构建失败)
  • 已运行 e start --version,检查 Electron 能否启动
  • 已按照提交指南提交所有更改

在满足这些条件之前不要停止。不要删除代码或功能,也绝不要为了走捷径而注释掉代码。要让所有现有代码、逻辑和意图都正常运行。

背景

自动化创建了 roller/node/main 分支,用于更新 DEPS 中 Electron 的 Node.js 依赖版本。没有进行任何工作来处理新旧版本之间的破坏性变更。Node.js API(尤其是内部 V8 集成、OpenSSL/BoringSSL 兼容性以及构建系统文件)在不同版本之间经常发生变化。无论遇到何种情况,都必须更新 Electron 中的代码以适配 Node.js 的变更;应尽量避免修改 Node.js 代码来修复 Electron 的构建。

关键目录:

  • 当前目录:Electron 仓库(始终在此处运行 e 命令)
  • ../third_party/electron_node:Node.js 仓库(不要修改其中的代码来修复构建问题,只需阅读以了解背景)

工作流

  1. 运行 e build -k 999 -- --quiet(--quiet 标志会隐藏每个目标的状态行,只显示错误和最终结果)
  2. 如果成功 → 跳到第 6 步
  3. 如果构建失败:
    • 根据编译错误消息确定 "electron" 中的底层文件
    • 分析失败原因
    • 调整 Electron 代码以适配 Node.js 中的更改,修复构建问题
    • 运行 e build -t {target_that_failed}.o,仅构建我们要修复的失败目标
      • 可从构建日志中的失败行识别 target_that_failed。例如,FAILED: 2e506007-8d5d-4f38-bdd1-b5cd77999a77 "./obj/electron/shell/browser/api/electron_api_utility_process.o" CXX obj/electron/shell/browser/api/electron_api_utility_process.o 中的目标名称是 obj/electron/shell/browser/api/electron_api_utility_process.o
    • 现在阅读 references/phase-two-commit-guidelines.md,然后严格按照其中的说明提交更改。
    • 返回第 1 步
  4. 重要:每次提交后(尤其是补丁提交后),立即在 electron 仓库中运行 git status
    • 查找其他仅修改了索引/区块标题的 .patch 文件
    • 这些是受你修复影响的依赖补丁。立即运行以下命令提交它们:git commit -am "chore: update patches (trivial only)"
  5. 返回第 1 步
  6. 当 e build 成功后,运行 e start --version
  7. 在 ../third_party/electron_node 中运行 git status,检查 Node.js 仓库是否有待处理的更改
    • 如果有更改,请按照下文“A. 补丁修复”中的说明,将这些修改正确提交到相应的补丁文件中

命令参考

命令用途
e build -k 999 -- --quiet构建 Electron,遇到错误时继续,并隐藏状态行
e build -t {target}.o仅构建一个指定目标以验证修复
e start --version验证 Electron 在构建成功后能否启动

两种构建修复类型

A. 补丁修复(针对经过补丁修改的 Node.js 文件)

当错误发生在 Electron 会打补丁的文件中时(使用 grep -l "filename" patches/node/*.patch 检查):

  1. 在 Node.js 源代码树中编辑文件(../third_party/electron_node/...)
  2. 创建一个修复提交,目标为原始补丁提交:
    cd ../third_party/electron_node
    git add <modified-file>
    git commit --fixup=<original-patch-commit-hash>
    GIT_SEQUENCE_EDITOR=: git rebase --autosquash --autostash -i <commit>^
    
  3. 导出更新后的补丁:e patches node
  4. 按照 references/phase-one-commit-guidelines.md 中的说明提交更新后的补丁文件。

查找要修复的原始补丁提交:git log --oneline | grep -i "keyword from patch name"

变基的基准提交是应用补丁前的 Node.js 提交。通过检查 refs/patches/upstream-head 引用来查找。

B. Electron 代码修复(针对 shell/、electron/ 等目录中的文件)

当错误发生在 Electron 自有源代码中时:

  1. 直接在 electron 仓库中编辑文件
  2. 直接提交(无需导出补丁)

Electron Node.js 升级:第三阶段

概述

通过 script/node-spec-runner.js 运行 Node.js 测试套件,修复失败的测试,并持续提交修复,直到所有测试通过。某些测试已永久禁用(列在 script/node-disabled-tests.json 中),不应运行。

第二阶段完成后,立即运行第三阶段。

成功标准

满足以下条件时,第三阶段即告完成:

  • node script/node-spec-runner.js --default 运行后失败数为 0
  • 所有更改均已按照提交指南提交

在满足这些条件之前,不要停止。

上下文

Electron 使用自定义运行器(script/node-spec-runner.js)运行 Node.js 上游测试套件的一个子集。测试通过 ELECTRON_RUN_AS_NODE=true 使用 Electron 构建的二进制文件执行。由于 Electron 使用 BoringSSL(而不是 OpenSSL)和 Chromium 的 V8(可能与 Node.js 捆绑的 V8 不同),许多测试需要调整。

关键文件:

  • script/node-spec-runner.js — 测试运行器脚本
  • script/node-disabled-tests.json — 永久禁用的测试(不要尝试修复这些测试)
  • ../third_party/electron_node/test/ — Node.js 测试文件(补丁应用于此处)
  • patches/node/fix_crypto_tests_to_run_with_bssl.patch — BoringSSL 加密测试适配
  • patches/node/test_formally_mark_some_tests_as_flaky.patch — 不稳定测试列表

工作流

  1. 在 electron 仓库中运行 node script/node-spec-runner.js --default
  2. 如果所有测试均通过 → 第三阶段完成
  3. 如果测试失败:
    • 根据输出找出失败的测试文件
    • 分析每个失败项(请参见下方的“常见失败模式”)
    • 在 ../third_party/electron_node/test/... 中修复测试
    • 重新运行特定的失败测试以验证:node script/node-spec-runner.js {test-path}
      • 测试路径相对于 node 的 test/ 目录,例如 test/parallel/test-crypto-key-objects-raw.js
      • 运行特定测试时不要使用 --default — 它会添加完整测试套件的标志
      • 不要直接使用 ELECTRON_RUN_AS_NODE 运行测试 — 运行器会处理环境设置(例如,临时将 package.json 从 ESM 切换为 CommonJS)
    • 使用 fixup 工作流和提交指南提交修复
    • 返回步骤 1

命令参考

命令用途
node script/node-spec-runner.js --default运行完整的 Node.js 测试套件
node script/node-spec-runner.js test/parallel/test-foo.js运行单个测试
NODE_REGENERATE_SNAPSHOTS=1 node script/node-spec-runner.js test/test-runner/test-foo.mjs为基于快照的测试重新生成快照

常见失败模式

BoringSSL 不兼容问题

Electron 使用 Chromium 的 BoringSSL 构建 Node.js,而不是使用 Node.js 随附的 OpenSSL。从 v24.18.0 的版本更新起,这一设置通过 GN 参数启用,而不再依赖大量源码补丁:

# build/args/all.gn
# Build Node.js against Chromium's BoringSSL instead of node's bundled OpenSSL.
node_openssl_path = "//third_party/boringssl"

上游 Node.js 现已原生支持使用 BoringSSL 构建(参见 nodejs/node 提交 677ca7e76c9 和 61b20f60a39),因此 Electron 过去的大部分 BoringSSL 变通方案都已移除。在 v24.18.0 的版本更新期间:

  • fix_crypto_tests_to_run_with_bssl.patch 从约 1100 行缩减为仅跳过两个测试文件。
  • fix_handle_boringssl_and_openssl_incompatibilities.patch 删除了约 176 行。剩余内容是在 deps/ncrypto/ncrypto.cc、src/crypto/crypto_{common,context,hash}.cc、src/env.h、src/node_metadata.h 和 src/node_options.h 中的 C++ 层兼容处理。

请逐步删除这些变通方案,而不要继续增加。只有在某项功能确实仍不受 BoringSSL 支持时,才添加保护条件;上游测试越来越多地在设置了 process.features.openssl_is_boringssl 时自动跳过,因此无需修改 Electron。

仍不受支持的功能的首选保护方式——在文件顶部跳过整个测试文件,并将其添加到 fix_crypto_tests_to_run_with_bssl.patch 中:

if (process.features.openssl_is_boringssl) {
  common.skip('Skipping unsupported ML-DSA key tests');
}

对于无法通过行内代码妥善添加保护条件的测试,请改为将整个文件添加到 script/node-disabled-tests.json 中。

Chromium 的 BoringSSL 仍不支持的功能(截至 v24.18.0):

功能当前处理方式
RSA-PSS 密钥生成(弃用路径)在 test-crypto-keygen-deprecation 中通过文件级 common.skip 跳过
ML-DSA 密钥在 test-crypto-pqc-key-objects-ml-dsa 中通过文件级 common.skip 跳过
ML-KEM 密钥在 node-disabled-tests.json 中禁用(test-crypto-pqc-key-objects-ml-kem)
FIPS 模式已禁用(test-crypto-fips)
安全堆已禁用(test-crypto-secure-heap)
无状态 DH已禁用(test-crypto-dh-stateless)
其他密钥生成 / WebCrypto 密钥生成已禁用(test-crypto-keygen、test-webcrypto-keygen、wpt/test-webcrypto)

行为差异(更新断言,而非跳过)——有些错误的形式发生了变化:

  • 从不受支持的 OKP(Ed448)JWK 创建私钥时,现在会抛出 Invalid JWK OKP key(此前为 Invalid JWK data);参见 nodejs/node#62499。Electron 的 spec/node.spec.ts 断言已放宽为 /Invalid JWK/。

确实需要为测试添加保护条件时,如果可以直接探测功能,请优先使用精确的功能检查(例如 ciphers.includes('aes-128-ccm')),而不是笼统地检查 process.features.openssl_is_boringssl。

快照测试不匹配

有些测试使用 assert.strictEqual 将输出与已提交的 .snapshot 文件进行比较——这不是通配符比较。当 Chromium 的 V8 产生不同输出时(例如 V8 增强导致堆栈跟踪不同),必须重新生成快照:

NODE_REGENERATE_SNAPSHOTS=1 node script/node-spec-runner.js test/test-runner/test-foo.mjs

然后检查差异,确认更改符合预期,并将更新后的快照提交到相应补丁中。

V8 行为差异

Chromium 的 V8 可能比 Node.js 随附的 V8 更新。这可能导致:

  • 堆栈跟踪格式不同(例如 thenable 异步堆栈帧)
  • 错误消息不同
  • Chromium V8 中提供了 stock Node.js V8 不具备的功能(反之亦然)

两种测试修复类型

A. 修复补丁(测试失败时最常见)

大多数测试修复都应添加到 patches/node/ 中的现有补丁。请使用 fixup 工作流:

  1. 编辑 ../third_party/electron_node/test/... 中的测试文件
  2. 找到相关的补丁提交:git log --oneline | grep -i "keyword"
    • Crypto/BoringSSL 测试 → fix crypto tests to run with bssl
    • 快照测试 → 对应的快照补丁(例如 test: accomodate V8 thenable)
    • 不稳定测试 → test: formally mark some tests as flaky
  3. 创建 fixup 提交:
    cd ../third_party/electron_node
    git add test/path/to/test.js
    git commit --fixup=<patch-commit-hash>
    GIT_SEQUENCE_EDITOR=: git rebase --autosquash --autostash -i <commit>^
    
  4. 导出:e patches node
  5. 现在阅读 references/phase-three-commit-guidelines.md,然后提交更新后的补丁文件。
B. 新建补丁(少见)

只有在修复内容不适用于任何现有补丁时,才创建新补丁。../third_party/electron_node 中的新补丁提交必须包含说明,解释补丁存在的原因以及何时可以移除——lint 检查会强制执行这一要求。

添加到禁用测试列表

只有在万不得已时,才将测试添加到 script/node-disabled-tests.json——也就是测试在架构层面与 Electron 根本不兼容时(而不只是可以通过添加保护来处理的 BoringSSL 差异)。此处禁用的测试会被完全跳过,永远不会运行。

关键:提交前阅读

  • 在进行任何 Phase One 提交前:阅读 references/phase-one-commit-guidelines.md
  • 在进行任何 Phase Two 提交前:阅读 references/phase-two-commit-guidelines.md
  • 在进行任何 Phase Three 提交前:阅读 references/phase-three-commit-guidelines.md

高变更量补丁

在 Node.js 升级期间,这些补丁通常需要投入最多工作:

  • fix_handle_boringssl_and_openssl_incompatibilities.patch — Electron 使用 BoringSSL(通过 Chromium),而 Node.js 需要 OpenSSL。这个补丁过去规模庞大且复杂;Node.js 原生支持 BoringSSL 后(通过 build/args/all.gn 中的 node_openssl_path = "//third_party/boringssl" 启用),补丁已大幅缩减。它仍会为一些 C++ 层面的差异提供适配,而上游 OpenSSL/ncrypto API 的变更也可能导致其失效。
  • fix_crypto_tests_to_run_with_bssl.patch — 配套补丁,用于适配 Node.js 的 Crypto 测试,使其能够在 BoringSSL 下运行。由于上游测试现在会在 BoringSSL 下自行跳过,该补丁也已大幅缩减——目前主要跳过少数仍不受支持的测试文件。请参阅上文“BoringSSL incompatibilities”部分。
  • support_v8_sandboxed_pointers.patch — 当 V8 API 变更时,支持 V8 沙箱指针需要谨慎适配。
  • build_add_gn_build_files.patch — GN 构建文件补丁规模较大,会涉及许多构建目标。上游构建系统的变更经常会与其冲突。

主版本升级

Node.js 主版本迁移(例如 v22 → v24)远比补丁版本升级复杂:

  1. 预计会删除补丁。 Electron 使用 Chromium 的 V8,其版本通常领先于 Node.js 内置的 V8。许多补丁用于弥合这一差距——为较新的 V8 API 提供适配,而 Chromium 的 V8 中有这些 API,Node.js 较旧的 V8 中却没有。当 Node.js 升级到较新的主版本时,其 V8 会追上 Chromium 的版本,因此可以删除这些桥接补丁。v22 → v24 升级中,就因此删除了 17 个补丁。
  2. 在 package.json 中更新 @types/node,使其与新的主版本匹配。
  3. 升级后出现回归是预料之中的。 即使升级已完成,针对边缘情况(ESM 路径处理、证书加载、平台特定问题)的后续修复 PR 也很常见。

技能目录结构

此技能在 references/ 中还包含其他参考文件:

  • patch-analysis.md - 如何分析补丁失败
  • phase-one-commit-guidelines.md - 第一阶段的提交格式
  • phase-two-commit-guidelines.md - 第二阶段的提交格式
  • phase-three-commit-guidelines.md - 第三阶段的提交格式

在工作流步骤中引用这些文件时,请阅读它们。

评论

支持 Markdown