在不切换到 Bun 的情况下让 Node.js 变得快速便捷
Bun 和 Deno 引擎重新诠释了大家熟悉的 JS 开发体验。原生的 TypeScript 支持、即时启动测试、响应式包管理器,这些都树立了新的质量标杆。然而,并非所有人都准备将实际生产环境迁移到新的运行时。特定的 C++ 插件、模块行为的细微差异以及长期积累的遗留代码,使得大多数项目仍然停留在经典的 Node.js 上。
Nub 项目团队决定采用不同的方式。他们没有创建另一个独立的运行时,而是用 Rust 编写了一个工具来增强标准 Node.js。
核心理念
开发者经常在项目中堆砌大量工具:运行 TypeScript 的有 4 到 5 个,Node.js 版本管理的有 6 到 7 个,包管理的 8 个,还有环境变量的 9 个。结果是,在代码真正开始执行之前,运行任何脚本都会产生数百毫秒的延迟。
Nub 将所有这些功能整合到一个 Rust 二进制文件中。该工具充当开发者与 Node.js 之间的透明层。内部的 V8 和标准模块保持不变,但所有周围的工具都以编译代码的性能运行。
0运行 TypeScript 和自动版本选择
10 命令无需任何构建工具配置即可执行 11、12、13、14、15 等格式。
在底层,它使用快速的 Oxc Rust 解析器。对于转译和正确的路径解析(包括 16 和不带扩展名的导入),Nub 利用了现代 Node.js 的扩展点:17 预加载和 18 机制。
版本管理方面有一个有趣的特性。启动文件时,Nub 会检查 19 文件、20 或 22 中的 21 部分。如果所需的 Node 版本在本地不可用,该工具会将其下载到缓存并通过它执行代码。
1Nub 还会自动移除新版本 Node.js 特性的实验性标志。使用 23、24 或 25 时无需指定 CLI 标志即可立即使用。
加速脚本和启动二进制文件
每次调用 26 或 27 时,都会启动一个完整的 Node.js 进程,仅仅是为了读取 28 并调用相应的 shell 脚本。等待 JS 环境初始化会造成明显的瓶颈。
由于 29 是用 Rust 编写的,没有 JavaScript 初始化阶段。脚本可以即时被拾取。
在开发者的基准测试中,通过 30 热启动一个脚本大约需要 14 毫秒。作为对比,31 约为 330 毫秒,而 32 超过 440 毫秒。
33 工具的工作方式类似,替代了 34 和 35。当从 36 调用二进制文件时,它不会创建额外的中间 Node.js 进程,速度比 37 快约 19 倍。
2如果某个包在本地不可用,38 会从注册表下载它,执行后删除临时创建的文件。
包管理器和 Corepack 支持
39 命令处理依赖获取。它基于 Aube 引擎构建,可以与现有的 lock 文件兼容模式工作。
如果你进入一个使用 40 的项目,Nub 会尊重 pnpm 设置,读取 41 并构建没有冲突的依赖图。对于使用 42 或 43 的项目同样适用。
安装包时的几项安全特性:
- 默认自动阻止 44 脚本。
- 在依赖图解析期间根据 osv.dev 漏洞数据库检查包版本。
- 最低发布年龄限制为 24 小时,以防止供应链攻击。
对于多版本包管理器的工作,45 命令可用。它为 46、47 和 48 创建全局 shim。这是从 Node.js 25 版本开始被移除的 Corepack 的有用替代品。
实际使用
该工具不需要更改项目结构或放弃现有基础设施。你可以全局安装它,仅用于快速调试或运行本地 CLI 工具。
3在 GitHub Actions 流水线中,标准的 49 替换为 50。这提供了一致的接口,并通过快速缓存和依赖安装加速构建步骤执行。
总结
对于那些欣赏 Bun 的便利性但面临技术限制无法离开 Node.js 的团队来说,Nub 是一个很好的折中方案。该工具整合了分散的 CLI 工具集合,加速了日常命令,并且不需要你重写任何一行代码。
这个项目还很新,但已经在 GitHub 上积累了约 3.8k 星。即使只是为了即时 51 执行和方便的 Node.js 版本自动下载,也值得一试。
相关项目