介绍
在 JavaScript 和 Node.js 开发中,包管理器是必不可少的日常工具。
虽然npm仍然是默认的行业标准,但pnpm(以节省磁盘空间和速度而闻名)和yarn(具有零安装和即插即用模式)等现代替代品提供了独特的架构。
尽管它们解析相同的 package.json 规范,但它们的内部存储结构、依赖关系解析和安全功能不同。本文对这三个包管理器进行了比较,以帮助您为下一个项目选择最佳工具。
1. 结构比较:包是如何存储的
主要区别在于每个工具如何组织本地 node_modules 目录并将包文件存储在磁盘上。
① npm(扁平的node_modules结构)
从版本 3 开始,npm 在可能的情况下将依赖关系树平渲染到 node_modules 的根中。
- 工作原理: 如果库 A 依赖于库 B,则两者都放置在
node_modules(node_modules/A和node_modules/B)的根目录下,而不是将 B 嵌套在 A 内。 - 缺点(幻像依赖):
由于库 B 位于根级别,因此您的应用程序代码可以直接导入 B,即使它未在
package.json中声明。如果库 A 更新并放弃对 B 的依赖,您的代码将崩溃,因为不再安装 B。
② pnpm(内容寻址存储和硬链接)
pnpm 使用符号链接目录结构来防止冗余。
- 工作原理: 所有包都缓存在计算机上的单个全局存储中 (
~/.pnpm-store)。在您的项目中,pnpm 创建从全局存储到node_modules/.pnpm内的嵌套布局的硬链接,通过符号链接仅将您声明的依赖项映射到node_modules的根。 - 核心优势:
- 大量节省磁盘空间: 如果十个项目使用同一版本的软件包,则该软件包仅在您的硬盘上存储一次。
- 无幻像依赖项: 由于
node_modules的根仅链接到package.json中显式声明的依赖项,因此未经授权的导入会在编译器级别被阻止。
③ 纱线(即插即用模式)
Yarn Berry (v2+) 支持 Plug'n'Play (PnP),这是一种完全绕过 node_modules 目录的模式。
- 工作原理: 依赖项作为压缩档案 (
.zip) 存储在项目缓存中。 Yarn 生成一个控制文件 (.pnp.cjs),其中包含所有依赖路径的映射。在执行过程中,Yarn 会覆盖 Node 的模块解析,直接从 zip 存档中读取文件。 - 核心优势:
- 零安装: 您可以将缓存的 zip 文件直接提交到 Git 存储库。团队成员可以克隆存储库并立即运行应用程序,而无需运行
npm install。
- 零安装: 您可以将缓存的 zip 文件直接提交到 Git 存储库。团队成员可以克隆存储库并立即运行应用程序,而无需运行
2. 特性和性能矩阵
以下是每个包管理器的主要功能的比较:
| 公制 | npm | PNPM | 纱线(PnP 模式) |
|---|---|---|---|
| 创建node_modules | 是的 | 是(带符号链接) | 否(直接压缩分辨率) |
| 本地磁盘空间 | 高(每个项目的副本) | 低(全球链接) | 低(存储为压缩zip) |
| 幻影防御 | 弱 | 强(符号链接保护) | 强(PnP 分辨率映射) |
| 安装速度 | 中等 | 快速(硬链接生成) | 即时(零安装缓存) |
3. 决策指南:选择哪一个?
为您的项目选择包管理器时请考虑以下准则:
1. 如果出现以下情况,请选择 pnpm:
- 您可以在 monorepo 结构(工作区配置)中进行开发。
- 您想节省计算机上的磁盘空间。
- 您需要在 CI/CD 管道中实现快速安装。
2. 如果出现以下情况,请选择 npm:
- 您希望避免全局工具安装(npm 与 Node.js 一起预打包)。
- 您使用的旧版构建工具(如旧版 Webpack 加载器)很难解析符号链接或嵌套路径。
- 您优先考虑最大的开箱即用生态系统兼容性。
3. 如果满足以下条件,请选择纱线 (PnP):
- 您希望实施“零安装”以消除 CI/CD 管道中的依赖项安装步骤。
- 您的团队可以轻松地为 IDE 自动完成解决方案配置自定义 SDK 插件。
结论
了解包管理器在幕后的工作原理有助于您调试导入错误并优化容器构建时间。
对于新项目,由于其安全功能和磁盘效率,pnpm 通常是推荐的起点,其次是标准 npm 以获得最大兼容性。

