又有新的包管理器了!?(Bun 的替代方案)

BBetter Stack
컴퓨터/소프트웨어AI/미래기술

Transcript

00:00:00这是 Nub,一款全能型 JavaScript 工具包,它基于 Node 运行而非替代 Node。
00:00:04它能替代你目前使用的所有这些工具,从比 pnpm 快 5 倍的
00:00:08包管理器,到可以取代 TSX 的 TypeScript 运行器,
00:00:13甚至还包含 Node 版本管理器。它保留了 Bun 的核心优势,但直接构建在原生 Node.js 之上,
00:00:17这大概就是为什么 Nub 恰好是 Bun 字母倒过来拼写的原因。
00:00:21我知道 JavaScript 开发者喜欢重新造轮子,但这可不是什么随机路人的项目。
00:00:25项目。它实际上是由 Zod 的作者 Colin 打造的,他之前还制作过
00:00:29tRPC 的概念验证原型,甚至还在 Bun 工作过。接下来我们就深入体验一下。
00:00:38Nub 本质上是一个 Rust 单文件二进制工具,支持 Mac、Windows 和 Linux。正如我开头展示的那样,
00:00:44这些只是它能替代的部分工具。它是一个文件运行器、脚本运行器、
00:00:47包运行器、包管理器,以及 Node 版本管理器。我们逐个来看看。
00:00:52首先是文件运行器,光是这个功能就包含很多特性。文件运行器支持完整的
00:00:56TypeScript 语法,而不仅仅是像 Node 那样简单的类型剥离(type stripping),因此它可以完美取代 TSX 或 ts-node 等工具。
00:01:02我们可以看到,这里有一个包含 enum、namespace 以及参数属性(parameter properties)
00:01:06的 TypeScript 文件,而这些通常是 Node 无法直接运行的。如果我直接运行 Nub,加上
00:01:11我想执行的文件,可以看到它运行得非常顺利,而在 Node 上这本来会报错。
00:01:15如果我们把这里的 Nub 替换成 Node,可以看到报错提示不支持该 TypeScript 语法,
00:01:20因为它不认识 namespace 或 enum。文件运行器还可以替代 dotenv 类的工具,
00:01:24自动导入环境变量。它支持 .env 文件、.env.local 以及
00:01:29Node 相关的环境配置文件,甚至支持变量自动展开(variable expansion)。比如下方这里,我们可以定义一个
00:01:33由其他环境变量组合而成的变量。这里定义了数据库用户名和
00:01:37数据库主机名。现在如果我用 Nub 运行这个文件,可以看到它为我导入了那些环境
00:01:41变量,并且利用其他环境变量的值拼出了健康检查 URL。
00:01:46你还可以看到,我的 API Key 实际上跟 .env 文件里写的并不吻合。
00:01:50这是因为 .env.local 总是拥有最高优先级,而在那里我把 API Key
00:01:54设置为了 “subscribe to better stack”。如果你想随时掌握最新的
00:01:58AI 和开发者动态,这绝对是值得去做的一件事。欢迎点击订阅,这对我们真的很有帮助。接下来,我要
00:02:02运行 `nub src/index.tsx`,可以看到一切都在正常运行。这是
00:02:07我的 Nub 综合功能测试大杂烩(kitchen sink)。在这个文件的代码中,我使用了大量 Nub 文件运行器提供的特性。
00:02:12首先,我们可以直接导入 JSON 文件,以及 YAML、
00:02:15HTML 甚至纯文本文件;它还可以替代 tsconfig-paths 这类工具。比如我在
00:02:20tsconfig 中配置的以 `@config` 开头的路径别名,它能确保
00:02:24Node 正确解析它们。它还支持装饰器(Decorators),比如这里的 `@service` 和 `@sealed`。此外它还
00:02:29支持 JSX,并会根据你的 tsconfig 设置来进行转译;甚至还能使用
00:02:34现代 JS 关键字,如用于显式资源管理的 `using` 关键字。除此之外,
00:02:38它还支持大量的现代 API,例如 Web Workers、Temporal 等等。在尚不支持这些 API 的 Node 版本上,它会
00:02:43自动为你提供 Polyfill;同时它还会默认开启某些实验性
00:02:48Node 特性,比如 localStorage 支持。这些还只是该文件运行器
00:02:52强大特性的冰山一角,但我还想强调的是,它在 CLI 参数标志上与
00:02:56Node 保持 100% 兼容。毕竟它底层最终还是运行 Node,只是透传了这些 Flag。这意味着如果你的
00:03:01脚本没有使用 Node 不支持的特性,你完全可以把 `nub` 直接换成 `node`,结果
00:03:06完全一致。顺便一提,实现这一切几乎没有任何速度开销。
00:03:10它的性能表现尽可能贴近原声 Node;官方文档显示,运行一个 Nub 文件与直接
00:03:14在 Node 中运行所花费的时间几乎完全相同。我承认这不会比 Bun 更快,因为 Bun 是
00:03:19替代 Node 的原生运行时,而 Nub 只是构建在 Node 之上。我决定在我的 Mac 上
00:03:24亲自跑个基准测试,看看谁更快些。如果把排版稍微整理得更
00:03:28直观一点,可以看到对我来说原生 Node 实际上是最快的。虽然并没有
00:03:31和 Nub 完全同速,Nub 稍微落后了一点点,但 TSX 表现比它们俩都要慢。说完
00:03:36文件运行器,第二个核心特性就是 Node 版本管理器。你再也不需要 NVM 或
00:03:41FNM 了。在 Nub 中,只要项目目录下有一个名为 `.node-version` 的文件,或者在 `.nvmrc` 甚至是
00:03:46`package.json` 中定义了版本,Nub 就会自动从 Node.js 官方下载并安装所需的版本。
00:03:52目前这个项目使用的是最新的 Node 26 版本,如果我把这个文件改成
00:03:56像 24 这样的版本,然后重新用 Nub 运行,它就会自动去拉取对应的 Node 版本。它还拥有
00:04:02你所期待的所有常用管理命令,比如安装 Node 版本、列出已安装的
00:04:06版本、卸载 Node 版本,甚至支持版本锁定(version pinning)功能,它会为你写入 Node
00:04:10版本配置文件。用起来就是这么简单,下面我们来看接下来的三个特性,
00:04:15这三个功能让 Nub 能够直接替代 pnpm 和 Bun。
00:04:20首先是第三个特性,也就是纯粹的包管理器(Package Manager)。它号称比 pnpm 快 5 倍,而我原以为 pnpm 已经
00:04:25足够快了。它的用法符合直觉,用 `nub install` 来安装依赖包,但非常酷的一点是,
00:04:31它实际上可以直接兼容并继承你现有的 Lock 文件,如果你之前在项目里用过 Bun 或 pnpm,
00:04:36Nub 会直接更新现有的 Lock 文件,而不是强行生成它自己的一套。这使得在不同工具之间
00:04:41无缝无痛无缝无缝切换变得极其容易,对 pnpm 的兼容性也是如此。Nub 中的每个包
00:04:46管理命令都与 pnpm 完全相同,包括 pnpm 的高级特性,例如
00:04:51工作区目录(workspace catalogs)。它们的参数 Flag 完全一样,所以将 pnpm 替换为 Nub 应该能直接生效。如果你
00:04:57使用的是 npm、Bun 或 Yarn,这些包管理器的配置项也会被自动识别读取。
00:05:02至于速度方面的声称,官方基准测试将 Nub 评为热缓存
00:05:06冻结安装中最快的,仅需 346 毫秒即可安装 1168 个依赖包。而在我自己的机器上,我实际上测试了
00:05:1314 个直接依赖(最终解析为 212 个独立依赖包),测试结果确实证明了 Nub 是
00:05:19最快的。Nub 只用了 136 毫秒就安装好了我的依赖包,Bun 以 239 毫秒排名第二,
00:05:25而 pnpm 和 npm 实际上都花了一秒多,所以关于速度的宣传在我机器上确实成立,
00:05:30速度确实非常惊人。在安全性方面,该包管理器也继承了 pnpm 的优秀特性,
00:05:35默认设置了 24 小时的最小发布时间限制,且除非手动批准,否则不会运行构建脚本,
00:05:40因此能够抵御大多数 Shai Hulud 类的供应链攻击。包管理器的下一个亮点功能是
00:05:45执行依赖包,也就是特性 4(Package Runner),这里的最大宣传卖点是
00:05:49它比 npx 快 19 倍。`nub x` 命令实际上是直接定位到 node_modules 内部的 `.bin` 文件夹,
00:05:54在 Rust 层直接执行这些二进制文件,因此外层不会启动任何额外的 Node 包装进程,
00:05:59这也意味着它能够兼容任何包管理器,因为它只是直接调用了那些 node_modules。
00:06:03正如大多数 Nub 命令一样,它在 Flag 参数上与 `pnpm exec` 完全兼容,
00:06:07包括 `dlx` 命令也是如此。在我的 Mac 上运行基准测试,Nub 再次成为
00:06:12最快的一个,运行 esbuild 仅需 169 毫秒,而 pnpm 为 423 毫秒,所以速度优势依然明确。
00:06:20包管理器中你需要的最后一个功能是脚本运行器(Script Runner),据称这个功能
00:06:24比 `pnpm run` 快 24 倍,并且支持生命周期钩子(lifecycle hooks)、npm 环境变量,
00:06:29以及参数透传转发。当你使用 npm 或 pnpm 时,它们实际上会启动 Node.js 程序,
00:06:34每次都要加载对应包管理器的 JavaScript 代码;而 Nub 直接使用其 Rust 二进制文件,
00:06:38没有任何冷启动进程开销。我的本地基准测试再次显示 `nub run` 确实是最快的,
00:06:43不过领先优势并没有官方文档上标榜的那么夸张。同样值得一提的是(这也是我在这期视频里第四次强调了),
00:06:47这个命令在 CLI Flag 参数上与 pnpm 保持完全兼容,
00:06:51意味着它同样完美支持 pnpm 的 Monorepo 特性。针对最后这三个特性,我非常想点赞的一点是,
00:06:56Nub 并没有盲目去重复造轮子。它的底层实际上使用了
00:07:00OBE,这是一个由 JDX(同时也是 mise 的作者)编写的包管理器。
00:07:04他把这个包管理器设计成了可以被其他库嵌入的形式,Colin 与他合作将它集成到了 Nub 中,
00:07:08所以这绝不是简单的直接抄袭代码。以上就是 Nub 最核心的主打功能,
00:07:13但它还有很多值得探索的地方,比如可以完美无缝替代
00:07:17官方 `setup-node` 的 GitHub Action。它的初衷就是为了让
00:07:21Node 周边的一切变得更简单。但我现在不得不问自己一个问题:我真的会
00:07:26在日常中使用它吗?对我来说,答案是:在某些特定场景下会的。说实话,我是 Bun 的重度
00:07:31用户,而且在开发过程中还没遇到过任何兼容性问题。也许等它推出了全新的
00:07:35Rust 重构版本后我可能会迁移,但即使那样,我也倾向于继续用 pnpm 处理其他所有事情,
00:07:40而且必须承认,我从来没觉得 pnpm 有多慢。另外我还在用 mise 来管理我的 Node
00:07:44版本,所以我不觉得自己需要它这方面的功能;不过我确实很看好
00:07:48它能够替代 TSX 的文件运行器功能。在我看来,它对我来说最终极的使用场景,是
00:07:52当我使用全新的即用即抛型虚拟机时。有时候我会快速开一台虚拟机做点测试,
00:07:57如果我只想快速把 Node 环境搞定,我认为 Nub 是目前功能最完备、
00:08:01上手最快最省事的一站式方案。所以阻碍我把 Nub 当作日常主力的,主要还是因为我自己习惯成自然,
00:08:05但我很想知道大家平时都在用什么
00:08:08包管理器?如果出现了像 Nub 这样的工具,在 Bun 用 Rust 重构之后,你会不会考虑从 Bun 切换过来?
00:08:12欢迎在下方评论区告诉我,如果你还没订阅的话也顺手点个订阅吧,
00:08:16老规矩,我们下期视频再见!

Key Takeaway

由 Zod 作者 Colin 打造的 Nub 是构建在原生 Node.js 之上的 Rust 单文件工具包,通过完美兼容 pnpm 和 Node 命令行参数,以极高的执行效率全面替代 TSX、NVM、pnpm 及 npx。

Highlights

  • Nub 是基于原生 Node.js 构建的 Rust 单文件二进制工具,集成了文件运行器、Node 版本管理器、包管理器、包运行器及脚本运行器。

  • Nub 的文件运行器支持 enum、namespace、装饰器、JSX 和 `using` 关键字等高级 TypeScript 语法,无需依赖 TSX 或 ts-node。

  • Nub 包管理器在热缓存冻结安装基准测试中,仅需 136 毫秒即可解析并安装包含 212 个独立依赖包的项目,速度超越 Bun、pnpm 和 npm。

  • Nub 继承了 pnpm 的安全机制,默认设置 24 小时最小发布时间限制,且无手动批准不自动运行构建脚本,防范供应链攻击。

  • Nub 的 `nub x` 包运行器直接在 Rust 层定位并执行 node_modules 内部的二进制文件,运行 esbuild 仅需 169 毫秒。

Timeline

Nub 工具包定位与作者背景

  • Nub 是一款直接构建在原生 Node.js 上的 Rust 单文件二进制工具包。
  • 项目由 Zod 作者、tRPC 概念验证原型制作人兼前 Bun 员工 Colin 打造。

Nub 并非替代 Node.js 的新运行时,而是运行在 Node 之前的统一工具集。它整合了 TypeScript 运行器、环境配置加载器、Node 版本管理器以及包管理工具链,旨在消除 JavaScript 开发生态中工具链碎片化的问题。

全功能 TypeScript 文件运行器特性

  • 文件运行器提供超越 Node 原生类型剥离的完整 TypeScript 语法支持。
  • 自动处理环境变量加载、路径别名解析及现代 JavaScript API 补丁。
  • CLI 参数标志与原生 Node 保持 100% 兼容且几乎无性能开销。

文件运行器可直接执行包含 enum、namespace、参数属性、装饰器及 JSX 的代码文件。它内置了 dotenv 功能,支持 .env.local 优先级覆盖与变量展开,并能识别 tsconfig 中的路径别名。在尚不支持 Temporal 或 Web Workers 的 Node 版本上,Nub 会自动注入 Polyfill。

无缝集成的 Node 版本管理器

  • Nub 可根据项目配置文件自动下载并切换所需的 Node.js 版本。
  • 提供完整的版本管理 CLI 工具链,支持安装、卸载及版本锁定。

项目根目录下的 `.node-version`、`.nvmrc` 或 `package.json` 中的版本声明会被 Nub 自动读取并按需拉取对应 Node 版本。这一机制消除了对 NVM 或 FNM 等外部版本管理工具的依赖。

高性能包管理器与安全机制

  • Nub 直接继承现有 Lock 文件,完全兼容 pnpm 语法与工作区目录。
  • 在 212 个依赖包的基准测试中,Nub 以 136 毫秒的成绩成为最快的包管理器。
  • 默认启用 24 小时发布限制与构建脚本拦截,防御供应链攻击。

包管理器基于 JDX 开发的可嵌入库 OBE 构建,能更新现有 Bun 或 pnpm 的 Lock 文件而不强行生成新格式。其安全设计遵循 pnpm 标准,未经手动确认不会执行任何第三方的构建脚本。

高效率包运行器与脚本运行器

  • 包运行器在 Rust 层直接调用 Node 模块二进制文件,消除包装进程开销。
  • 脚本运行器摆脱了传统包管理器每次启动 Node 程序的冷启动延迟。
  • 所有命令参数标志与 pnpm 完全兼容,完美适配 Monorepo 架构。

`nub x` 命令跳过 Node 包装层,直接在 node_modules/.bin 目录执行二进制文件,运行 esbuild 仅用时 169 毫秒。脚本运行器凭借 Rust 二进制的轻量化特性提升了命令响应速度,并在底层深度集成了通用生态库。

应用场景与使用总结

  • Nub 最适合快速配置即用即抛型虚拟机开发环境。
  • 作为 TSX 替代品,Nub 能显著简化单文件脚本的执行流程。

对于已建立固定工具链(如 Bun、pnpm、mise)的开发者,Nub 提供了在云端服务器或一次性虚拟机中一键搭建全套 Node 基础设施的最快方案。

Community Posts

View all posts