首页 / Bun 入门教程 / 锁文件

Bun 入门教程

锁文件

本教程共 34 篇 · 第 12 篇 · 更新于 2026-08-06

Bun锁文件bun.lockbun.lockb文本锁文件可复现依赖锁定迁移

本节目标:

  • 弄清 bun.lock 是什么、为什么从 v1.2 起默认变成文本(JSONC)格式
  • 理解文本锁相比旧二进制 bun.lockb 在评审、diff、工具兼容上的实际好处。
  • 掌握从 bun.lockb 以及 npm/yarn/pnpm 锁文件迁移到 bun.lock 的方法。
  • 会用 --frozen-lockfile--lockfile-only--no-save--yarn 等标志控制锁文件行为。

12.1 什么是 bun.lock

每次运行 bun install,Bun 都会在项目根目录生成一份锁文件 bun.lock。它记录了当前解析出的精确依赖树(每个包的具体版本、来源、完整性信息等),作用和其他包管理器的锁文件一致:让团队里每个人、每次 CI、每次部署都安装到完全一样的依赖组合。

官方文档对”是否要提交到 git”的回答非常干脆:要(Yes)。锁文件应该和 package.json 一起纳入版本控制。

Note

从 Bun v1.2 开始,bun.lock 默认就是文本格式(本质是带注释的 JSON,即 JSONC,和 tsconfig.json 同理)。在此之前的版本,默认锁文件是二进制的 bun.lockb;新版本依然兼容读取 bun.lockb,但新建项目不会再默认生成它。

12.2 为什么改成文本格式

在 Bun v1.1.39 之前,Bun 的锁文件是二进制文件 bun.lockb。团队从 npm/yarn/pnpm 迁移过来后,反馈最集中的一点就是:二进制锁文件在 pull request 里很难审阅——你无法在 GitHub 上直观地看到改了哪些依赖;合并冲突极难解决;外部工具也读不了二进制内容。

Bun 团队曾经提供过 bun ./bun.lockb 来生成一份兼容 yarn.lock 的文本文件作为折中,但”真相来源”始终是二进制文件,工具链、GitHub、冲突解决都绕不开它。于是他们引入了文本锁 bun.lock(via bun install --save-text-lockfile),并在 v1.2 把它设为默认。

文本格式的 bun.lock 带来的实际好处:

  • GitHub 原生渲染 diff:评审 PR 时能直接看到依赖的增删改,而不是一段乱码。
  • VSCode 语法高亮:社区已为 bun.lock 提供了高亮支持。
  • 工具可读:任何能解析 JSONC 的程序都能读取它,依赖机器人(如 Dependabot)也更容易接入。
  • 合并更友好:文本冲突可以像普通代码一样人工解决,Git 的三方合并也能介入。
Tip

如果你拿到一份 bun.lockb 想快速看看里面有什么,可以运行 bun ./bun.lockb 把它转成可读的 yarn.lock 风格文本来查看(这不会改变锁文件本身)。

12.3 文本锁的内部优化

有一点需要澄清:Bun 安装快,并不是因为”用了二进制锁文件”。Bun 团队明确表示,他们不接受性能回退,文本锁的引入没有牺牲速度,反而让”缓存安装”在某些基准上更快(官方博客提及文本锁相比旧二进制锁使缓存安装再快约 30%)。

其底层优化主要来自工程层面,例如:

  • Structure of Arrays(数组结构):解析依赖树时,避免为每个包、每个依赖反复分配嵌套对象,而是用”索引 + 大数组”的方式线性序列化。这样把大量小对象的内存分配从 O(N³) 量级降下来。
  • 小字符串优化:包名、版本号这类大量出现的小字符串,用内联存储避免逐个独立分配。
  • 谨慎的 I/O:只调用真正必要的系统调用,并针对不同平台选用 clonefilesendfilefaccessatmemfd_create 等专用接口。

换句话说,无论锁文件是二进制还是文本,这些优化都生效。从 bun.lockb 迁到 bun.lock,你得到的是”可读”与”好维护”,而不是”变慢”。

12.4 升级旧的 bun.lockb

如果你手上的工程还在用二进制锁文件,推荐这样迁移到文本锁:

bun install --save-text-lockfile --frozen-lockfile --lockfile-only
rm bun.lockb

这条命令会在不改动 node_modules 的前提下,依据现有的 bun.lockb 生成文本版 bun.lock(保留解析结果与元数据),然后你可以删掉旧的 bun.lockb。官方文档也提到:只要 bun.lock 存在,后续 bun install 就会以它为准,忽略 bun.lockb

Warning

迁移前请确保锁文件对应的依赖状态是你认可的版本。删除 bun.lockb 之后,若想回退就只能重新生成,请确保新锁文件已通过评审再提交。

12.5 从 npm / yarn / pnpm 自动迁移

对于没有 bun.lock 的工程,bun install自动识别并迁移下列锁文件:

  • yarn.lock(v1)
  • package-lock.json(npm)
  • pnpm-lock.yaml(pnpm)

迁移时,原始的锁文件会被保留不动,你可以核对无误后再手动删除。覆盖的范围包括包版本、解析信息、依赖关系、peer 依赖,以及带完整性哈希的补丁依赖。

Note

pnpm 的迁移会额外处理 pnpm-workspace.yaml:把工作区包列表、catalog: 目录(catalogs)以及 overrides / patchedDependencies 配置,对应搬到根 package.jsonworkspacesoverrides 等字段。该迁移只在 bun.lock 不存在时触发,目前没有”退出”开关,且要求 pnpm 锁文件版本 ≥ 7、各工作区包都有 name 字段。

12.6 控制锁文件的常用标志

日常工作中,有几个和锁文件相关的标志很实用:

bun install --lockfile-only     # 只生成/更新 bun.lock,不安装到 node_modules
bun install --no-save           # 安装但不写锁文件
bun install --frozen-lockfile   # 严格按 bun.lock 安装,若与 package.json 不一致则报错
  • --lockfile-only 适合”先定版依赖树、稍后再装”的场景。注意它仍会把 registry 元数据、git/tarball 依赖填充进全局缓存。
  • --frozen-lockfile 是 CI 里的关键开关(也等价于下一章会提到的 bun ci),保证构建可复现。
  • 想额外再写一份 Yarn 风格的锁文件(方便混合工具链),加 --yarn,或在 bunfig.toml 里写:
[install.lockfile]
# 在 bun.lock 之外,额外写一份非 Bun 锁文件,目前只支持 "yarn"
print = "yarn"

12.7 与平台无关的特性

bun.lock 还会把 npm 里归一化后的 cpuos 字段,连同解析出的包一起记下。这意味着:即使不同平台最终安装的包内容不同(例如某个原生包只在 linux 上取 x64 构建),锁文件本身在不同平台/架构之间也不会变化,便于统一提交与比对。

12.8 合并冲突与常见问题

多人协作的仓库里,bun.lock 出现冲突几乎是必然的——两个人各自加了依赖,合并时同一段区域被双方都改过。文本锁的好处在于你有得选,而不是像二进制锁那样只能干瞪眼。

  • 最省事、也最推荐的做法:不要逐行去调和冲突块。先无脑接受任意一边(例如 git checkout --theirs bun.lock),确认 package.json 本身已经正确合并,然后在项目根目录重跑一次 bun install,让 Bun 依据合并后的依赖声明重新推导出锁文件,最后提交。这一步几乎总是正确的,因为锁文件本质上是 package.json推导产物,而不是需要手工维护的真相来源。
  • 需要人工判断的情况:当两边分别把同一个依赖升到了不兼容的大版本时,重跑安装并不能替你做决定。这时应该先在 package.json 里明确定下要哪个版本,再走上面的流程。

在 CI 里,如果想按锁文件内容来缓存依赖,bun pm hash 系列命令会很实用:

bun pm hash          # 计算并打印当前锁文件的哈希
bun pm hash-print    # 打印 bun.lock 中已存储的哈希
bun pm hash-string   # 打印用于计算该哈希的原始字符串

bun pm hash 的输出当作缓存 key,锁文件没变时就能直接命中缓存、跳过整轮安装;锁文件一变,key 随之改变,缓存自然失效。这比用 package.json 的哈希做 key 要准确得多,因为间接依赖的变化只会反映在锁文件里。

Q:bun.lockbun.lockb 同时存在会怎样?

bun.lock 优先生效,bun.lockb 会被忽略。但不建议长期让两份并存:不同分支、不同 Docker 构建阶段可能校验的是不同的依赖图,很容易出现”本地明明没问题、CI 就是装错版本”这类让人抓狂的现象。迁移完成后就把旧文件删掉,并把这次删除也一并提交进版本库。

Q:锁文件可以手工编辑吗?

技术上当然可以,它就是一份 JSONC。但强烈不推荐。修改依赖版本的正确入口始终是”改 package.json + 重跑 bun install”;直接手改锁文件很容易让记录的完整性哈希与实际包内容对不上,安装时才报错,反而更难排查。

Q:锁文件应该被 code review 吗?

应该,但方式要对。你不需要逐行读完几千行 diff,重点看两类信号:有没有出现你完全不认识的新包(可能是某个依赖悄悄引入的传递依赖),以及有没有依赖发生了大版本跳变。这正是当初从二进制换成文本格式想要换来的能力。

12.9 小结

  • bun.lock 是 Bun 的锁文件,自 v1.2 起默认文本(JSONC)格式,应提交到版本库以保证可复现。
  • 文本锁解决了旧二进制 bun.lockb 在审阅、diff、工具兼容、冲突解决上的痛点,且没有牺牲安装速度
  • 旧的 bun.lockbbun install --save-text-lockfile --frozen-lockfile --lockfile-only + 删除旧文件即可迁移;npm/yarn/pnpm 锁文件会被 bun install 自动迁移。
  • --frozen-lockfile(CI 严格模式)、--lockfile-only--no-save--yarn 是日常最常用的几个控制开关。

下一章我们进入 monorepo 场景,看看 Bun 的 Workspaces 如何组织多个相互依赖的包。