Yarn 与 pnpm:其他包管理工具
🎯 引言
学会这篇文章,你将知道除了 NPM 之外,前端开发中常用的 Yarn 和 pnpm 是什么,它们各自解决了什么问题,以及如何在不同项目中做出合适的选择。
🧱 为什么需要其他包管理工具
NPM 是 Node.js 自带的包管理工具,功能完善,生态成熟。但随着项目变大、依赖变多,大家也发现了一些痛点:
- 安装速度慢:NPM 早期版本串行下载依赖,大项目安装很耗时。
- 磁盘占用大:每个项目的
node_modules都独立保存一份相同的包,重复文件很多。 - 依赖结构不确定:不同时间执行
npm install,可能会得到略有不同的依赖树。
Yarn 和 pnpm 就是为了解决这些问题而生的替代方案。它们和 NPM 共用同一个包仓库(npm registry),所以包的来源是一样的,只是安装和管理方式不同。
✨ Yarn
Yarn 是 Facebook 于 2016 年推出的包管理工具,目标是解决当时 NPM 安装慢、不稳定的问题。
主要特点
- 并行下载:多个包同时下载,速度比早期 NPM 快很多。
- 锁文件
yarn.lock:锁定依赖精确版本,保证团队安装一致。 - 离线模式:下载过的包会缓存,断网时也能复用。
- 工作区(Workspaces):方便管理 monorepo(一个仓库多个包)。
常用命令
# 安装项目全部依赖
yarn install
# 安装指定包
yarn add dayjs
yarn add dayjs@1.11.13
# 安装开发依赖
yarn add eslint -D
# 卸载包
yarn remove dayjs
# 运行脚本
yarn dev
yarn build
yarn dev 等价于 npm run dev,yarn add 等价于 npm install。⚡ pnpm
pnpm 是近年来非常流行的包管理工具,名字代表 performant npm(高性能 NPM)。它在速度、磁盘占用和依赖管理严格性上做了大量优化。
主要特点
- 内容可寻址存储:所有包只在本机保存一份,不同项目通过硬链接共用,极大节省磁盘空间。
- 非扁平 node_modules:默认使用严格的依赖树结构,避免“幽灵依赖”问题。
- 安装速度快:由于大量复用本地缓存,重复安装时速度非常快。
- 原生 workspaces 支持:内置 monorepo 多包管理能力。
常用命令
# 安装项目全部依赖
pnpm install
# 安装指定包
pnpm add dayjs
pnpm add dayjs@1.11.13
# 安装开发依赖
pnpm add eslint -D
# 卸载包
pnpm remove dayjs
# 运行脚本
pnpm dev
pnpm build
🪤 什么是幽灵依赖
幽灵依赖(Phantom Dependencies)是指:你的代码里直接 import 或 require 了一个包,但这个包并没有写在你的 package.json 里,而是被其他依赖“顺便”带进来的。
举个例子
假设你的项目只显式安装了 element-plus:
{
"dependencies": {
"element-plus": "^2.9.0"
}
}
而 element-plus 内部依赖了 vue 和 @popperjs/core。在 NPM 或 Yarn 的扁平 node_modules 结构下,这些间接依赖会被提升到 node_modules 的顶层:
node_modules/
├─ element-plus/
├─ vue/ ← 被提升上来了
└─ @popperjs/core/ ← 也被提升上来了
于是你的代码可以这样写,并且能正常运行:
import { createApp } from 'vue'; // ⚠️ vue 不在 package.json 里!
问题就出在这里:
- 你的
package.json里没有vue,但代码却依赖了它。 - 一旦
element-plus升级后不再依赖vue,或者换成别的版本,你的代码就会直接报错。 - 换一台电脑、换一个包管理工具,依赖树的提升结果可能不同,导致“我电脑上能跑,你电脑上不能跑”。
这种“看不见、管不住”的依赖,就是幽灵依赖。
🛡 pnpm 如何解决幽灵依赖
pnpm 默认采用非扁平的 node_modules 结构,只把你在 package.json 里显式声明的包放到顶层:
node_modules/
├─ element-plus/ ← 只有你自己安装的包
└─ .pnpm/ ← 其他依赖被严格隔离在这里
├─ vue@3.x/
└─ @popperjs/core@x.x/
在这种结构下,如果你试图 import vue,pnpm 会直接告诉你找不到这个模块,因为 vue 不在顶层。
import B,除非你自己也安装了 B。这种设计能避免很多隐式依赖问题。如果你想在项目中使用 vue,就必须显式安装:
pnpm add vue
这样 vue 会写入 package.json,你的依赖关系就变得清晰、可控,不会再出现幽灵依赖。
🧰 什么是 Workspaces 和 Monorepo
Monorepo 是指把多个相关项目或包放在同一个 Git 仓库里管理。比如一个组件库仓库里同时包含:
packages/ui:UI 组件源码packages/utils:工具函数apps/docs:文档站点
Workspaces 就是包管理工具提供的“多包管理”能力。开启 workspaces 后,你可以在仓库根目录执行一次安装,同时管理多个子包的依赖,子包之间还可以互相引用。
pnpm workspaces 示例
在仓库根目录创建 pnpm-workspace.yaml:
packages:
- 'packages/*'
- 'apps/*'
然后执行:
pnpm install
pnpm 会自动识别 packages 和 apps 下的所有子项目,统一安装依赖。相比 Yarn,pnpm 的 workspaces 与它的存储机制结合得更好,安装速度更快、磁盘占用更小。
⚖️ NPM、Yarn、pnpm 对比
| 特性 | NPM | Yarn | pnpm |
|---|---|---|---|
| 出品方 | Node.js 官方 | Facebook(现 Meta) | 社区开源 |
| 安装速度 | 较快(v5 以后改进明显) | 快 | 很快 |
| 磁盘占用 | 大 | 大 | 小(内容可寻址存储) |
| 锁文件 | package-lock.json | yarn.lock | pnpm-lock.yaml |
| 依赖结构 | 扁平 | 扁平 | 非扁平,更严格 |
| 幽灵依赖问题 | 容易出现 | 容易出现 | 基本避免 |
| workspaces | 支持 | 支持 | 原生支持,效率更高 |
| 推荐场景 | 通用,Node.js 默认自带 | 大项目、monorepo | 追求速度、严格依赖管理、monorepo |
💡 如何选择
选 NPM 的情况
- 你是初学者,不想额外安装工具。
- 项目规模不大,NPM 已经完全够用。
- 团队统一使用 NPM,避免工具混用。
选 Yarn 的情况
- 项目依赖很多,希望安装速度更快。
- 团队已经在用 Yarn,保持统一。
- 需要使用 Yarn 的 workspaces 管理 monorepo。
选 pnpm 的情况
- 电脑磁盘空间有限,希望节省空间。
- 项目依赖复杂,希望避免幽灵依赖问题。
- 团队追求更快的安装速度和更严格的依赖管理。
package-lock.json、yarn.lock、pnpm-lock.yaml,否则会造成依赖不一致。🛠 在项目中切换工具
如果你接手了一个用 pnpm 的项目,但电脑上没有安装 pnpm,可以先全局安装:
npm install pnpm -g
当前课程环境使用的 pnpm 版本为 10.6.2,你可以在安装时指定版本以保证一致:
npm install pnpm@10.6.2 -g
安装完成后,用 pnpm -v 检查版本,然后就可以使用 pnpm install 安装项目依赖了。
🧾 小节总结
- NPM、Yarn、pnpm 都基于同一个 NPM 仓库,只是安装和管理策略不同。
- Yarn 以并行安装和
yarn.lock著称,适合大项目和 monorepo。 - pnpm 以内容可寻址存储和严格依赖树著称,能避免幽灵依赖,速度快、磁盘占用小。
- workspaces 是管理 monorepo 多包的能力,pnpm 在这方面原生支持更好。
- 选择工具要看团队习惯和项目需求,一个项目不要混用多种锁文件。
❓ 知识问答
Q1:Yarn 和 pnpm 能安装 NPM 仓库里的包吗?
A:可以。它们都兼容 NPM 仓库,包的来源完全相同。
Q2:yarn.lock 和 pnpm-lock.yaml 需要提交到 Git 吗?
A:需要。它们和 package-lock.json 作用一样,都是用来锁定依赖版本的。
Q3:pnpm 为什么能节省磁盘空间?
A:pnpm 把所有下载过的包放在全局存储中,不同项目通过硬链接共用同一份文件,而不是每个项目都复制一份。
Q4:什么是幽灵依赖?
A:幽灵依赖是指代码里直接使用了某个包,但这个包并没有写在你的 package.json 里,而是通过其他依赖被“顺便”安装进来的。一旦那个间接依赖升级或移除,你的代码就会报错。
Q5:pnpm 为什么能避免幽灵依赖?
A:pnpm 使用非扁平的 node_modules 结构,只有 package.json 里显式声明的包才能被直接引用。没有被显式安装的包无法被代码直接 import。
Q6:一个项目可以同时用 NPM 和 pnpm 吗?
A:不建议。混用会导致锁文件不一致,团队成员安装的依赖版本可能不同。
🧪 小练习
- 查看你当前电脑是否安装了 Yarn 或 pnpm:
# 请在这里输入命令
- 尝试用 pnpm 安装
dayjs@1.11.13:
# 请在这里输入命令
- 观察项目根目录,看看生成了哪个锁文件。
🎉 恭喜你了解了 Yarn 和 pnpm!至此,NPM 课程已经全部学完。你可以根据项目需求,灵活选择合适的包管理工具了。
