🙋🏻♀️ 编者按:本文是 NodeParty 回顾文章之一,作者是 Node.js、V8 活跃贡献者,阿里巴巴集团 TC39 代表吞吞,介绍了 Node.js 的工作组与战略计划,以及未来十年的发展,欢迎查阅~
其他 NodeParty 回顾文章:
大家好,今天很高兴能够在 NodeParty 和大家介绍 Node.js 的工作组与战略计划,以及未来十年的发展。我先做一个简单的自我介绍,我是来自阿里巴巴淘系技术部的吞吞,目前是 CNCF OpenTelemetry 项目的维护者,同时也是Node.js、V8 的活跃贡献者,阿里巴巴集团 TC39 代表。
在这次的分享中,我们会介绍如何跟踪 Node.js 中正在发生的事情,和在跟踪过程当中需要了解的发行计划;了解我们跟踪的特性会在哪一个版本当中发行;我们也会了解当前 Node.js 正在活跃维护的一些有趣的新特性;在这之后我们会了解一下当前比较活跃的工作组和战略计划。这些都是我们了解 Node.js 接下来会发生什么的重要窗口。在了解了当前活跃的工作之后,我们也会介绍一下如果我们有想要落地的特性,我们该如何将这些特性落地到 Node.js 上,参与到这些工作之中。
Node.js 如何决定接下来发展路线?
Node.js 项目维护的基本方针是透明治理,也就是说它所有决策都是透明公开在 GitHub 仓库上的。我们可以在 GitHub 的 Issue Tracker 当中去追踪到它所有的决策过程。Node.js 技术指导委员(TSC)会也会将他们所有的讨论公开在 GitHub 上。值得注意的是,Node.js TSC 中单个公司的雇员是不能超过 25% 的。也就是说这是一个去中心化的组织,它是由社区控制来驱动 Node.js 来发展的。也正是因为去中心化的组织架构,能够让 Node.js 集合所有人的兴趣、爱好和利益点去推动 Node.js 的发展。
作为一个松散的组织,Node.js 官方其实是没有一个明确路线图。新特性通常是没有具体的版本发布计划,会随着 Current/LTS 版本滚动发布。也就是说这些新特性完成了实现之后,那么它就会在下一个即将发布的版本当中随之滚动发布。不过虽然它是一个松散组织,Node.js 也存在长期紧密合作的工作组和一些明确的战略计划。
我该如何跟踪 Node.js 进展?
如果想要去追踪 Node.js 接下来需要发布的内容、接下来正在进行的进展,最便捷的方式就是关注 Node.js 官方博客。每当一个新版本发布,或者是有重要的事项需要通知时,Node.js 官方博客上都会发布发行纪要或者公告。
除了官方博客,了解 Node.js 发展最直观、最便捷的方式,当然是直接参与 GitHub 讨论。而正如刚才所说,Node.js 的决策都是透明和公开的,我们可以在 GitHub 上看到它所有特性的实现过程与决策讨论的过程。讨论没有任何的门槛。当然你必须要有一个 GitHub 账号来进行讨论。除此之外,还可以参与到各个工作组的定期工作会议了解当前工作组的工作进展。
Node.js 版本发行
Node.js 主要有三个发行线,一个是 Nightly 版本,也就是我们熟知的 Main 分支,它每天都会有最新的版本打包出来可以让开发者们试用。但这个发行通常也是最不稳定的,可能会有各种奇奇怪怪的问题,不过是开发者们尝试最新特性、最新修复的一个非常便捷的方式。
另一个是 Current 版本,每六个月都会从 Main 分支上切出新的 Major 版本作为 Current 版本。其中为 Major 版本号为偶数的 Current 版本,它会在发布当年的十月份被提升为 LTS 版本,也就是长期维护版本。
LTS 长期维护版本每 12 个月发布一次,它有 30 个月的长期维护期。在这 30 个月内,包含 12 个月的活跃特性支持。这 12 个月内只要 Main 分支上有任何新的特性,这个长期维护版本都能同样获得这些特性更新。在这 12 个月的活跃特性支持的周期过后,还有 18 个月的维护支持,如 Bug Fix、安全更新等。
刚才我们有提到,新特性通常不会有固定的发布计划。他们会在这些特性实现之后,随着 Current 和 LTS 版本固定的发布周期来滚动发布。这些新特性在合并到 Main 分支之前,他们会被标记为 SemVer Major 或者 SemVer Minor。通常来说他们都会被标记为 Semver Minor 版本,也就意味着他们会被发布到活跃支持的 LTS 版本上。比如目前 v16 是最新的 LTS 版本,v18 是 Current 版本,在今年 10 月份时 v18 将提升为 LTS 版本。v18 作为新的 LTS 版本发布时,它上面的一些新特性我们其实已经在 Node.js v16 上使用过一段时间了,可能已经是我们熟知的一些“老”特性。这也是 LTS 版本发布机制的一个好处。
有趣的新特性
了解了 Node.js 的版本发布计划后,我们接下来看一看最新的一些特性,如 ECMAScript Modules 新支持了 JSON Module、Module Loaders,以及在近期的 v17 中发布的 node:test 这种内置的测试驱动模块,之前社区当中热议的中立的模块管理器的管理器 Corepack。Node.js 也在努力做 Web API 的兼容性支持,比如说 Web Crypto, Fetch, Web Stream, WebAssembly, Web Worker 等等。
ECMAScript Module
自从 2015 年 ES6 发布以来,Node.js 一直在不断改进 ECMAScript Module 支持,不断地优化 ECMAScript Module 与已经广泛使用的 CommonJS 模块互操作性,如在 ESM 中导入 CJS 模块,或者在 CJS 中导入 ESM 模块。现在对于模块维护者来说,他们可以在 package.json 当中去声明模块类型为 module 类型。除此之外,他们也可以在 package.json 当中去声明对于 CJS 和 ESM 来说,不同的入口模块,这样模块维护者可以在一个 npm 包里面针对 CommonJS 和 ECMAScript Module 区分不同的入口。
Node.js 最近也已经支持了 ECMAScript 中的 JSON Modules。我们可以通过 import assertion 语法来去导入一个 JSON 模块。
然后还有实验性的 Module Loaders,现在我们可以同时使用多个 Module Loader。比如我们通过 http loader 像 deno 或者 Web 浏览器环境直接导入一个 Http 模块。或者使用类似于 CommonJS 中 tsnode 的 TypeScript Loader 导入 TypeScript 文件。Module Loader 特性还在持续地演进当中,后续也会支持更多的场景,比如在 ShadowRealm 中使用 Module Loader。
我们可以在 Loaders 工作组仓库中去追踪他们的 roadmap。
node:test
然后我们接下来看一下 v17 中正式落地到 Node.js 中的实验性特性 node:test。我们现在可以使用 node 的提供的测试界面来写测试用例,而不需要任何的第三方模块。他提供的测试界面非常简单,就是一个 test 函数。Node.js 也提供了 behavior driven test 中的 describe 和 it 的界面。我们可以通过命令行 node --test 来执行这些测试。Node.js 输出的测试报告是社区常见 tap 格式,我们可以使用各式各样的 tap reporter 来解析测试输出结果。
Corepack
Corepack 是中立的“模块管理器”管理器。我们现在比较常用的像 npm,yarn,pnpm 或者 tnpm 都提供了兼容 Node.js 模块查找逻辑的包管理能力。在 2022 年,npm 已经不再是 Node.js 项目安装依赖的唯一工具。值得注意的是,npm 是一个私有公司项目,它不是托管于 OpenJS Foundation 等中立基金会、通过社区驱动管理的项目。所以作为 OpenJS Foundation 的中立项目,为了避免被一个特定私有公司所绑架、驱动,将 Corepack 作为 Node.js 内置的功能让大家去有更多中立的选择。
当然 Corepack 还可以将一个“模块管理器”打包成一个压缩包,然后我们就可以将这个压缩包上传到我们的生产环境当中,或者是一个特殊的网络的环境中,然后将打包好的包管理器使用 Corepack 恢复出来,即可直接使用。具体的话也可以直接看 Corepack 的文档。
Node.js 工作组
工作组是驱动 Node.js 绝大多数特性落地实现的一个重要工作方式。Node.js 工作组都是公开的,比如工作组的工作会议都会在 Node.js 官网上的日历中公开。参与这些工作会议是没有任何门槛的,只要有大家有任何兴趣,都可以直接去参与到他们的线上会议当中。
接下来我们会简单介绍一下 undici,Node-APi, 还有诊断工作组。
Undici 工作组
我们刚才提到 Node.js 目前也正在活跃提供 Web API 的兼容性支持。其中 Fetch API 就是由这个工作组维护、支持。
undici 是 Node.js 现代化的一个HTP Client。相对于现在的 http 模块来说,undici 模块提供了更加现代化的 API。比如说他提供了 Web Fetch API 的支持, mock 请求能力的支持。如果我们想要拦截 http 模块当中的一些发起的请求,我们可能需要去做 monkey patch,而通过 undici 提供的这个内置请求拦截能力,我们就不再需要去做 monkey patch。我们可以通过它提供的拦截器来去对请求做装饰,或者对请求做本地的 mock 拦截。
当然它还提供了最新的 diagnostic channel 支持。这个我们会在等一会儿介绍诊断工作组的时候会去介绍这个特性。这个特性就是说我们常见的,比如像 APM,也就是比如社区常见的 OpenTelemetry,DataDog,或者是 Sentry,它们都可以通过 diagnostic channel 来对 undici 模块做注入,然后去插入一些对于 APM 来说必要的信息,比如说在里面插一些 Trace ID 等等。同时 undici 也提供了内置的 Http Proxy 的支持。
undici 工作组主要就是维护 undici 包。Node.js 官方还维护了 undici 的 npm 包,可以通过 npm 安装使用。
诊断工作组
诊断工作组主要工作是在 Node.js 当中去维护多种多样的诊断能力。比如说 diagnostic channel,诊断报告等。诊断报告是人可读的 JSON 格式的文件,如果在 Node.js 进程崩溃的时候,比如说出现了 fatal error,那它可以在进程退出前生成诊断报告。因为诊断报告是文本文件,我们可以直接去阅读这个文件,不像核心转储是二进制的格式,需要一些特殊的工具去解析核心转储。
在上图中的使用例子里面看到,我们可以通过 diagnostic channel 去订阅 undici 的 request 创建事件,然后在这个 request 中注入 Trace Id 等等信息。上图右下角是一个诊断报告的示例,我们可以看到它里面包含了报告版本,包含了报告的触发原因,报告时间等等。当然还包含了进程的很多信息,比如 JavaScript 调用栈,C++ Native 的调用栈等等。
除了这两个关键的特性之外,诊断工作组也维护了很多其他的诊断工具,比如说像 llnode 等等。
Node-API 工作组
除了刚才这两个工作组之外,还有就是 Node-API 工作组。Node-API 是一个 ABI 稳定的 Addon API,里面包含了 ECMAScript 语言常用的一些特性,比如说创建对象,创建 array 等。像 SWC,node-sqlite3,parcel, cbrypt 等等这些常见 npm 模块目前都已经迁移到了 Node-API 来实现 Node.js addon。Addon 使用了 Node-API 的话,在我们在切换 Node.js 版本之后,就不需要再重新 npm install 去编译了。它是可以跨 Node.js 版本使用的,不像直接使用可能 breaking change 的 V8 API。
Node-API 是由 Node-API 工作组来长期维护,并保证 API/ABI 稳定的。我们能够通过 C、C++,还有其他如 Rust、Go 等等编程语言通过 Node-API 去编写多种多样的 Node.js Addon。Node.js 官方维护了一个 node-addon-api 的 npm 包,提供基于 Node-API 的现代化的 C++ API 封装。
战略计划
战略计划目前包括像 Core promise API,在 Node.js 中将以前传统的基于 callback 的API 转换成基于 Promise 的 API,让他们更加现代化;像 HTTP3 的最新协议支持;ShadowRealm;Startup Performance;还有最新的 V8 版本支持。接下来主要是简单介绍三个战略计划。
Startup Performance
在上周,我们刚好在 Node.js 中落地了在用户态创建 Startup Snapshot 的 API。通过这个 API,我们可以获得更快的启动速度。比如我们业务当中可能常用到通过 vm 来做服务端渲染,或者是在通过 Node.js 来做 Serverless Runtime 等等,都可以受益于这个启动性能优化。
它主要是通过 V8 Startup Snapshot 机制来将 JavaScript 执行状态来保存到硬盘上。然后在下一次启动的时候,快速地从保存的 Startup Snapshot 中反序列化出整一个JavaScript Heap。通过这种方式,启动初始化过程中的 JavaScript 逻辑都不需要再重新执行一遍,我们就可以从保存的 Startup Snapshot 中恢复出可执行的状态。
Startup Snapshot 除了提供的启动速度的优化之外,我们后续也会基于这个特性来实现 Signle Executable Application,以期将 Node.js 应用打包成一个单独的可执行二进制文件,不再需要一大堆的 node_modules 等等。
ShadowRealm
ShadowRealm 目前也是一个 TC39 Stage 3 的提案。ShadowRealm 相对于目前 Node.js 提供的 vm 模块来说,它提供了绝对的 JavaScript 对象交互隔离的执行环境,对象逃逸、对象身份不连续等问题将得到解决。ShadowRealm 相比于 vm 来说,它内置了部分 Node.js 中常见的 API,比如 URL、TextEncoder 等等,也意味着在 ShadowRealm 执行常见的 JavaScript 代码将更加便捷。
ShadowRealm 支持原生的 ECMAScript Modules,并且 Realm 之间的 Module 缓存是互相独立的。我们可以利用这个特性,实现如执行插件代码等等可信的二方脚本。这也是由我负责的一个战略计划。
Next-10
Next-10 战略计划是期望寻找接下来十年 Node.js 的工作方向。对于从这个战略计划来说,目前优先级第一是去明确我们如何改进开发者体验;第二是让 Node.js 一直保持稳定,能够服务于更多的企业场景。目前正在讨论的计划有如在 Node.js 中集成执行 TypeScript 文件的能力。目前 TypeScript 已经成为大家开发 Node.js 应用常见的方案,很多开发者都或多或少的体验到 TypeScript 比如说像类型提示等等好处。但因为 TypeScript 是由微软主导的一个项目,Node.js 如何集成 TypeScript 将会是一个非常大的挑战。我相信 Node.js 将会提供一个中立的选择,让开发者可以选择去使用 TypeScript,也可以使用如 facebook 的 flow 等编程语言。
Openservability 也是一个非常重要的方面,比如说后续应用迁移到 ECMAScript Module之后,我们如何向 ECMAScript module 中通过类似于 CommonJS monkey patch 的方式注入观测代码等等。
这些都是 Next-10 战略计划正在活跃讨论的话题。大家只要对这些有兴趣,都可以在 Node.js slack 中 Next-10 Channel 里面去参与讨论。
成为 Node.js 的关键贡献者
了解了这些战略计划和工作组之后,我们该如何去参与到这个工作当中去、成为 Node.js 的关键贡献者呢?我们刚才提到最简单就是参与 GitHub 讨论,提交 PR,去评论,去发表你的看法。除了 Issue Tracker 上比较零散的一些课题之外,我们可以去参与到工作组当中,去参与他们的工作会议。工作组的会议基本上都是每周定期举行的。我们可以直接在官方的日历上看到他们的会议是在什么时间,线上参会链接等。
像 Node-API 的工作会议是北京时间每周五晚上十一点。Node-API 工作会议也是由我来主持的一个会议之一。
工作会议没有门槛,如果有任何感兴趣的话题,或者对 Node-API 有任何疑问,都可以直接加入这些会议。除了工作组之外,如果我们认为 Node.js 当前它还有一些领域还没有人主导的,但是我们认为它非常重要,这个时候可以在 Node.js 的 Issue 中发起你认为重要的需求、发起你认为重要的战略计划和工作组。提交 Feature Request 或者是战略计划方案、工作组方案,都是没有任何门槛的。只要你有想法、愿意去做这些事情,愿意去贡献你的一份力量,你都可以去发起这些 Feature Request。所以如果我们想要决定 Node.js 接下来十年的发展方向的话,我非常推荐大家主动地去参与到社区的讨论中去,主动发起需求,主动发起战略计划,然后主动去参与到工作组中去。
这些就是我们这次要分享的主要的内容,谢谢大家。
🔗 相关链接:
- Node.js 战略计划:
https://github.com/nodejs/node/blob/main/doc/contributing/strategic-initiatives.md - Node.js ⼯作组惯例⼯作会议:
https://nodejs.org/calendar