译:Node.js 2023 年度总结

作者:Rafael Gonzaga 原文:https://blog.rafaelgss.dev/nodejs-2023-year-in-review

两个月过去,进入了 2024 年,我决定总结一下 Node.js 在 2023 年的成就。和往常一样,这份清单是由我精心策划的,所以可能会由于 Node.js 合作者完成的大量工作以及我对一些需要更多上下文的领域(如 WASI)而忽略了一些拉取请求。

Node.js 正在迅速发展,对于普通用户来说,要跟上最新的变化可能会很具有挑战性。即使作为项目成员,也有可能会忽视某些提交。因此,本文旨在突显 2023 年 Node.js 领域内发生的主要变化和讨论。

作为参考,2023 年对 nodejs/node#main 进行了 2641 次提交。虽然这个信息可能看起来比较琐碎,但我发现将其与历史数据进行比较很有趣。例如,这是过去 10 年中 main 上的提交计数。

2023 年 1 月 1 日 ~ 2024 年 1 月 1 日 = 2641
2022 年 1 月 1 日 ~ 2023 年 1 月 1 日 = 2629
2021 年 1 月 1 日 ~ 2022 年 1 月 1 日 = 2683
2020 年 1 月 1 日 ~ 2021 年 1 月 1 日 = 3390
2019 年 1 月 1 日 ~ 2020 年 1 月 1 日 = 3953
2018 年 1 月 1 日 ~ 2019 年 1 月 1 日 = 4720
2017 年 1 月 1 日 ~ 2018 年 1 月 1 日 = 4609
2016 年 1 月 1 日 ~ 2017 年 1 月 1 日 = 3081
2015 年 1 月 1 日 ~ 2016 年 1 月 1 日 = 2261
2014 年 1 月 1 日 ~ 2015 年 1 月 1 日 = 1052

💡 我使用了我创建的一个小项目,叫做 nodejs-stats,来获取这样的信息。

看到像 Node.js 这样一个成熟的项目在多年内仍然有显著的发展是相当令人印象深刻的。不幸的是,我没有历史数据,但我强烈怀疑 Node.js 在今年迎来了大量的首次贡献者。这可能是由于像 Grace Hopper 的日子和各种研讨会等倡议的影响。例如,在 NodeConfEU 2023 上,我的团队进行了“你的第一个 Node.js 贡献”研讨会。我相信其他成员也一直在协助新贡献者参与到项目中 - 如果你期待着对 Node.js 项目做出你的第一贡献,请随时与我联系。我正在进行直播,协助人们理解 Node.js 代码库。

Node.js 发布

在 2023 年,不同版本线上进行了 102 次发布(包括安全发布)

$ git log --all --grep=', Version' --pretty=format:"%cs,%aN,%s" --since='Jan 1 2023' --before='Jan 1 2024' | wc -l
102

该年度始于 4 个活跃的版本线:

  1. Node.js 14
  2. Node.js 16
  3. Node.js 18
  4. Node.js 19

Node.js 14、16 和 Node.js 19 现已进入生命周期结束(EOL),Node.js 18 处于维护模式,这意味着不再有定期发布到此版本。

该年度结束时,以下版本线仍然活跃:

  1. Node.js 18(维护)
  2. Node.js 20(LTS)
  3. Node.js 21(当前)

因此,如果你没有使用这些版本之一,请尽快升级。

在 Node.js Collaborator Summit(NodeConfEU)期间,我们分析了 Node.js 二进制文件的下载统计数据,这表明用户没有像他们应该的那样快速更新他们的二进制文件。

Node.js 下载统计

正如图表所示,即使是 EOL 版本仍然会收到大量下载,这对 Node.js 用户来说是危险的,因为他们将在某个时候使用一个有漏洞的版本。因此,我们心中产生了一个理论,即我们的发布计划太快了。一个新的提案正在讨论中,仍然需要由发布团队评估,但建议将主要发布减少到每年一次,而不是每年两次。

在上面的图表中,特别关注 y 轴,人们可能会推断 Node.js 下载在 3 月 23 日左右达到了约 6000 万。然而,这种解释是误导性的,因为它没有考虑 NodeSource 的分发统计数据,这主要包括生产二进制文件,并不包括来自不活跃版本线(如 Node.js 8、10、12 等)的下载。为了更深入地了解 Node.js 分发机制,我鼓励你探索 “Node By Numbers 2021~2022” 这篇文章中概述的细节,因为深入探讨这个主题超出了本文的范围。

在金矿中的金丝雀(CITGM)上的积极工作

@nodejs/releasers 在 Node.js 领域中扮演着至关重要的角色。他们确保您在您的机器上收到的版本是可靠的。为了实现这个目标,我们使用了在所有支持的架构上运行的全面测试套件,并根据更改运行特定的测试,如 V8。此外,对于每个发布,我们执行 CITGM(Canary-In-The-Gold-Mine),它基本上会获取lookup.json中列出的所有模块,并使用新的二进制前景运行它们的测试套件。如果出现任何问题,我们会调查并有时联系模块作者寻求指导。

然而,CITGM 需要一组强大的机器来正确运行所有测试。不幸的是,在这方面我们有点受限,导致一些测试之间存在并发错误。这是因为某些测试需要并行运行;否则,CITGM 将需要数年才能完成。另一个挑战是确保lookup.json中列出的模块是最新的。有时,一个模块会被存档,或者可能永远不会支持更新版本的 Node.js,或者它们可能只是不可靠(这是相当常见的)。

因此,看到像下面这样的倡议并不罕见:

否则,我们可能会发现自己处理一个不可靠的 CITGM,从而让我们对潜在的重大变化一无所知。

Node.js 项目的新方向

为了澄清,我想强调我并不是代表整个项目发言;这篇文章仅代表我的观点。

作为项目的一员已经有一段时间了,而且自 2022 年以来,我一直是技术指导委员会(TSC)的成员,我观察到项目现在比以往任何时候都更容易受到重大变化的影响。由于这个原因,一些新的依赖正在集成到核心中,并且正在开发新的内置模块。这扩大了 Node.js 作为平台的范围。然而,在我看来,这种新的方法可能会引发对维护和潜在攻击途径的担忧。另一方面,这也赋予开发人员更多的权力,并减轻了使用恶意库的风险,尽管在本机端执行操作会带来性能上的影响。作为参考,我一直在密切监控 Node.js 在不同版本间的二进制大小,显然可以看到添加新的依赖和功能直接影响了二进制大小。

每个版本的二进制大小

除非在极度受限制的环境中操作,100MiB 不应引起重大关切。

新的依赖关系

Node.js 将以下依赖关系纳入其二进制文件中:

{
  node: '21.6.0',
  acorn: '8.11.3',
  ada: '2.7.4',
  ares: '1.20.1',
  base64: '0.5.1',
  brotli: '1.1.0',
  cjs_module_lexer: '1.2.2',
  cldr: '44.0',
  icu: '74.1',
  llhttp: '9.1.3',
  modules: '120',
  napi: '9',
  nghttp2: '1.58.0',
  nghttp3: '0.7.0',
  ngtcp2: '0.8.1',
  openssl: '3.0.12+quic',
  simdjson: '3.6.3',
  simdutf: '4.0.8',
  tz: '2023c',
  undici: '5.28.2',
  unicode: '15.1',
  uv: '1.47.0',
  uvwasi: '0.0.19',
  v8: '11.8.172.17-node.19',
  zlib: '1.3.0.1-motley-40e35a7'
}

在 2023 年,Node.js 向其添加了 3 个新的依赖:

  1. Ada - 一款采用现代 C++ 编写的符合 WHATWG 标准且快速的 URL 解析器
  2. simdutf - Unicode 路由(UTF8、UTF16、UTF32)解析器
  3. simdjson - 一款使用通用 SIMD 指令和微并行算法高效解析 JSON 的库

所有这些库都专注于性能,使 Node.js 能够在 “Node.js 性能现状 2023”中看到的新的改进高峰。

OpenSSL 3.0.x 在 QUIC 上的成本

自版本 16 起,Node.js 使用了来自 quictls 团队的 openssl 分支。这是将 QUIC 协议引入 Node.js 的初始步骤。然而,OpenSSL 3.0.x 的性能明显低于 OpenSSL 3.2.x。从 Node.js 的角度看,有两个难以从 OpenSSL 3.0.x 转移到 OpenSSL 3.2.x 的关键点:

  1. 它并不完全支持 QUIC — 虽然 Node.js 尚未(至今)支持 QUIC。
  2. OpenSSL 3.2.x 不是一个长期支持(LTS)版本 — 在它的生命周期结束后可能存在漏洞,这对 Node.js 中的 LTS 版本是不可接受的。

如果需要一些上下文,请查看 #51152。在性能方面,您可以使用我的存储库 nodejs-bench-operations 作为 crypto 操作的参考:

Node.js 16.20.2 - OpenSSL 1.x操作/秒样本数
crypto.createVerify('RSA-SHA256')30,33798
crypto.verify('RSA-SHA256')29,00194
Node.js 18.18.2 - OpenSSL 3.x操作/秒样本数
crypto.createVerify('RSA-SHA256')3,59986
crypto.verify('RSA-SHA256')3,59987

持续性能进化

“Node.js 性能现状 2023” 中所述,Node.js 在性能方面持续稳步发展。本节将不涉及具体的数字数据(将在《Node.js 性能现状 2024》中详细提供),而是突出显示在性能领域取得明显进展的倡议和 PR。

一个显著的改进是将 libuv 升级到版本 1.45.0。在这个版本中,在 Linux 上启用了 IO_URING,使文件系统操作(如 readwritefsyncfdatasyncstatfstatlstat)的吞吐量增加了 8 倍。更多详情可以在相关的 pull request 中找到:libuv/libuv#3952

此外,在 2023 年,我们引入了 Ada 作为 Node.js 的新 URL 解析器,现在已经在所有活跃的发布线(18、20 和 21)中可用。更多信息可以在 pull request 中找到:nodejs/node#46410

2023 年还发现了两个重要的退化:

  1. AsyncHooks
  2. WebStreams

这些功能对 Node.js 的某些用例至关重要。例如,如果使用 fetch(),可能会依赖于 WebStreams;或者如果使用任何应用性能监控(APM)工具,应该通过 AsyncLocalStorage 利用 AsyncHooks。

在一月份启动的一个倡议,在问题 #46265 中有所记录,提出了在不依赖 AsyncHooks 的情况下替代实现 AsyncLocalStorage。在 pull request #46387#48528 中进行了一些相关的工作。

WebStreams 在 2022 年被确定为 fetch 函数的瓶颈,正如在 这个问题评论 中所强调的。自那时以来,我们一直通过多个 PR 不断增强 undici 中对其的使用,例如:

对于那些关注 Node.js 性能的人,我强烈建议关注 nodejs/performance 存储库,并参加它们的会议。务必关注 performance 标签,以了解诸如 nodejs/node#49745nodejs/node#49834 这样的 PR,它们旨在提升常规 Node.js 流的性能。

Node.js 中的本地基准模块

在 2023 年,Node.js 几乎 获得了一个内置的基准模块。我和一位同事一起编写了一个 pull request(Vinicius Lourenco),向 Node.js 添加了一个实验性的基准模块:require('node:benchmark')

尽管这个 pull request 得到了很多关注,但出于一些原因,我们并未继续进行这项工作:

  • 基准测试很困难,微基准测试甚至更难。它们难以评估,并且难以证明它们的准确性,因为有不同的策略来衡量它们 — 有关更多上下文,请参阅我的 Preparing and Evaluating Benchmarks 文章 — 当时我在不同领域的 Node.js 上有限的带宽,无法在这个主题上进行深入的研究。
  • 一些 Node.js 协作者提出了一些建议,正如我之前所说,当时我没有太多带宽来深入探讨和参与深入的对话。

然而,这并不意味着我们放弃了!我们将这个模块发布为 bench-node,在 npmjs 上 — 我知道,我们还没有找到一个更好的名字。看一看并给一个星星 ⭐ https://github.com/RafaelGSS/bench-node/

提升 Node.js 安全性

安全性是我在 2023 年大部分时间中都投入的领域。我与 OpenSSF 有一份合同,全职致力于 Node.js 的开发和安全性改进。在这一部分,我将简要展示我们讨论过的所有主题、实施的功能、工作流程等。非常感谢 Node.js 安全团队的所有成员,他们在过去和当前的项目中给予了帮助。对 Node.js Triage 团队的一声赞美,因为他们帮助我处理了所有 HackerOne 报告。特别感谢 Tobias Nießen 为在 Node.js 核心中发现和解决问题而辛勤工作。

Node.js 权限模型

让我们从 2023 年我 — 完全主观 — 认为的最大安全成就开始。Node.js 权限模型。这个倡议始于很久以前,由 Anna Henningsen 和 James Snell 开始,但当时还没有准备好,我在 2022/2023 年重新实现了它。如果想要了解这个功能背后的本质,我在 NodeConf EU 上做了一个关于它的演讲:Node.js 权限模型之旅

从技术上讲,这个 实验性 功能允许您限制对环境资源的访问,例如:

  • 文件系统(更具体地说,fs 模块)- 读/写
  • 检查器协议
  • 工作线程
  • 子进程和
  • 本机插件

使用起来非常简单,使用 --experimental-permission 启动 Node.js 进程,并传递 --allow-* 标志。例如,我想给我的应用程序的入口点提供 只读 访问权限:

$ node --experimental-permission --allow-fs-read=./index.js index.js

因此,如果尝试从其他路径读取/写入,它应该抛出错误:

// index.js
const fs = require('fs') 
const data = fs.readFileSync('/etc/passwd') 
console.log(data.toString())
node:fs:581
  return binding.open(
                 ^

Error: Access to this API has been restricted
    at Object.openSync (node:fs:581:18)
    at Object.readFileSync (node:fs:460:35)
    at Object.<anonymous> (/home/rafaelgss/index.js:3:17)
    at Module._compile (node:internal/modules/cjs/loader:1378:14)
    at Module._extensions..js (node:internal/modules/cjs/loader:1437:10)
    at Module.load (node:internal/modules/cjs/loader:1212:32)
    at Module._load (node:internal/modules/cjs/loader:1028:12)
    at Function.executeUserEntryPoint [as runMain] (node:internal/modules/run_main:142:12)
    at node:internal/main/run_main_module:28:49 {
  code: 'ERR_ACCESS_DENIED',
  permission: 'FileSystemRead',
  resource: '/etc/passwd'
}

Node.js v21.6.1

更多信息可以在官方文档中找到。

处理更多安全发布

在 2023 年,我们发布了更多的安全发布,主要是因为我们在第三方 CVE 方面更加主动。在 2022 年,Security Team 创建了几个倡议,如 Alpha-Omega Node.js 报告 2022 中所描述的那样,这些倡议的结果在 2023 年展现出来。自动更新和 Node.js 发布对我们团队的行动时间产生了影响。

随着权限模型的最新添加,人们还发现了 Node.js 从版本 11.8.0 起就存在的另一个实验性安全功能:策略机制。这个功能适用于我们所谓的模块化权限,并且我们在 2023 年解决了这个功能的一些漏洞。

此外,在报告方面,在我们的威胁模型中进行了一些澄清。实验性功能,如 权限模型策略,可以与任何稳定功能一样附加到相同的级别。因此,在审查 Node.js 安全发布时,请检查漏洞是否影响您。我们经常修补的是一个仅影响该功能用户的 ‘High’ 漏洞。

网站更新

在 2023 年,有关给 Node.js 网站焕然一新的讨论,如此处所述。我们在 TSC 会议上多次讨论过这个话题,还在 Node.js Collab Summit 上分享了这个想法。这是一项涉及许多步骤的大工程,我想要向整个 @nodejs/website 团队致以崇高的敬意,感谢他们在这方面的辛勤工作。请看下面的图片:

Website new design 1

Website new design 2

即将推出的下载页面:

Website new design 3

草案 PR: nodejs/nodejs.org#6353

功能

2023 年发布了多个功能。在一篇文章中详细阐述每个功能对我来说有点困难。因此,这篇文章将列举一些重要的功能,供您深入挖掘!

  • 单可执行文件应用程序(实验性)- 这个功能已经在 Node.js 19 上落地,但在 Node.js 20.0.0 发布 后受到了更多关注。这个功能允许将 Node.js 应用程序方便地分发到没有安装 Node.js 的系统上。值得注意的是,我们仍在开发中,因此这也是一个 实验性 功能,我强烈建议您尝试一下!
  • 内置 .env 支持(实验性)- 在 Node.js 20.6.0 中发布,此功能旨在提供从配置文件读取环境变量的官方机制。以前常用的方法是依赖于 dotenv 包或类似的方法。在这个版本之后,您可以在 Node.js 中直接使用它,而无需安装新的包。此外,可以在 —env-file 文档 中找到更多信息。
  • WebSocket 客户端(实验性)- Node.js 21.0.0 发布 中包含了另一个实验性功能。此版本引入了一个内置 WebSocket 客户端(在一个标志后面)。通过 --experimental-websocket 标志启用。遵循 WHATWG WebSocket 规范
  • 测试运行器(稳定)- 尽管这个功能在 2023 年并没有发布,但在去年的 API 中包含了许多功能。包括将此模块标记为 稳定
  • 添加了对函数模拟的支持 #45326
  • 添加了对时间(MockTimers API)模拟的支持 #47775
  • 更改了执行上下文和域的方法 #47686。
  • 也增加了 --inspect-brk 的支持。

结束语

在 2023 年,我继续为 Node.js 做出了贡献,但这次以全职的身份。2023 年给了我深入了解 Node.js 的机会,并在一系列项目中取得了可观的进展。这篇文章的目的是分享 2023 年的一些重大事件、改进和新功能,以及对将来的一些建议和展望。感谢所有在这一年中帮助过我的人,特别是 Node.js 社区,你们使得这个项目如此有活力和令人愉快。希望 2024 年对 Node.js 社区来说同样是一个积极向前的一年,充满了新的创意和进步!

注:

  • 此文档基于我的一些个人经验和对 Node.js 仓库的贡献,也包括了一些 Node.js 社区中其他人的工作。这并不是一个全面的报告,而是着重强调一些我认为在 2023 年具有重要意义的方面。
  • 请注意,Node.js 的版本和功能可能会随时间推移而发生变化。在查看最新信息时,请查阅 Node.js 官方文档Node.js GitHub 仓库
2024-03-07

访问量 93

扫码关注公众号“前端微志”

第一时间获取新周刊

预览图片