DevToolBox免费
博客

npm vs yarn vs pnpm vs bun:2026 年该选哪个包管理器?

10 分钟阅读作者 DevToolBox

选择正确的 JavaScript 包管理器可以显著影响你的开发工作流、CI/CD 流水线速度和磁盘使用量。2025 年的四大主要竞争者是 npmYarnpnpmBun。每个都有不同的理念和权衡取舍。本综合指南从所有重要维度对比这四个工具:速度、磁盘效率、monorepo 支持、安全性和开发者体验。

什么是 JavaScript 包管理器?

包管理器自动化了在项目中安装、更新、配置和删除第三方库(包)的过程。它解析依赖树,通过锁文件管理版本,并提供构建和测试代码的脚本。

每个现代 JavaScript 项目都依赖于一个包管理器。它们之间的差异初看可能很小,但在大型代码库、monorepo 和 CI 流水线中会逐渐累积。让我们深入了解每一个。

npm:默认标准

历史和背景

npm(Node Package Manager)由 Isaac Z. Schlueter 于 2010 年创建,自 Node.js 0.6.3 版本起与 Node.js 捆绑发布。它是每个 Node.js 开发者开箱即用的默认包管理器。npm 注册表托管了超过 200 万个包,是世界上最大的软件注册表。

核心特性

  • 与 Node.js 捆绑——零配置,安装了 Node.js 就可用
  • npm workspaces——从 npm 7 开始内置 monorepo 支持
  • npm ci——为 CI 环境提供确定性的快速安装(删除 node_modules 并从锁文件安装)
  • npm audit——内置安全漏洞扫描
  • npx——无需全局安装即可执行包
  • Overrides——强制指定依赖版本以解决冲突
  • Provenance——npm 现在支持包来源证明,增强供应链安全

优点

  • 零安装——随 Node.js 一起提供
  • 最大的生态系统和社区
  • 优秀的文档
  • 稳定且经过实战检验
  • workspaces 支持 monorepo
  • npm audit 安全扫描

缺点

  • 四个管理器中安装速度最慢
  • 较高的磁盘使用量——每个项目都会复制一份所有依赖
  • 历史上存在安全问题(虽然已大幅改善)
  • node_modules 可能变得极其庞大("宇宙中最重的物体"梗)
# 安装依赖
npm install

# 添加包
npm install express

# 安装开发依赖
npm install --save-dev typescript

# CI 优化安装
npm ci

# 运行脚本
npm run build

# 不安装直接执行包
npx create-react-app my-app

Yarn:创新的先驱

历史和背景

Yarn 由 Facebook(现 Meta)于 2016 年创建,旨在解决当时 npm 的不足:非确定性安装、默认无锁文件、性能缓慢。Yarn 引入了 yarn.lock 文件和并行下载,大幅提升了安装速度。如今,Yarn 存在两个版本:Yarn Classic (1.x)Yarn Berry (2.x+),它们本质上是不同的工具。

Yarn Classic (1.x)

Yarn Classic 的工作方式类似于 npm,但性能更好,锁文件更可靠。它使用扁平的 node_modules 目录结构并支持 workspaces 用于 monorepo。虽然仍被广泛使用,但 Yarn Classic 已进入维护模式——团队建议迁移到 Yarn Berry。

Yarn Berry (2.x+) 和 Plug'n'Play

Yarn Berry 是一次完全重写,引入了 Plug'n'Play (PnP),一种彻底消除 node_modules 目录的激进方法。它生成一个 .pnp.cjs 文件,将包名映射到压缩的 .yarn/cache 文件夹中的位置。这带来了:

  • 近乎即时的安装——无需将数千个文件复制到 node_modules
  • 严格的依赖解析——防止幻影依赖(访问你未声明的包)
  • 零安装——将缓存提交到 git,在 CI 中完全跳过 npm install
  • 大幅减少磁盘使用

核心特性

  • Plug'n'Play (PnP)——消除 node_modules,通过 .pnp.cjs 映射依赖
  • 零安装——将缓存提交到仓库,在 CI 中跳过安装
  • Workspaces——一流的 monorepo 支持(首创此概念)
  • Constraints——在工作区间强制执行规则(例如所有包必须使用相同的 React 版本)
  • 插件——通过插件系统扩展架构
  • 离线模式——使用缓存的存档在无网络环境下安装包

优点

  • PnP 提供最快的安装速度和最小的磁盘占用
  • 零安装完全消除 CI 安装步骤
  • 出色的 monorepo 支持,包含 workspaces 和 constraints
  • 严格的依赖解析能捕获幻影依赖问题
  • 插件系统提供扩展性

缺点

  • PnP 与某些包和工具存在兼容性问题
  • 学习曲线较陡,特别是从 npm 迁移时
  • 两个差异很大的版本(Classic vs Berry)容易混淆
  • 社区比 npm 小
  • 某些 IDE 集成需要额外配置才能支持 PnP
# 安装依赖
yarn install

# 添加包
yarn add express

# 添加开发依赖
yarn add --dev typescript

# 运行脚本
yarn build

# 交互式升级
yarn upgrade-interactive

# 启用 PnP(Yarn Berry)
yarn set version berry
yarn install

pnpm:磁盘空间冠军

历史和背景

pnpm(performant npm)由 Zoltan Kochan 于 2017 年创建,旨在解决 npm 和 Yarn Classic 固有的磁盘空间问题。它的核心创新是内容寻址存储系统:每个包的每个版本在磁盘上只存储一次,项目通过链接指向这些共享副本。如果 10 个项目使用 lodash@4.17.21,你的机器上只有一份副本。

内容寻址存储详解

当你运行 pnpm install 时,pnpm 不会将包复制到每个项目的 node_modules 中。相反,它创建一个全局存储(通常在 ~/.local/share/pnpm/store),每个唯一文件按其内容哈希存储。你项目的 node_modules 包含指向此存储的硬链接(或 Windows 上的符号链接)。这意味着:

  • 大量磁盘节省——包只全局存储一次,而非每个项目一份
  • 更快的安装——文件是链接的,不是复制的
  • 严格的 node_modules 结构——默认防止幻影依赖
  • 完整性验证——内容寻址意味着文件通过哈希验证

核心特性

  • 内容寻址存储——全局存储加硬链接,大幅节省磁盘
  • 默认严格模式——只有声明的依赖才可访问(无幻影依赖)
  • pnpm workspaces——出色的 monorepo 支持,包含过滤和并行执行
  • 副作用缓存——缓存 postinstall 脚本输出以加速后续安装
  • 补丁——内置 pnpm patch 命令,无需 fork 即可修补依赖
  • Catalogs——在工作区包之间定义共享依赖版本

优点

  • 最佳磁盘空间效率——在多项目机器上节省数 GB 空间
  • 快速安装(特别是有热存储的第二次安装)
  • 默认严格依赖解析
  • 出色的 monorepo 工具,支持过滤命令
  • npm 的直接替代品(类似的 CLI 命令)
  • 积极开发和不断增长的社区

缺点

  • 需要单独安装(未与 Node.js 捆绑)
  • 硬链接可能使某些工具和文件监视器混淆
  • 严格模式可能破坏依赖幻影依赖的包
  • 社区和生态系统比 npm 或 Yarn 小
  • 某些托管平台没有内置 pnpm 支持
# 安装 pnpm
npm install -g pnpm
# 或使用 corepack(推荐)
corepack enable
corepack prepare pnpm@latest --activate

# 安装依赖
pnpm install

# 添加包
pnpm add express

# 添加开发依赖
pnpm add -D typescript

# 运行脚本
pnpm run build

# 检查磁盘使用节省
pnpm store status

Bun:全能运行时

历史和背景

Bun 由 Jarred Sumner 创建,于 2023 年 9 月发布 1.0 版本。与其他三个不同,Bun 不仅仅是包管理器——它是一个全能 JavaScript/TypeScript 运行时,包含包管理器、打包器、测试运行器和转译器。使用 Zig 从头构建(使用 JavaScriptCore 而非 V8),Bun 专为最大性能而设计。

核心特性

  • 极速安装——用原生代码编写,通常比 npm 快 10-25 倍
  • 全能运行时——一个工具替代 Node.js、npm、webpack/esbuild 和 Jest
  • 原生 TypeScript 支持——直接运行 .ts 文件,无需编译步骤
  • npm 兼容——读取 package.json,使用 node_modules,兼容 npm 注册表
  • 内置打包器——为生产环境打包 JavaScript/TypeScript
  • 内置测试运行器——使用 bun test 进行 Jest 兼容的测试
  • 热重载——使用 --hot 标志的内置监视模式
  • Node.js 兼容——实现大多数 Node.js API 以进行直接替换

优点

  • 包安装速度最快,优势显著
  • 全能工具减少工具链复杂性
  • 原生 TypeScript 执行,无需配置
  • 大多数项目可直接替换 Node.js
  • 内置打包器和测试运行器
  • 积极开发,快速改进

缺点

  • 相对较新——在生产环境中的实战检验较少
  • 不是 100% Node.js 兼容(某些边缘情况和原生模块可能不工作)
  • 社区较小,Stack Overflow 答案较少
  • Windows 支持是后来添加的,可能存在一些粗糙之处
  • Monorepo 支持不如 pnpm 或 Yarn 成熟
  • 某些带有原生插件的 npm 包可能无法用 Bun 编译
# 安装 Bun
curl -fsSL https://bun.sh/install | bash
# 或在 Windows 上
powershell -c "irm bun.sh/install.ps1 | iex"

# 安装依赖
bun install

# 添加包
bun add express

# 添加开发依赖
bun add --dev typescript

# 运行脚本
bun run build

# 直接运行 TypeScript 文件
bun run server.ts

# 运行测试
bun test

并排对比

特性npmYarn (Berry)pnpmBun
首次发布20102016(Berry:2020)20172023(1.0)
编写语言JavaScriptJavaScriptJavaScriptZig + C++
安装速度(冷启动)快(PnP:非常快)非常快
磁盘使用高(每项目复制)低(PnP)/ 高(Classic)非常低(共享存储)中等(node_modules)
锁文件package-lock.jsonyarn.lockpnpm-lock.yamlbun.lockb(二进制)
Monorepo 支持Workspaces(基础)Workspaces + ConstraintsWorkspaces + 过滤Workspaces(基础)
幻影依赖防护是(PnP)是(默认严格)
Node.js 捆绑否(使用 corepack)否(使用 corepack)否(自身是运行时)
安全审计npm audit(内置)yarn auditpnpm audit未内置
离线模式基于缓存零安装(优秀)基于存储基于缓存
依赖补丁通过 overridesyarn patchpnpm patchpatch-package

安装速度基准测试

以下基准测试基于典型的中型项目(约 500 个依赖),在现代机器上运行。时间为近似值,会因网络条件、缓存状态和硬件而异。

场景npmYarn (Berry)pnpmBun
冷安装(无缓存)~45s~25s~20s~5s
热安装(有缓存)~20s~1s(零安装)~5s~2s
CI 安装(干净环境)~35s(npm ci)~15s~12s~4s
添加单个包~8s~4s~3s~1s
注意:基准测试仅供参考。请务必用你自己的项目进行测试,因为结果会因依赖树形状、网络速度和操作系统而有显著差异。

迁移指南

在包管理器之间切换通常很简单。以下是每条迁移路径的关键步骤。

从 npm 迁移到 pnpm

pnpm 被设计为 npm 的直接替代品,迁移很简单:

# Step 1: Install pnpm
corepack enable
corepack prepare pnpm@latest --activate

# Step 2: Remove npm artifacts
rm -rf node_modules package-lock.json

# Step 3: Install with pnpm
pnpm install

# Step 4: Update scripts in package.json
# Replace "npm run" with "pnpm run" in CI configs

# Step 5: Add packageManager field
# "packageManager": "pnpm@9.x.x"

从 npm 迁移到 Yarn Berry

迁移到 Yarn Berry 需要更多步骤,特别是如果你想使用 PnP:

# Step 1: Enable Yarn via corepack
corepack enable
yarn set version berry

# Step 2: Remove npm artifacts
rm -rf node_modules package-lock.json

# Step 3: Install with Yarn
yarn install

# Step 4: Configure PnP (optional but recommended)
# Add to .yarnrc.yml:
# nodeLinker: pnp

# Step 5: Add SDK for your editor
yarn dlx @yarnpkg/sdks vscode

# Step 6: Add to .gitignore
# .yarn/*
# !.yarn/cache
# !.yarn/patches
# !.yarn/plugins
# !.yarn/releases
# !.yarn/sdks
# !.yarn/versions

从 npm 迁移到 Bun

Bun 读取你现有的 package.json,可以直接使用 npm 的注册表:

# Step 1: Install Bun
curl -fsSL https://bun.sh/install | bash
# Windows: powershell -c "irm bun.sh/install.ps1 | iex"

# Step 2: Remove npm artifacts
rm -rf node_modules package-lock.json

# Step 3: Install with Bun
bun install

# Step 4: Update scripts
# Replace "node" with "bun" in scripts
# Replace "npm run" with "bun run"
# Replace "npx" with "bunx"

# Step 5: Test everything
bun test
bun run build

通用迁移建议

  • 充分测试——迁移后运行完整的测试套件
  • 更新 CI/CD——更新流水线配置以使用新的包管理器
  • 锁文件——在生成新锁文件之前删除旧锁文件;永远不要有两个锁文件
  • 团队对齐——确保团队中的每个人同时切换
  • corepack——使用 corepack enable 在团队中一致管理包管理器版本
  • Engines 字段——在 package.json 中添加 packageManager 字段以强制使用正确的包管理器

何时使用哪个:建议

使用 npm 当...

  • 你想要零配置——npm 随 Node.js 提供,无需额外安装
  • 你在处理中小型项目,安装速度不是关键
  • 你是初学者,想要最大的社区来解决问题
  • 你的团队不想学习新工具
  • 你需要与教程、指南和 Stack Overflow 答案的最广泛兼容性

使用 Yarn Berry 当...

  • 你想要最快的 CI 流水线,使用零安装
  • 你运行大型 monorepo,需要 constraints 来强制一致性
  • 你想要严格的依赖解析来捕获幻影依赖问题
  • 你的团队愿意投入时间学习 PnP 并解决兼容性问题
  • 离线开发能力对你的工作流很重要

使用 pnpm 当...

  • 磁盘空间是一个考虑因素——你在一台机器上有很多项目
  • 你想要一个比 npm 更快更高效的直接替代品
  • 你运行 monorepo,想要强大的过滤和并行执行
  • 你想要严格的依赖解析,但不想要 PnP 的学习曲线
  • 你正在为生产构建,想要一个经过验证的稳定工具

使用 Bun 当...

  • 原始速度是你的首要优先级
  • 你想要一个全能工具(运行时 + 包管理器 + 打包器 + 测试运行器)
  • 你正在启动一个新项目,可以容忍一些兼容性边缘情况
  • 你正在构建 TypeScript 项目,想要原生 TS 执行
  • 你愿意成为早期采用者,帮助塑造生态系统

对于 2025 年的大多数团队,pnpm 在速度、磁盘效率和兼容性方面提供了最佳平衡。如果你从头开始并想要最前沿的性能,Bun 值得评估。如果你已经使用 npm 且一切正常,没有紧迫的切换需要——npm 在最近的版本中已经显著改善。

使用 Corepack 管理包管理器

Corepack 是从 Node.js v16.9.0 起捆绑的工具,让你无需全局安装即可管理 Yarn 和 pnpm 版本。它确保团队中的每个人都使用完全相同版本的包管理器。

以下是使用 Corepack 的方法:

# Enable corepack (bundled with Node.js 16.9+)
corepack enable

# Use a specific Yarn version
corepack prepare yarn@4.1.0 --activate

# Use a specific pnpm version
corepack prepare pnpm@9.0.0 --activate

# Verify the active version
yarn --version
pnpm --version

在 package.json 中添加 packageManager 字段以强制使用特定版本:

{
  "name": "my-project",
  "version": "1.0.0",
  "packageManager": "pnpm@9.1.0",
  "engines": {
    "node": ">=18.0.0"
  }
}

常见问题

pnpm 比 npm 快吗?

是的,pnpm 在大多数场景下比 npm 快得多。冷安装时,pnpm 通常比 npm 快 2-3 倍。热安装时(当全局存储已有包时),pnpm 可以快 4-5 倍,因为它只需要创建硬链接而不是复制文件。在共享相同依赖的多项目机器上,速度优势更加明显。

Bun 可以作为 Node.js 的直接替代品吗?

对于大多数应用,是的。Bun 实现了大部分 Node.js API,包括 fs、path、http、crypto 等。但是,一些原生 Node.js 模块(使用 node-gyp/N-API)可能不工作,Node.js API 中还有一些 Bun 尚未实现的边缘情况。在将生产应用从 Node.js 切换到 Bun 之前,务必充分测试。

什么是幻影依赖,为什么它很重要?

幻影依赖是你的代码导入但未在 package.json 中列出的包,它恰好存在于 node_modules 中,因为它是你某个已声明依赖的依赖。这在 npm 的扁平 node_modules 结构中碰巧可以工作。当间接依赖被更新或删除时就会出问题,意外地破坏你的代码。pnpm 和 Yarn PnP 默认防止幻影依赖,使你的依赖树显式且可靠。

应该将锁文件提交到 git 吗?

绝对应该。锁文件(package-lock.json、yarn.lock、pnpm-lock.yaml 或 bun.lockb)确保每个开发者和 CI 服务器安装完全相同的依赖版本。没有它,你可能会遇到由不同依赖解析导致的"在我机器上可以工作"的 bug。始终提交你的锁文件,永远不要将其添加到 .gitignore。

可以在用 npm 设置的项目中使用 pnpm 或 Yarn 吗?

可以。pnpm 和 Yarn 都可以读取你现有的 package.json。要迁移,删除 node_modules 和旧锁文件(package-lock.json),然后运行新包管理器的安装命令(pnpm install 或 yarn install)。新工具会生成自己的锁文件。迁移后充分测试你的应用以确保一切正常。

为什么 Bun 的锁文件是二进制而不是文本?

Bun 使用二进制锁文件(bun.lockb)是为了性能——二进制文件比基于文本的格式(如 JSON 或 YAML)读写更快。代价是你不能在 PR 中轻松查看或对比它。你可以使用 bun install --yarn 生成 yarn.lock 风格的可读文本文件,或使用 bun.lockb --hash 验证完整性。从 Bun 1.1+ 开始,你还可以使用 bun install --save-text-lockfile 生成基于文本的 bun.lock 文件。

𝕏 Twitterin LinkedIn
这篇文章有帮助吗?

保持更新

获取每周开发技巧和新工具通知。

无垃圾邮件,随时退订。

试试这些相关工具

{ }JSON FormatterYMLYAML Validator & Formatter.gi.gitignore Generator

相关文章

JSON vs YAML vs TOML:你应该用哪种配置格式?

比较 JSON、YAML 和 TOML 配置格式,了解语法、特性和优缺点,选择适合你项目的格式。

npm install 错误大全:每个常见错误及解决方法

修复所有 npm install 错误:EACCES、ERESOLVE、ENOENT、EPERM 等。附故障排查流程图。