锁文件
本教程共 34 篇 · 第 12 篇 · 更新于 2026-08-06
本节目标:
- 弄清
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:只调用真正必要的系统调用,并针对不同平台选用
clonefile、sendfile、faccessat、memfd_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 依赖,以及带完整性哈希的补丁依赖。
Notepnpm 的迁移会额外处理
pnpm-workspace.yaml:把工作区包列表、catalog:目录(catalogs)以及overrides/patchedDependencies配置,对应搬到根package.json的workspaces、overrides等字段。该迁移只在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 里归一化后的 cpu 与 os 字段,连同解析出的包一起记下。这意味着:即使不同平台最终安装的包内容不同(例如某个原生包只在 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.lock 和 bun.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.lockb用bun install --save-text-lockfile --frozen-lockfile --lockfile-only+ 删除旧文件即可迁移;npm/yarn/pnpm 锁文件会被bun install自动迁移。 --frozen-lockfile(CI 严格模式)、--lockfile-only、--no-save、--yarn是日常最常用的几个控制开关。
下一章我们进入 monorepo 场景,看看 Bun 的 Workspaces 如何组织多个相互依赖的包。