
Bun 1.4 相关讨论里最抓眼球的一幕是一次性删掉 15 个项目依赖。命令敲下去终端几乎不需要停顿package.json、bun.lockb、node_modules 就完成了同步。对常年被 npm install 和 Maven 依赖问题卡住的人来说这种体验很反常识。其实 Bun 能“秒删依赖”核心不是删除动作本身而是它把依赖管理里的很多步骤提前做完了。这篇文章会沿着 Bun 依赖管理的命令、机制、验证、排查和最佳实践展开既讲怎么用也讲为什么快还会补充在生产环境里容易踩的坑。1. 先厘清一个前提Bun 的依赖管理到底管什么1.1 包管理器要解决的三个核心问题无论是 npm、pnpm、Yarn 还是 Bun依赖管理都必须解决三个问题解析、锁存、落地。解析是根据 package.json 里的声明去 registry 拿元数据算出当前应该安装哪个版本锁存是把解析结果固定下来防止不同时间安装出不同版本落地是把依赖包实际放到 node_modules 或者系统缓存里让代码能 import 到。传统工具的问题恰恰是这三步都必须依赖整个依赖图。比如 npm 在执行 install 时经常需要对几十个包做网络请求每请求一个包又要去读它的 dependencies再继续请求下一层。项目只要稍微复杂时间就会成倍增加。Maven 和 Gradle 类似也需要从远程仓库拉 POM 和 jar 包如果网络源不稳定就会出现依赖缺失、无法安装的问题。Vue、Flutter、Docker 安装场景里的依赖报错根源也大多是版本约束、网络、缓存和生命周期脚本之间的冲突。很多基于 .deb 的 Linux 环境安装 mysql 或 onlyoffice 时会出现“依赖关系不满足 fonts-dejavu”或“无法安装 libaio1”这类错误在 Python 项目里服务端忽略了 requirements.txt代码一启动就 ModuleNotFoundError在 Flutter 工程里不同插件版本约束互相冲突依赖一直拉不下来。这些表面问题不同底层都落在“解析-锁存-落地”三个环节里。Bun 做依赖管理时并没有发明新的依赖理论而是把这三个环节用原生代码高度并行地实现同时把中间步骤简化到最少。1.2 Bun 将“安装、运行、打包”整合成一条链路Bun 不只是包管理器它还是 JavaScript 和 TypeScript 运行时、测试运行器和打包器。这种一体化直接影响依赖机制的设计Bun 不需要通过 Node.js 进程来驱动 npm 脚本它的包管理逻辑和运行时共享同一套模块解析策略。安装依赖时它可以直接处理 JS、TS、JSON 甚至 wasm 的导入路径运行时遇到 import 时能直接命中 Bun 自己的安装布局。这也是为什么 Bun 的问题看起来更少它安装出来的 node_modules 布局是和它的运行时互相匹配的。反观 npm既要考虑 Node 老版本的模块解析又要兼容各种工具链把入口要求追加进去很多无关工作都会被塞进安装流程。1.3 不要神化“秒删”要把它当成设计目标的结果“秒删 15 个依赖”这个现象不是某个命令单独调优出来的而是 Bun 把包管理整体设计成“少做事”的结果。它安装时不做多余解析、删除时不需要重建整棵依赖树所以命令看起来像“删文件”而不是“重新安装”。这一点会直接影响后面理解 bun.lockb 和缓存的作用。2. 准备实验环境先能在本地跑起 Bun 1.4 的依赖命令2.1 安装 Bun 并确认版本在 macOS 或 Linux 上推荐使用官方安装脚本curl -fsSL https://bun.sh/install | bash在 Windows 上可以通过 PowerShell 或 npm 安装powershell -c irm bun.sh/install.ps1 | iexnpm install -g bun安装完成后先确认当前使用的版本bun --version如果你在项目里同时安装了 npm 和 bun建议先明确当前 CLI 是哪个避免命令回调到不同路径。文章里出现的命令以 Bun 主流版本行为为基础具体小版本如果与官方 release notes 不一致要以官方文档为准。2.2 初始化一个带 15 个依赖的实验项目为了还原“一次删掉 15 个依赖”的场景可以先创建一个空项目mkdir bun-remove-demo cd bun-remove-demo bun init -ybun init 会生成 package.json、入口文件等基础结构。接下来添加 15 个纯 JS 依赖用这些依赖模拟一个依赖关系比较杂的项目bun add lodash axios dayjs chalk commander express fast-glob glob minimist nanoid react react-dom uuid zod yaml命令执行完后package.json 的 dependencies 会出现 15 项。这里选择的包彼此没有强依赖关系更适合做“纯删除操作”的时间对比不会因为某个子包绑定其它依赖而导致结果失真。2.3 安装并生成锁文件再执行一次标准的安装命令bun install命令完成后项目目录下会出现 bun.lockb。这个文件是二进制的不建议直接编辑也不适合交给普通文本合并工具处理。如果项目之前用的是 package-lock.json切换到 bun install 之后旧的 lockfile 不会被自动纳入 bun 的锁文件体系从切换这一刻开始建议只维护 bun.lockb。2.4 用 time 感受一次真实删除现在可以复现“秒删 15 个依赖”的操作time bun remove axios chalk commander dayjs express fast-glob glob lodash minimist nanoid react react-dom uuid zod yaml观察三个地方package.json 里 dependencies 中对应的 15 项已经消失。bun.lockb 被重新生成或更新。node_modules 里对应的包目录不再存在。同样的删除操作如果用 npm 来执行往往需要对剩余依赖重新做一次解析和磁盘扫描项目越复杂差异越明显。这里的“秒删”并不代表 0 毫秒而是说 Bun 在删除时不需要重建整棵依赖树。3. 核心命令与参数拆解从 install 到 pm3.1 bun install 的常用参数bun install 负责把 package.json 里声明的依赖安装到本地。它常用参数如下参数作用学习环境建议生产环境建议--production只安装 dependencies跳过 devDependencies不常用构建镜像时常用--frozen-lockfile锁文件有变化就报错保证可复现不常用CI 中必须使用--verbose输出详细安装日志排查问题时使用不建议默认开启--force忽略已有缓存强制重新下载缓存疑似损坏时使用谨慎使用在 CI 流水线里推荐这样使用bun install --frozen-lockfile --production3.2 bun add加依赖时控制版本范围bun add 负责新增依赖。它支持常见的包名写法bun add zod bun add zod3 bun add -d typescript第一条命令添加最新版本第二条锁定在 3.x 大版本内第三条把依赖写到 devDependencies。命令执行后package.json 和 bun.lockb 会同步更新。这里要特别注意bun add 不是简单往 package.json 塞一个字段它会真正解析这个包及其传递依赖并把结果写进锁文件。3.3 bun remove一次删除多个依赖这是“秒删 15 个依赖”的直接操作命令。基本用法bun remove pkg...它支持一次传入多个包名。执行删除时大约会做三件事从 package.json 中删除对应的直接依赖声明。更新 bun.lockb去掉与该包相关的锁存条目。清理 node_modules 中对应该包的目录和索引。与直觉不同bun remove 不会立刻扫描磁盘上的所有嵌套 node_modules 来“清扫垃圾”。它只处理直接关联的部分其它空间留到后续的缓存回收或 install 操作再处理。这也是它速度感更强的原因之一。有两点容易误解如果 react 仍然被项目里的其它包间接依赖bun remove react 只会移除 package.json 里的直接声明不能保证把 react 从所有引用中彻底清走。如果包名拼写错误Bun 会提示未找到对应的直接依赖不会静默成功。3.4 bun update控制版本漂移bun update 用来按 package.json 里的 semver 范围更新依赖bun update bun update zod bun update --latest第一种会更新所有依赖到当前声明范围内允许的最新版本第二种只更新指定包第三种会忽略 semver 范围直接升到 registry 上的最新版本。第三种操作风险最高因为 major 版本升级往往包含破坏性变更运行时会很快暴露问题但排查成本也不低。推荐策略是小步更新一次只更新一个或几个包然后跑测试确认再继续下一批。3.5 bun pm查看缓存和依赖树pm 子命令提供了和依赖管理相关的辅助能力bun pm ls bun pm cache bun pm binbun pm ls 会输出当前项目的依赖列表或依赖树。当怀疑某个包没有安装成功时先看它是否在列表里。bun pm cache 能显示全局缓存的路径配合缓存清理能解决不少“改了代码却没生效”的假象。bun pm bin 会打印可执行文件所在目录适合排查命令行工具找不到的问题。如果依赖丢失可以用这些命令确认到底缺的是哪个层级再决定是重装单个包还是清理缓存后完全重装。4. 为什么快从实现机制看“删除 15 个依赖”4.1 原生执行引擎减少进程启动开销Bun 使用 Zig 和 C 编写核心逻辑包管理逻辑内嵌在运行进程里。执行 bun remove 时不需要像 npm 那样再拉起一个 Node.js 进程、初始化完整事件循环、加载一堆 npm 自身模块因此仅进程启动开销就低很多。对一次性命令来说这条优势非常明显。npm 的项目越用越慢一部分原因就是每次命令都要经历完整启动流程和依赖加载Bun 把常用操作编译成紧凑的原生代码启动路径短指令数量也更少。4.2 node_modules 扁平布局与全局缓存Bun 在安装依赖时依赖全局缓存。如果某个包已经在缓存里bun install 不需要再次下载。它在项目 node_modules 中落地的速度主要取决于文件系统操作而不是网络。Bun 的 node_modules 布局整体上是扁平的顶层目录和 package.json 的直接依赖一一对应。删除包时只需要确认它在顶层目录中的索引可以被移除再更新锁文件里的相关条目不需要对整棵依赖树重新做一次递归解析。这也是“秒删”的直观原因。注意这里不能把 Bun 的缓存机制和“所有安装都瞬间完成”画等号。冷缓存时第一个项目的安装仍然要下载大量包快的是缓存命中后的增量操作。4.3 二进制锁文件是整个依赖图的结果缓存bun.lockb 采用二进制格式把解析结果按 Bun 内部数据结构直接序列化。相比 JSON 文本格式读取和反序列化的成本更低。执行 bun remove 时Bun 在确认要删除的包之后只需要修改锁文件里相关条目的引用再对 node_modules 做增量清理不需要回到 registry 重新查询版本。这个设计目标是让锁文件成为“依赖图的结果缓存”而不是一份可以手工阅读的账本。带来的代价是二进制文件不便于自动 diff 和 merge团队协作时需要统一工具链。4.4 并行化下载、解析与校验Bun 使用多线程并发处理网络请求和文件操作。在大项目里它可以在一个安装任务里同时请求多个包而不是像一些传统工具那样串行遍历依赖队列。删除依赖时并行校验多个包的依赖关系也能节省时间。这个速度优势在冷缓存、新机器上最明显。热缓存时更多体现为文件系统操作和锁文件更新时间差距会缩小但整体仍然比传统工具轻快。5. 生产环境落地的真实问题为什么“快”反而要小心5.1 二进制锁文件不能像 JSON 那样通用混用工具会冲突bun.lockb 是二进制格式直接 diff 或 merge 都不方便。如果团队里一部分人用 npm一部分人用 Bun两个包管理器会各自生成不同锁文件互相覆盖后出现不可复现的安装结果。建议团队统一包管理器。如果遇到 npm 工程师在分支里更新了 package.jsonBun 用户需要重新执行 bun install 生成新 bun.lockb并把这个变更明确写进提交说明。不要把 package-lock.json 和 bun.lockb 同时维护成两套事实。5.2 lifecycle scripts 策略影响原生模块某些 npm 包依赖 postinstall 脚本去下载二进制、编译原生模块比如 sharp、esbuild、node-sass 等。Bun 出于安全考虑不会默认允许所有包执行 lifecycle scripts。如果该包没有写进 trustedDependencies 白名单install 可能看上去成功实际运行时却找不到对应二进制文件。安装这类依赖时可以使用 Bun 对包或包名的信任配置bun add sharp如果发现缺少二进制可以尝试重新安装并把该包加入受信任列表bun add sharp --trusted在生产构建里不要把“所有包都信任”当成默认值。白名单应该只放行确实需要脚本的包这样能减少供应链脚本被滥用时的风险面。5.3 全局缓存不是一劳永逸坏缓存会造成假阳性如果某个依赖在全局缓存里损坏bun install 可能直接使用坏文件导致运行时出现莫名的模块缺失或版本错位。排查时可以清掉缓存再重装bun pm cache rm但不要一上来就清缓存。先看报错信息确认是不是某个包的完整性有问题再决定是否清理。生产环境里频繁清理全局缓存会拖慢每一次安装不是推荐做法。5.4 workspace 与 monorepo 场景Bun 支持 workspace。在根 package.json 声明{ workspaces: [packages/*] }运行 bun install 会同时解析所有子包。此时在根目录执行 bun remove 删除共享依赖没有特殊问题但如果要删除某个子包里的依赖应该在对应子包目录里执行并确认其它 workspace 没有引用它。稍不留神会在 CI 中出现“本地能跑流水线里找不到依赖”的现象。5.5 生产镜像里的构建注意点使用 Docker 部署时建议使用 Bun 官方镜像并在构建阶段明确安装模式FROM oven/bun:1 AS builder WORKDIR /app COPY package.json bun.lockb ./ RUN bun install --frozen-lockfile --production COPY . . CMD [bun, run, start]生产阶段不应该依赖开发机缓存。构建镜像时尽量使用 frozen-lockfile 保证可复现镜像构建完成后可以通过清理缓存或利用镜像层回收来控制体积。不要为了“看起来更快”而在生产镜像里重复安装全套 devDependencies。6. 依赖管理的通用最佳实践不只是 Bun 的事6.1 锁文件必须进版本库无论使用什么包管理器锁文件都是可复现安装的底线。对于 Bunbun.lockb 应该提交到 git并纳入分支保护。如果锁文件总在变化说明当前流程里存在不稳定因素比如混用包管理器、Bun 版本不一致或者某些依赖使用了不固定的版本范围。在每次提交前可以问自己一句如果 CI 在完全干净的环境里执行相同命令能拿到和我本地一样的依赖图吗锁文件是回答这个问题的关键。6.2 把“学习环境”和“生产构建”分开学习时为了省时间可以依赖全局缓存、临时目录直接改 package.json 再 install。生产构建必须满足以下条件固定近期验证过的 Bun 版本。使用 frozen-lockfile 阻止隐性变更。不依赖开发机缓存。在干净环境验证一次冷安装。检查锁文件变更的触发原因。这样能避免“我本地没问题但服务器装不出同一套依赖”的经典事故。6.3 升级策略小步走单包验证推荐“大版本锁定小版本更新”。示例bun update zod bun add axios^1.2.3不要盲目执行 bun update --latest更不要在 CI 里自动升级全部依赖。依赖升级不是包管理器一个命令能解决的问题它涉及到 API 兼容性、运行行为变化和安全影响应该交给人工测试来把控。6.4 安全维度依赖审计与白名单Bun 生态的安全工具仍在快速演进。对安全要求高的项目建议在 CI 中叠加 npm audit 或 OSV-Scanner 等工具扫描锁文件对引入的依赖做许可和来源评估。维护 trustedDependencies 白名单时只放行确实需要 scripts 的包并记录放行理由。依赖安全不是一次检查就能结束的事。新依赖加入时要做一次评估已依赖包出现新漏洞时也要能快速定位到使用位置。6.5 可复用检查清单依赖相关的检查可以按这个顺序过一遍bun --version 与团队定义版本是否一致。项目里是否存在多个包管理器在同时维护 lockfile。bun install --frozen-lockfile 能否在干净目录通过。package.json 中是否有长期未被引用的历史依赖。CI 是否依赖本地缓存或开发机环境。trustedDependencies 白名单是否最小化。需要编译原生模块的依赖能否在生产基础镜像里完成构建。安全扫描报告是否存在高危漏洞是否有关联任务跟进。7. 常见问题排查从现象到解决方案7.1 错误现象与处理表现象常见原因检查方式处理建议bun.lockb 不断变化混用 npm/pnpm 或 Bun 版本不一致查看 git diff确认触发命令统一团队包管理器与 Bun 版本bun install 后仍缺模块lifecycle scripts 未执行查看 install 日志中的跳过记录添加 --trusted 允许必要脚本原有 Node 项目 import 失败module 解析路径与需求不匹配打印错误堆栈查看 node_modules 结构根目录重新执行 bun install或用 Bun runtime 启动安装过程 SIGKILL内存不足或扫描文件过多查看系统日志或容器资源限制减小并发、增加内存、清理缓存postinstall 下载二进制失败网络源不可达或证书异常单独执行对应脚本验证配置镜像源、网络策略、离线缓存bun update 后服务启动报错major 版本破坏性变更查看 release notes 与运行日志锁回版本逐个升级并补测试7.2 排错链路依赖问题的排查顺序应该从“输入是否正确”开始逐步向“环境是否可用”推进先确认执行的命令和上下文包名是否拼写错误是否在正确的 package.json 目录里执行。再看日志Bun 的报错通常会指明模块或文件位置。验证锁文件是否干净运行 bun install --frozen-lockfile如果失败说明锁文件与 package.json 不一致。尝试用 bun pm cache 查看缓存状态确认缓存路径是否异常。检查权限、磁盘空间、网络源和 registry 配置。仍然无解时删除 node_modules 和 bun.lockb 重新安装。这个操作只适合本地确认安全后再执行。其中最容易忽略的是第 3 步。很多人遇到依赖问题后先清缓存或重装结果发现根因是 lockfile 已经和 package.json 失配重装只会把问题掩盖一段时间。7.3 从 npm 项目迁移到 Bun 的注意迁移的第一步不是删掉旧锁文件而是先备份。推荐顺序提交当前项目的 package-lock.json 与 node_modules 状态。备份现有 node_modules再执行 bun install。对比本地运行结果确认行为差异。如果项目使用 C 插件、Electron 或者某些依赖绝对路径查找Bun 的模块解析可能和 Node 不同。不要一次迁移全部项目先挑一个非核心服务验证真实场景。迁移后最常出现的疑问是“为什么本地能跑CI 跑不了”。这时要同时检查 Bun 版本、node_modules 缓存、lockfile 差异、系统依赖和权限设置。Bun 1.4 能不能在每台机器上都做到秒删 15 个依赖取决于缓存、网络、项目复杂度和文件系统。但它给依赖管理带来的真正价值是把安装、运行、构建之间的偏差压缩到最小。拿到命令之后建议先做一次最小的 15 依赖实验把 bun remove、bun add、bun install 和 bun.lockb 的行为摸清楚再分批迁移到真实项目里。版本、脚本、锁文件和团队规范这四件事比任何性能数据都更值得长期维护。