Skip to content

🔰 bun 介绍四:自动安装依赖项,bun 立志要做一个零配置的快速框架

🕒 Published at:

bun 介绍四:自动安装依赖项,bun 立志要做一个零配置的快速框架

在 webpack 工程中,无论是使用 pnpm,还是 yarn,在运行项目之前都需要执行 pnpm i 或 yarn,这是在安装依赖项,将项目代码中引用的类库放在当前项目的 node_modules 目录下。

一般情况下,对于复杂的项目这个过程耗时会比较久,这是 Node.js 作为基础构架的痛点,也是 bun 着力解决与优化的亮点。在第一篇中,我们就已经详细介绍过了,bun 在这方面将其它包管理工具甩开了一个数量级。

但这远远还不够,bun 做的还更多。

bun 在安装速度优化之外,还提供了一个自动安装的功能。这个特征,目的在于实现零配置运行代码。对于一个 bun 项目,没有什么是不可缺失的,什么 package.json 等文件,统统都可以没有。代码即是项目本身,有代码就可以运行

下面我们深入了解一下这个自动安装的机制。

先看实现了什么效果。所谓的自动安装,就是不需要执行 bun i,直接通过 bun run 运行代码,遇到本地没有的依赖项,bun 先自己下载安装然后再运行代码。对于下面的代码:

js
// src/index.ts
import _ from "lodash";
const array = [1, 2, 3];
_.fill(array, 'a');
console.log(array); // => ['a', 'a', 'a']
// src/index.ts
import _ from "lodash";
const array = [1, 2, 3];
_.fill(array, 'a');
console.log(array); // => ['a', 'a', 'a']

项目中还没有添加过 lodash 这个类库,没关系,当我们执行 bun run 指令时:

bash
$ bun run src/index.ts
// ... installing dependency
[ "a", "a", "a" ]
$ bun run src/index.ts
// ... installing dependency
[ "a", "a", "a" ]

bun 会自动下载、安装好 lodash,然后再运行 ts 代码。这时候如果你扫一眼 index.ts 文件所在的目录,发现什么变化都没有,那下载的 lodash 放到哪里去了?(这一点后面会说。)

要实现自动安装,有几个问题需要解决:

1)什么情况下启用自动安装?

2)安装类库的哪个版本?

3)要不要下载选定的版本,从哪里下载,放在哪里?

1、什么情况下启动自动安装

先看第一个问题,bun 通过查看源码目录下是否存在 node_modules 目录,以此决定要不要启动自动安装。没有 node_modules 就启用,有则不启用。此处,官方文档说,这个开关还受到$HOME/.bunfig.toml 配置文件或项目目录下的 bunfig.toml 配置文件的制约,如果配置文件里面有一个 install.auto 等于 force 的配置节点,则会强制启用自动安装。

js
[install]
auto = "force"
[install]
auto = "force"

经实践,这个配置字段不好使。

无论将配置文件放在哪里,放在项目的目录下,还是放在$HOME 下,都不起作用。想查看自动安装的效果,目前最好使的方式是在一个空目录下放置上面 index.ts 代码,然后执行 bun run 指令,这是可以 100% 复现效果的。

如果你的项目是新项目,没有被 pnpm、yarn 等包管理工具蹂躏过,本身就没有 node_modules 目录,那么自动安装后仍然没有,也就是说,下次你仍然可以继续享用自动安装的便利。对于开发者来说,你只需要写代码就可以,想用哪个类库,直接使用 import 引入,根本不必考虑安装的问题。整个 github 上的开源类库,都在你的操控范围之内。(当然了,前提是你的网卡得能顺利访问到 github。)

2、如何确定类库版本

在代码中使用 import 语句时,我们是不能直接指定其版本的,像下面这种写法就不合法:

js
import _ from "lodash@4.0.0" // 不合法
import _ from "lodash@4.0.0" // 不合法

以后 bun 风行起来以后,或许能够推动修改 JS 标准,使上述这行代码成立。目前,当 bun 发现正常运行代码需要 lodash 类库时,它会依次从三个地方询问版本:

1)先看项目中的 bun.lockb 文件。如果本项目安装过 lodash 这个类库,则 bun.lockb 文件一定会有记录,里面有明确的版本。为了保证一个项目中引用同一个类库的版本保持一致,此处直接使用缓存过的版本。bun.lockb 文件并不一定是自己执行 bun add 指令产生的,如果我们的项目代码是从团队仓库中拉出来的,这个 bun.lockb 文件可能是同事产出的。使用同事已经验证过的类库版本,是保证团队协作顺利进行的基本准则,同时也是不需要言明就存在的准则。

2)如果没有 bun.lockb 文件,那就看看 package.json 文件。如果这是一个使用过 pnpm 或 yarn 的旧项目,它可能有一个 package.json 文件,里面的 devDependencies 节点或 dependencies 节点记录了本地项目的依赖项,找到 lodash,取其版本即可。

3)如果 package.json 中也没有记录 lodash 的版本,最后一招,就只有默认使用 latest 版本了。

3、如何下载与缓存

确定了版本,就是下载了。

1)从本地全局缓存目录下查找 lodash 的指定版本,这个全局缓存目录默认位于~/.bun/install/cache,在这个目录下查找<pkg>@<version>,如果找到了就直接使用。这里还有一个特殊情况,如果在上一步指定的版本是 latest,在这一步则要求上一次下载的时间不能超过 24 小时,如果超过了则不能使用,要视为未找到版本对待。

这里可能会产生未知 Bug,当团队中的两个人使用同一个类库并且均是以 latest 确定版本的情况下,有可能两个人实际使用的版本不一致。同一个项目在不同的协作者手里使用不一致的版本,这本身就是风险,尽管这种风险概率很小,但它确实有可能存在。为此,在团队开发中,使用版本明确的类库版本是一项基本准则,第一个建立项目的人,一定要将版本写明在 package.json 里面,或者保留在 bun.lockb 文件里。一些开发者可能看 bun.lockb 这个文件名字奇怪,而将它打入.gitignore 冷宫中,这是错误的行为。

在明确版本的时候,要使用 4.0.0 这样明确的版本号,而不要使用^4.0.0这样的版本号。后者版本号中的尖括号在正则表达式中是“开始”的意思,在这里也可以理解为“开始”,意思是大于等于某个版本,这样的版本号一般称为 semver range version,它是一个范围,范围版本是不适宜在项目中直接使用的。

2)如果从本地全局缓存中没有取到想要的类库版本,就必须从外网下载了。bun 从 npm 的软件源下载类库的指定版本。bun 立志要做零配置运行的快速框架,在开始的时候它可以没有任何配置,它直接使用了 npm 中配置的软件源,这是它作为后起之秀的优势。如果要配置 bun 自己的软件源,或实现软件源地址国产化,可以在$HOME/.bunfig.toml 文件中修改 install.registry 配置节点:

bash
[install]
registry = "http://registry.npm.taobao.org"
[install]
registry = "http://registry.npm.taobao.org"

3)如果从外网下载不了,那项目就运行不下去了,本地研发中止。不过看过前面的介绍,你也发现了,对于团队协作,直接将同事的全局仓库缓存拷贝过来也是可以的,这还可以大大节省下载的时间。

有人甚至提议将本地全局缓存设置成某个局域网的共享目录,大家维护同一个缓存,不要这样做。这个目录不仅有读取,还有写入,两个人同时写入可能会发现意想不到的错乱。宁肯在一个地方缓存,然后分发给所有人,也好过所有人都有权限维护它,这是 CDN 分发的思维。

4、最佳实践

最后说一下最佳实践。

既然 bun 有自动安装的功能,就要用起来,不要再让项目目录动辄就有几百上千 MB 的大小,团队里第一个创建项目的人,使用 bun add 指令创建好 bun.lockb 文件并随项目源码分享给他人。同事只需拿到 bun.lockb 文件就可以了,本地的 package.json 与 node_modules 都不需要有。但是这里有一个问题需要注意,这个 bun.lockb 是二进制格式的,这意味着如果团队中有两个以上的人同时维护了该文件,那么文件冲突便没有办法解决了,所以最好这个 bun.lockb 文件由项目的 owner 负责维护,其它人仅负责拉取就可以了。