Bun

自动安装

如果在工作目录或更高级别的目录中未找到 node_modules 目录,Bun 将放弃 Node.js 风格的模块解析,转而支持 Bun 模块解析算法

在 Bun 风格的模块解析下,所有导入的包都会在执行期间动态地自动安装到全局模块缓存中(与 bun install 使用的缓存相同)。

import { foo } from "foo"; // install `latest` version

foo();

首次运行此脚本时,Bun 将自动安装 "foo" 并将其缓存。下次运行脚本时,它将使用缓存的版本。

版本解析

为了确定要安装哪个版本,Bun 遵循以下算法

  1. 检查项目根目录中是否存在 bun.lock 文件。如果存在,则使用 lockfile 中指定的版本。
  2. 否则,向上扫描目录树,查找包含 "foo" 作为依赖项的 package.json。如果找到,则使用指定的 semver 版本或版本范围。
  3. 否则,使用 latest

缓存行为

一旦确定了版本或版本范围,Bun 将

  1. 检查模块缓存中是否存在兼容版本。如果存在,则使用它。
  2. 当解析 latest 时,Bun 将检查 package@latest 是否在最近 24 小时 内被下载并缓存。如果是,则使用它。
  3. 否则,从 npm 注册表下载并安装相应的版本。

安装

包被安装并缓存到 <cache>/<pkg>@<version> 中,因此同一包的多个版本可以同时缓存。此外,在 <cache>/<pkg>/<version> 下创建一个符号链接,以便更快地查找缓存中存在的所有包版本。

版本指定符

通过在导入语句中直接指定版本或版本范围,可以绕过整个解析算法。

import { z } from "zod@3.0.0"; // specific version
import { z } from "zod@next"; // npm tag
import { z } from "zod@^3.20.0"; // semver range

优势

这种自动安装方法在以下几个方面很有用

  • 空间效率 — 依赖项的每个版本在磁盘上只存在一个位置。与每个项目的冗余安装相比,这节省了大量的空间和时间。
  • 可移植性 — 为了共享简单的脚本和 gist,您的源文件是自包含的。无需将包含代码和配置文件的目录 zip 在一起。通过 import 语句中的版本指定符,甚至不需要 package.json
  • 便捷性 — 无需在运行文件或脚本之前运行 npm installbun install。只需 bun run 即可。
  • 向后兼容性 — 因为 Bun 仍然尊重 package.json 中指定的版本(如果存在),所以您可以使用一个命令切换到 Bun 风格的解析:rm -rf node_modules

局限性

  • 没有智能感知。IDE 中的 TypeScript 自动完成依赖于 node_modules 内部类型声明文件的存在。我们正在研究各种解决方案。
  • 不支持 patch-package

常见问题解答

这与 pnpm 的做法有何不同?

这与 Yarn Plug'N'Play 的做法有何不同?

这与 Deno 的做法有何不同?