Node.js 18.19.0 "Hydrogen" LTS 发布全解析:npm 10 回溯、ESM 定制钩子体系重构与测试运行器增强
【免费下载链接】nodejs.orgThe Node.js® Website项目地址: https://gitcode.com/GitHub_Trending/no/nodejs.org
2023 年 11 月 29 日,Node.js 发布了 18.x 主线上的重要 LTS 版本18.19.0 "Hydrogen"(由 Michaël Zasso 以@targos名义发布)。这是 Node.js 18 生命周期中一次"承前启后"的里程碑:它首次将npm 10回溯到 18 号线,让所有仍在维护的发布线都拥有受支持的 npm 版本;同时把 Node.js 20 中沉淀下来的ESM 模块定制钩子体系(registerAPI、initialize钩子、import.meta.resolve去实验化、--experimental-default-type标志)整体回迁,并大幅增强了内置测试运行器的能力。
本文以 nodejs.org 官网仓库中的 v18.19.0 发布说明 为骨架,结合该仓库对发布博客的解析与版本数据生成逻辑,逐项拆解本次发布的 Notable Changes、ESM 钩子迁移路径、测试运行器新特性、下载与校验和验证方法,帮助你评估是否升级、如何平滑迁移。
版本背景:为何 18.19.0 值得关注
先看发布说明的元信息:
date: '2023-11-29T17:28:42.041Z' category: release title: Node.js 18.19.0 (LTS) layout: blog-post author: Michaël Zasso在 nodejs.org 仓库中,这类发布说明统一存放在apps/site/pages/en/blog/release/目录下(截至本文写作时该目录包含自 v0.10.0 以来的数百篇发布博客,见 apps/site/pages/en/blog/release)。每一篇的category: releasefrontmatter 决定了它的归档分类与 URL。仓库通过 scripts/blog-data/generate.mjs 流式读取这些文件的 frontmatter:
- 以
category字段(缺省为uncategorized)和发布年份共同组成分类集合[category, year-<年份>, all]; - 依据
category + 文件名生成博客 slug,即/blog/release/v18.19.0; - 前端再通过 util/blog.ts 中的
mapBlogCategoryToPreviewType将release类别映射为发布预览卡片类型,在博客列表与首页聚合展示。
也就是说,你在官网上看到的这篇发布公告,其内容骨架正是本文将要展开的这份文档。
本次版本的主要亮点可归纳为四条主线:npm 10 回溯、ESM 与定制钩子(customization hooks)体系变更、测试运行器(test_runner)增强、以及一批SEMVER-MINOR 级的 API/依赖更新。
npm 升级到 v10:全发布线统一支持
After two months of baking time in Node.js 20, npm 10 is backported, so that all release lines include a supported version of npm. This release includes npm v10.2.3.
发布说明明确指出:npm 10 已在 Node.js 20 中"烘烤"(baking)两个月,本次将其回溯(backport)到 18 号线,使得所有仍在维护的发布线都包含受支持的 npm 版本。本次随附的 npm 具体版本为10.2.3。
从版本数据生成器 next-data/generators/releaseData.mjs 可以看到,每个主版本的latestVersion.dependencies.npm会被抽取出来,用于官网下载页展示各版本线对应的 npm 版本;对应的数据结构定义在 types/releases.ts(MinorVersion中的npm?: string字段)。这意味着升级到 18.19.0 后,npm -v将直接得到 10.2.x 的新体验,包括 npm 10 引入的安装输出、overrides行为以及lockfileVersion处理上的变化。
需要留意的是,npm 10 要求 Node.js 满足其自身引擎约束,因此在 18.19.0 上运行 npm 10 属于官方设计内的组合;若你的 CI 或生产环境对 npm 版本有严格锁定(如通过corepack或packageManager字段固定),升级前应先在目标环境中验证npm install与锁文件的兼容性。
ESM 与模块定制钩子(customization hooks)变更
这一节是本次发布说明中篇幅最大、技术含量最高的部分,涉及四项核心变更,全部来自 Node.js 20 的沉淀回迁。
1. Loaders 现在会作用于后续的 loader
Loaders now apply to subsequent loaders, for example:
--experimental-loader ts-node --experimental-loader loader-written-in-typescript.
在此之前,通过--experimental-loader链式加载多个 loader 时,后续 loader 的加载过程不会经过前面 loader 的解析流程,导致"用 TypeScript 写的 loader 无法被 ts-node 这类 loader 加载"。本次修复后,loader 解析是**级联(cascade)**的:
node --experimental-loader ts-node --experimental-loader loader-written-in-typescript ./app.js即第二个 loader(loader-written-in-typescript)会先经过第一个 loader(ts-node)的转换再被执行。这一点对 ts-node、tsx 等工具链的 loader 组合使用场景非常关键。该改动由 Maël Nison 贡献(PR #43772)。
2. 新增node:module的registerAPI 与initialize钩子
There is a new API
registeravailable onnode:moduleto specify a file that exports module customization hooks, and pass data to the hooks, and establish communication channels with them.
这是本次 ESM 变更中影响最深远的架构调整:
- 此前,指定定制钩子文件只能通过命令行标志
--experimental-loader完成; - 自 Node.js 20.0.0 起,钩子被移入独立的线程(hooks thread)执行,因此需要一个在主线程与钩子线程之间建立通信通道的方式;
- 新的
registerAPI 允许从主线程调用,指定导出模块定制钩子的文件、向钩子传递数据,并可通过传递MessageChannel实例建立双向通信。
官方推荐的新式用法是结合--import使用register:
node --import ./file-that-calls-register.js ./app.js其中file-that-calls-register.js内部调用register来装载钩子。使用--import可以保证定制钩子在任何应用代码(包括入口文件本身)运行之前注册完毕。这一迁移路径的核心价值在于:--experimental-loader只解决"指定钩子文件"的问题,而无法在应用启动早期与运行在独立线程中的钩子建立通信;register则补全了这一点。
该 API 由多个 PR 协作完成(#46826、#48842、#48559),并配套实现了新的initialize钩子(#48842),用于在钩子线程启动时执行初始化逻辑、接收主线程通过register传入的数据。发布说明还提示,自定义 loader 场景下import.meta.resolve存在一些限制(相关文档改动见 #49242)。
3.import.meta.resolve取消实验标志
In ES modules,
import.meta.resolve(specifier)can be used to get an absolute URL string to whichspecifierresolves, similar torequire.resolvein CommonJS.
在 ES 模块中,import.meta.resolve(specifier)现在可以直接使用而无需任何实验标志,它返回specifier解析后的绝对 URL 字符串,功能上对标 CommonJS 的require.resolve。这一变化让 Node.js 在模块解析能力上与浏览器及其他服务端运行时保持一致,是 ESM 生态走向成熟的重要标志(由 Guy Bedford 贡献,PR #49028)。
一个直观的对比:
// CommonJS require.resolve('node:fs'); // 得到绝对路径/URL 字符串 // ES Modules(18.19.0 起无需 flag) import.meta.resolve('node:fs'); // 得到 file:///.../fs.mjs 形式的绝对 URL4. 新增--experimental-default-type标志:翻转模块默认类型
The new flag
--experimental-default-typecan be used to flip the default module system used by Node.js.
--experimental-default-type允许翻转 Node.js 默认采用的模块系统。显式声明为 ESM 或 CommonJS 的输入不受影响,这些显式声明包括:
package.json中的"type"字段;.mjs/.cjs文件扩展名;--input-type标志。
而在--experimental-default-type=module下,原本隐式按 CommonJS 处理的内容将按 ES 模块解释,具体涉及三类输入:
- 通过
--eval或 STDIN 提供的字符串输入,且未指定--input-type; - 以
.js结尾或无扩展名的文件,且当前目录及所有父目录中都不存在package.json; - 以
.js结尾或无扩展名的文件,其最近父级package.json缺少type字段(位于node_modules内的除外)。
此外还有一个联动细节:当同时传入--experimental-wasm-modules时,无扩展名的文件如果包含 Wasm "magic bytes" 头,将被解释为 Wasm 模块。该标志由 Geoffrey Booth 贡献(PR #49869),其实现还包括"在--default-type下绕过 CommonJS loader"(#49986)与"模块作用域内去标志化无扩展名 JavaScript 与 Wasm"(#49974)等配套改动。
5. 其他 ESM 相关变更
发布说明还列出若干值得关注的 ESM 侧改动:
- import attributes 取代 import assertions:ESM 与
vm模块均改用 import attributes 语法(#50140、#50141),这是对 TC39 提案演进的跟进,assert关键字相关用法需要注意迁移; - loaders 文档章节移动与重命名(#49261);
- 一批与
register行为相关的修复,例如支持URL实例作为注册目标(#49655)、移除Module.register的返回值(#49529)、修复全局预加载(globalPreload)警告等。
从提交历史看,本次还移除了对已废弃钩子的支持(#47580),并将钩子执行迁入独立线程(#44710,这是 Node.js 20 架构决策的回迁基础)。如果你仍在使用基于旧钩子 API 的 loader,升级到 18.19.0 时应同步迁移到register+ 新钩子签名。
测试运行器(test_runner)大幅增强
Node.js 18.19.0 将内置测试运行器在 20 号线上的多项改进整体回迁(backport),以下是发布说明中列出的全部新增能力:
| 能力 | 说明 | 类型 |
|---|---|---|
testOnlyinrun | run()方法接受testOnly选项,可只执行标记为only的测试 | SEMVER-MINOR |
| JUnit Reporter | 新增 JUnit 格式报告器,便于对接 Jenkins 等 CI 系统 | SEMVER-MINOR |
| 测试位置暴露 | 向外部暴露测试在源文件中的位置(location)信息 | SEMVER-MINOR |
| Shards 支持 | 支持将测试集按分片(shard)切分,适合分布式并行执行 | SEMVER-MINOR |
| fakeTimers 初版 | 内置 mock 定时器(MockTimers)的初始版本,支持setImmediate等 | SEMVER-MINOR |
--test-concurrency标志 | CLI 新增并发度控制标志,可限制测试文件并发执行数 | SEMVER-MINOR |
以--test-concurrency为例,其 CLI 形态为:
node --test --test-concurrency=4该标志与run()编程式 API 配合,可以让开发者精细控制测试执行对 CPU 资源的占用;而 shards 支持则让大型测试集可以按--test-shard=1/4之类的方式拆分到多台 CI 机器并行执行。MockTimers初版则允许在测试中模拟setTimeout、setInterval、setImmediate等定时器行为,减少对真实时间的依赖(相关提交还包含对Symbol.dispose的支持)。
配套的修复与打磨还包括:spec报告器对todo/only的处理、全局before/after钩子的执行时机修正、test:fail事件类型修正、以及测试失败时退出码行为的调整等。对于在 18 号线上希望获得更现代测试体验的团队,18.19.0 之后内置测试运行器的可用性已显著提升。
其他值得注意的变更
发布说明的 "Other notable changes" 还包含多项SEMVER-MINOR更新:
- uvwasi 升级到 0.0.19(#49908),并为
wasi模块同步引入了适配最新 uvwasi 的更新(#49908); - stream:Readable 状态改用 bitmap 表示(#49745),这是对可读流内部状态管理的一次结构性优化;
- lib:新增 API 检测 source maps 是否启用(#46391),便于工具链在运行时感知
--enable-source-maps状态; - lib:为
diagnostics_channel新增 tracing channel(#44943),进一步强化 Node.js 内置可观测性能力; - src:新增
cjs_module_lexer_version与base64_version(#45629); - tls:新增
ALPNCallback服务端选项,支持动态 ALPN 协商(#45190),允许在 TLS 握手过程中根据客户端提供的协议列表动态选择应用层协议(如 HTTP/2 与 HTTP/1.1 的运行时抉择)。
此外,依赖侧还同步升级了 OpenSSL 3.0.12+quic1、c-ares 1.20.1、corepack 0.22.0、simdutf、ada 等多个组件,并修复了child_process在 Linux 上的 spawn 性能(#48523)等实际问题。完整的提交清单(数百条按bootstrap、build、deps、doc、esm、test_runner、tools等模块组织的 commit)可查阅 v18.19.0 发布说明 原文。
下载资源与校验和验证
发布说明末尾附带了完整的官方下载清单,覆盖 Windows、macOS、Linux、AIX 与源码包。主要分发物包括:
| 平台 | 分发物 |
|---|---|
| Windows | x86/x64 的.msi安装器、node.exe二进制、.7z/.zip压缩包 |
| macOS | 通用.pkg安装器、Apple Silicon(arm64)与 Intel(x64)二进制 |
| Linux | x64、PPC LE 64-bit、s390x、ARMv7 32-bit、ARMv8 64-bit 二进制 |
| AIX | ppc64 二进制 |
| 通用 | 源码包(.tar.gz)、headers 包、node.lib等开发用文件 |
所有文件均位于官方发布目录nodejs.org/dist/v18.19.0/,并提供了对应的SHA256 校验和列表。例如 Linux x64 压缩包的校验和为:
153312ae9fe8684f345100e4d141a521dc542b36d8c1e09c31ac290eae98c62a node-v18.19.0-linux-x64.tar.gz 61632bb78ee828d6e8f42adc0bc2238a6b8200007093988d3927176a372281e8 node-v18.19.0-linux-x64.tar.xz校验和列表以PGP 签名消息形式呈现(-----BEGIN PGP SIGNED MESSAGE-----到-----END PGP SIGNATURE-----),这意味着校验和文件本身经过 Node.js 发布团队的 PGP 签名,可防止校验和被篡改。完整清单(含 Windows、macOS、AIX、headers 等全部条目及签名块)可直接在 v18.19.0.md 中核对。
总结与升级建议
Node.js 18.19.0 "Hydrogen" 是 18 号线后期一次高价值的功能回迁:
- npm 用户将随版本获得 npm 10.2.3,注意验证锁文件与 CI 流程;
- ESM 生态维护者应尽快将
--experimental-loader用法迁移到--import+register,并适配 import attributes 与去标志化的import.meta.resolve; - 测试工程团队可以开始用内置测试运行器的 shards、JUnit 报告器与
--test-concurrency增强 CI 效率; - 服务端团队可关注
ALPNCallback与diagnostics_channeltracing channel 带来的协议协商与可观测性能力。
在 nodejs.org 仓库中,你还可以继续探索:发布博客的 frontmatter 解析与分类逻辑(scripts/blog-data/generate.mjs)、发布类别在前端的预览映射(util/blog.ts)、以及各版本线的 npm/V8 版本数据生成(next-data/generators/releaseData.mjs),从而完整理解"版本发布 → 官网呈现"的全链路。
【免费下载链接】nodejs.orgThe Node.js® Website项目地址: https://gitcode.com/GitHub_Trending/no/nodejs.org
创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考