你以为 Node.js 26 升级只是改个版本号?10 月 28 日进 LTS 前,writeHeader 已删、_stream_* 没了、ABI 变 147——这 5 处别漏
Node.js 26 是 5 月 5 日发布的 Current 版本,10 月 28 日就要转入 Active LTS——升级窗口只剩两周多。这一版的删除和运行时报警不是走过场:response.writeHeader() 直接删了,_stream_* 六个遗留模块整体退场,module.register() 从文档弃用升级成运行时报警,原生模块 ABI 从 146 变成 147 必须重编。只改个 engines 字段就升,控制台当天就给你颜色看。升级前先扫下面这 5 处。
第一处:两个 API 已经删了,调用即抛错
最典型的是 writeHeader——它其实是 writeHead() 的拼写错误版本,26 之前只是没人用,26 直接删进了 SEMVER-MAJOR 清单(#60635):
// 旧写法(Node 24 还能跑,Node 26 直接 TypeError)
const server = http.createServer((req, res) => {
res.writeHeader(200, { 'Content-Type': 'text/plain' }); // 已移除
res.end('hello');
});
// 新写法
res.writeHead(200, { 'Content-Type': 'text/plain' });
第二处是 _stream_* 遗留模块(#60657):_stream_readable、_stream_writable、_stream_duplex、_stream_transform、_stream_passthrough、_stream_wrap 六个入口全部移除。早期基于 streams1 时代手写的库会 require('stream/_stream_readable'),升级后这些 require 路径直接 MODULE_NOT_FOUND:
// 旧写法:第三方库里的历史代码
const { Readable } = require('stream/_stream_readable'); // Node 26: MODULE_NOT_FOUND
// 新写法:统一从 node:stream 导入
const { Readable } = require('node:stream');
另外 --experimental-transform-types 标志也删了(#61803)——用它编译 TS 枚举和命名空间的 CI 脚本要改回 tsc 或交给打包器。
第三处:能跑,但控制台开始报警的三类
删掉的还好查,真正麻烦的是「从文档弃用升级为运行时弃用」的那批——代码不报错,但每次执行打印 DeprecationWarning,日志告警会慢慢变多:
module.register()(#62401):注册自定义 ESM 加载器的老 API,26 起运行时报警。官方迁移方向是同步模块钩子机制,依赖--import+module.register()挂 loader 的工具链(如老版本的 ts-node loader、自定义 mock 框架)要评估切换。- crypto DEP0203 / DEP0204(#62453):短 GCM tag 必须显式传
authTagLength,不再默认兜底。 - stream DEP0201(#62173):旧流 API 调用点开始报警。
先用 -e 跑一次冒烟,就能看到全部报警:
NODE_OPTIONS='--throw-deprecation' npm test
# 有任何废弃调用直接抛出,CI 里先暴露,别等生产日志刷屏
第四处:原生模块 ABI 变 147,全部要重编
bcrypt、sharp、sqlite3 这类原生 addon 的 NODE_MODULE_VERSION 在 26 里是 147(24 是 146)。装完不重编,运行时报 NODE_MODULE_VERSION does not match。升级当天的标准动作:
rm -rf node_modules package-lock.json
npm ci # 或 npm rebuild 触发 node-gyp 重编
自己从源码编 Node 的团队还有两道门槛:GCC 要求从 12 提到 13.2,Python 3.9 支持被移除(#62555)。
第五处:Undici 8 换了 fetch 的底座
Node 内置 fetch() 背后的 Undici 升到 8.0.2(#61898)。如果你的集成测试直接打支付网关、CRM 或 AI API,Major 版本的边界行为可能有变化——升级后第一件事是把所有走 fetch() 的集成测试重跑一遍,而不是只跑单测。
升级前的五处检查清单
| 检查项 | 类型 | 动作 |
|---|---|---|
writeHeader 调用 |
已删除 | 全局搜 writeHeader(,替换为 writeHead( |
stream/_stream_* require |
已删除 | 换成 node:stream |
--experimental-transform-types |
已删除 | CI 脚本改用 tsc |
module.register() / crypto 短 GCM / 旧流 API |
运行时报警 | --throw-deprecation 跑测试收集 |
| 原生模块 + fetch 集成测试 | ABI/依赖 | 重装重编 + 重跑集成测试 |
三步落地
- 本周先扫:在当前版本上跑
NODE_OPTIONS='--throw-deprecation' npm test,并全局搜索writeHeader(、require('stream/_stream、--experimental-transform-types三个模式,把命中项记进清单——这三类是 26 直接删的,留到升级当天再改就是线上事故。 - 10 月 28 日 LTS 前两周切到预发:用 26.x 镜像重建预发环境,
rm -rf node_modules && npm ci强制重编原生模块,重点回归 fetch 集成测试(Undici 8)和依赖module.register()的工具链。 - LTS 当周再上生产:Node 26 进 LTS 后有 30 个月维护期(总支持 36 个月),不需要抢 Current 阶段冒险——预发过了再动生产,失败也可以随时回 24(它的维护期到 2028 年 4 月)。
参考来源:nodejs.org v26.0.0 发布说明(2026-05-05)、Node.js Release Working Group 进度表(LTS 2026-10-28)、社区升级清单(2026-10-05/10-06)。
评论区
登录后可评论。