如果你刚接触前端工程化,第一次看到 npm install、yarn install、pnpm install,大概率会有一个疑问:
它们不都是“装包”的吗?为什么会有三个?
答案是:它们做的是同一件事,但解决问题的方式不一样。
npm是 Node.js 官方自带的包管理器,历史最久,生态最稳。Yarn是在 npm 早期体验不够好的时候出现的,重点解决“慢”和“不稳定”。pnpm是在 Yarn 和 npm 继续发展之后,进一步解决“磁盘浪费”和“依赖不严谨”的问题。
这篇文章不讲太多绕人的术语,只用一条主线讲清楚:
为什么会从 npm 发展到 Yarn,再发展到 pnpm?
一、先说结论:新手该怎么理解这三个工具?
你可以先把它们理解成三个版本的“快递仓库管理系统”:
npm:最早上线,先把“包能装下来”这件事解决了。Yarn:发现 npm 早期装得慢、装得不稳,于是把流程优化了。pnpm:继续往前走,开始追求“更省空间、更快、更严格”。
所以它们并不是谁“取代”谁,而是在不同阶段针对不同痛点做优化。
如果只想先记一句话:
- 小项目、通用项目:
npm完全够用。 - 注重安装速度、磁盘空间、Monorepo:更推荐
pnpm。 Yarn依然有人用,但新项目里相较前两者已经没那么常见。
二、它们到底是干什么的?
三者本质上都是 JavaScript / Node.js 的包管理器,主要做这几件事:
- 安装依赖
- 删除依赖
- 更新依赖
- 锁定依赖版本
- 管理
node_modules
比如你写 React 项目时要安装 react、vite、axios,这些工具都会帮你从包仓库下载代码,并放到项目里可用的位置。
最常见的命令长这样:
npm install
yarn install
pnpm install
表面看它们差不多,但内部怎么存、怎么装、怎么复用依赖,差别很大。这也是为什么它们的速度、磁盘占用、依赖管理体验会不一样。
三、为什么会先有 npm,再有 Yarn 和 pnpm?
理解这件事最好的方法,不是背定义,而是看它们分别解决了什么问题。
1. npm 先解决“从无到有”
2010 年,npm 随 Node.js 一起出现。那个阶段最重要的不是“快不快”,而是:
JavaScript 终于有了一个像样的包管理系统。
开发者可以很方便地发布包、安装包、复用社区代码。这个意义非常大,Node.js 生态能爆发,npm 功不可没。
但随着项目越来越大,问题也开始暴露。
2. Yarn 解决“太慢、太不稳”
后来大家发现,早期 npm 在大型项目里有几个明显问题:
- 安装速度慢
- 依赖容易重复安装
- 不同机器安装结果不一定完全一致
于是 2016 年,Facebook 推出了 Yarn。它的重点很明确:
先把安装体验做得更快、更稳。
3. pnpm 解决“太占空间、依赖不够严格”
再往后,大家又发现一个问题:
你电脑里多个项目,往往装了大量重复依赖,但这些文件其实一模一样。
而且 npm / Yarn 早期常见的扁平化依赖结构,还会带来“幽灵依赖”问题。
于是 2017 年,pnpm 出现了。它的核心思路是:
同样的包,全局只存一份;项目里通过链接去复用。
这让它在磁盘占用、安装速度、Monorepo 场景上都非常亮眼。
四、npm 做了什么?它为什么会遇到问题?
1. npm 最早的价值:把包管理标准化
在 npm 出现之前,前端和 Node.js 世界的依赖管理非常零散。npm 出现后,开发者终于可以:
- 用统一命令安装依赖
- 通过
package.json管理项目依赖 - 从公共仓库下载别人发布的包
这个阶段的 npm,最大的贡献是:
让整个 Node.js 生态跑起来。
2. 早期 npm 的问题:依赖越多,项目越重
早期 npm 会采用更偏“嵌套”的依赖结构。简单理解就是:
每个包都可能在自己的目录里再放一份依赖。
结果就是,同一个依赖如果有多个版本,甚至相同版本,也可能在不同位置被重复安装。
像这样:
node_modules/
├── package-a/
│ └── node_modules/
│ └── package-b@1.0.0
└── package-d/
└── node_modules/
└── package-b@2.0.0
这会带来几个问题:
node_modules很大- 安装时间越来越长
- 依赖关系越来越复杂
3. npm 后来做了哪些改进?
后来 npm 也持续升级,比如:
- 使用更扁平的依赖结构,减少重复安装
- 引入
package-lock.json,让依赖版本更可控 - 持续优化安装性能
- 支持
workspaces
所以今天的 npm,已经不是“很早以前那个慢吞吞的 npm”了。
它现在依然是最通用、最稳妥、门槛最低的选择。
五、Yarn 为什么会火?它到底改进了什么?
1. Yarn 出现的背景很现实
当项目依赖变多之后,团队最怕的不是“不会装”,而是:
- 装得太慢
- 同事之间装出来结果不一样
- CI 安装耗时太久
Yarn 就是冲着这些问题来的。
2. Yarn 的几个关键改进
并行安装
早期 npm 的安装过程更偏串行,Yarn 把很多步骤并行化了,所以体感速度明显更快。
更好的缓存
Yarn 会把下载过的包缓存起来,再次安装时可以更快复用。
这对下面这些场景很有帮助:
- 频繁删除再安装依赖
- 切分支后重新安装
- CI 重复构建
yarn.lock
锁文件的意义很简单:
把“这次安装出来的精确版本”记录下来。
这样团队里每个人、包括 CI,安装结果就更一致,不容易出现:
“为什么你能跑,我这边不行?”
3. Yarn 的局限
Yarn 虽然让安装体验更好了,但它并没有彻底解决两个问题:
node_modules依然可能很大- 依赖管理仍然不够“严格”
也就是说,Yarn 主要解决的是速度和一致性,不是空间复用和依赖隔离。
六、pnpm 为什么越来越受欢迎?
如果说 npm 和 Yarn 的主要思路是“把依赖装到项目里”,那么 pnpm 更像是在说:
没必要每个项目都存一整份一样的东西。
1. pnpm 最核心的优势:省空间
假设你电脑上有 3 个前端项目,它们都用了 react、typescript、eslint。
用传统方式时,三个项目的 node_modules 里可能各有一份,浪费很明显。
pnpm 的做法是:
- 全局维护一个统一的依赖存储区
- 相同版本的包只保存一份
- 各项目通过链接方式使用这些包
所以 pnpm 的磁盘占用通常更小。
2. pnpm 为什么通常也更快?
因为它有两层优势:
- 能并行安装
- 已有包可以直接复用,不用每个项目都重新“存一遍”
尤其当你电脑里项目很多时,这种优势会越来越明显。
3. pnpm 的另一个关键点:依赖更严格
这是很多人第一次接触 pnpm 时最容易踩坑、但也是它最有价值的地方。
先看一个例子。
你的 package.json 里只写了:
{
"dependencies": {
"package-a": "^1.0.0"
}
}
但 package-a 自己依赖了 package-b。
在某些旧的依赖结构下,你可能会“误打误撞”直接这样写:
import { something } from 'package-b'
虽然你根本没有在自己的 package.json 里声明 package-b,代码却可能还能跑。
这就叫幽灵依赖。
问题在于:
它能跑,不代表它对。
一旦换环境、换工具、换版本,就可能突然出问题。
pnpm 更强调“你声明了什么,就只能用什么”,所以它更容易帮你提前发现依赖管理不规范的问题。
这也是为什么很多团队会觉得:
pnpm 一开始更严格,但长期更省心。
七、几个容易混淆的概念,顺手讲明白
1. 锁文件是什么?
锁文件就是把依赖安装结果“钉死”。
常见对应关系:
npm对应package-lock.jsonYarn对应yarn.lockpnpm对应pnpm-lock.yaml
它的价值主要有两个:
- 团队成员安装结果更一致
- CI / 线上环境更稳定
2. 什么是“幽灵依赖”?
一句话解释:
你没声明,但你居然还能用到的依赖。
这不是“方便”,而是“隐患”。
3. pnpm 里的“硬链接 / 软链接”是什么?
如果你不是很关心底层细节,可以只记住这个结论:
硬链接:多个地方看起来都有这个文件,但底层其实共享同一份内容软链接:像一个指向真实位置的快捷方式
pnpm 会利用这些机制,在兼容 Node.js 模块解析规则的同时,实现复用依赖、节省空间、严格隔离。
你不需要天天研究这些名词,但知道它们是 pnpm 的技术基础就够了。
八、三者怎么选?这是最实用的部分
很多文章讲到最后,读者还是不知道项目里到底该用哪个。这里直接给建议。
1. 如果你想要最稳妥、最省心
选 npm。
原因很简单:
- Node.js 自带
- 不需要额外安装
- 生态兼容性最好
- 大多数教程默认都能直接跑
适合:
- 新手入门
- 普通前端项目
- 对团队统一要求不高的项目
2. 如果你更在意工程效率
选 pnpm。
它特别适合:
- 依赖很多的项目
- 多项目并行开发
- Monorepo
- 希望依赖关系更严格的团队
如果你的项目已经进入“工程化”阶段,pnpm 往往是更现代的选择。
3. Yarn 什么时候会用到?
主要是两种情况:
- 老项目历史上就在用 Yarn
- 团队对 Yarn 的工具链已经很熟
如果是存量项目,通常没必要为了“追新”强行迁移。
但如果是新项目,今天大多数情况下会更倾向于在 npm 和 pnpm 之间选。
九、一个简单对比表
| 工具 | 最大特点 | 优点 | 可能的不足 | 适合谁 |
|---|---|---|---|---|
npm | 官方默认 | 上手简单、兼容性好、生态稳 | 大型项目下不一定是最优体验 | 大多数普通项目、新手 |
Yarn | 早期以速度和锁文件见长 | 体验成熟、老项目常见 | 新项目存在感相对下降 | 已在用 Yarn 的团队 |
pnpm | 省空间、严格依赖、Monorepo 友好 | 快、占用小、依赖更规范 | 初次使用时可能会暴露历史依赖问题 | 工程化项目、中大型项目 |
十、把这段历史真正记住,只要抓住一条线
你可以把它们的演进记成一句话:
npm 先解决“能不能管理包”,Yarn 解决“装得快不快、稳不稳”,pnpm 解决“占不占空间、依赖严不严”。
所以它们的关系不是谁“打败”谁,而是前端工程随着项目规模变大,不断提出新的要求:
- 要更快
- 要更稳
- 要更省
- 要更适合大型项目和 Monorepo
这也是前端工具链演进的一个缩影:
先能用,再好用,最后追求更高的工程效率。
十一、最后给一个不纠结版本的建议
如果你不想看太多历史,只想知道现在怎么选,可以直接参考:
- 想省事,选
npm - 想更现代的工程体验,选
pnpm - 老项目已经在用
Yarn,通常继续用就行
对于大部分新项目来说,这已经足够了。
如果以后你再看到这些命令:
npm install
yarn install
pnpm install
你就知道,它们表面都叫“安装依赖”,但背后代表的是三代不同的工程优化思路。