看了很多相关文章,对npm、cnpm、yarn、pnpm做一个总结记录。
npm&cnpm
npm(ndoe package manager)是nodejs的包管理器,用于node插件管理(包括安装、卸载、管理依赖等)cnpm因为npm安装插件是从国外服务器下载,受网络影响大,可能出现异常。所以淘宝团队使用了国内镜像来代替国外服务器,国内的淘宝镜像则称之为cnpm。其两者用法都一样
npm vs yarn
npm和yarn 历史版本
- 2010:npm 发布,支持 Node.js。
- 2016:yarn发布。它显示出比 npm 更好的性能。它还生成一个
yarn.lock文件,使 repos 的共享和精确复制变得更加容易和可预测。 - 2018 年:npm 6 发布,提高了安全性。现在 npm 在安装依赖项之前检查安全漏洞。
- 2020:Yarn 2 和 npm 7 发布。yarn 2 增加了一些新的特性,包括
workspaces,交互式命令。npm 7 重大改动,增加了workspaces,自动安装peerDependencies等 - 2021:Yarn 3 发布并进行了各种改进。npm 8 发布,改动不大,目的是放弃对那些不再维护的 Node 版本和
require(npm)
yarn vs npm:速度和性能
每当 Yarn 或 npm 需要安装一个包时,它们都会执行一系列任务。在 npm 中,这些任务是按包顺序执行的,这意味着它将等待一个包完全安装,然后再继续下一个。相比之下,Yarn 并行执行这些任务,从而提高了性能。
虽然这两个管理器都提供了缓存机制,但 Yarn 似乎做得更好一些。正如我们将在功能比较部分看到的那样,通过实现零安装范例,它几乎可以立即安装软件包。它缓存每个包并将其保存在磁盘上,因此在下次安装此包时,您甚至不需要互联网连接,因为包是从磁盘离线安装的。
尽管 Yarn 有一些优势,但 Yarn 和 npm 的速度在它们的最新版本中是相当的。所以我们不能在这里定义一个干净的赢家。
然而,最近,尤其是从 v5 和 v6 开始,npm 已经大大缩小了与 Yarn 的差距。虽然 Yarn 在大多数情况下仍然更快,但 npm 正在迅速加剧这种竞争。
已经进行了几个基准测试来比较这两个堆栈的速度。例如,下面这张表总结了一个测试的结果,比较了不同条件下安装一些简单依赖项的速度:
yarn安装特性
零安装将缓存存储在项目目录的.yarn文件夹中。当你使用yarn或等命令时yarn add <package>,Yarn 会创建一个.pnp.cjs文件。该文件包含 Node 用来加载项目包的依赖层次结构。因此,您几乎可以在零时间访问它们。
npm vs yarn远程运行脚本
该npx命令用于从./node_modules/.bin. 它还允许您从 npm 注册表执行包,而无需将它们安装在项目依赖项中。例如,您可以通过运行以下命令创建一个新的 React 应用程序:
npx create-react-app my-app
在 Yarn 中,您可以使用等效的dlx命令来获得相同的结果:
yarn dlx create-react-app my-app
我们将要探索的其他功能是 Yarn 独有的。
yarn vs npm:安全性比较
从版本 6 开始,npm 会在安装期间审核包并告诉您是否发现任何漏洞。npm audit我们可以通过对已安装的包运行来手动执行此检查。如果发现任何漏洞,npm 会给我们提供安全建议。
Yarn 和 npm 都使用加密哈希算法来确保包的完整性。
Yarn vs npm:选择哪个包管理器
我们已经介绍了 npm 和 Yarn 的各种异同,但我们还没有确定哪个更好以及应该选择哪个。与以往一样,答案取决于我们的愿望和要求。
作为一般指南,让我总结以下建议:
- 如果您对当前的工作流程感到满意、不想安装额外的工具并且没有太多磁盘空间,没办法很好的科学上网请选择 npm。
- 如果你想要一些很棒的功能,比如 Plug'n'Play,你需要一些 npm 中缺少的功能,并且你有足够的磁盘空间,请选择 Yarn。
如果你仍然觉得很难在 npm 和 Yarn 之间做出明确的决定,那么你可以检查一下pnpm,它试图结合两个包管理器的优点,并且是包管理池中的第三大鱼.
平铺依赖管理不是 node_modules 唯一的解法
所以yarn和npm则采用了平铺的方式,解决了上面的问题,也让node_modules减少了尺寸,但也随之带来了新的问题:
- Phatom dependencies(幽灵依赖) 依赖管理在 yarn 和 npm v3+ 中都是使用平铺的方式,大家平时看项目的 node_modules 也应该比较熟悉,所以yarn对npm的管理是兼容的,而平铺的依赖树会带来很多问题,其中最经典的问题就是模块可以访问它们不依赖的包,就是package.json没有的包,我也能引入。
比如说项目中依赖了A,A依赖了B,在package.json,只有A,但由于扁平管理那么在node_modules就可以看到同级的A、B:
▾ node_modules
▸ A
▸ B
这样通过 nodejs 的require的寻址特性,我们就可以直接找到B,这一点我之前也利用过这个缺陷去减少了部分依赖,但后续出现过A真的不依赖B了,也就不再用这个缺陷了。
- NPM doppelgangers
举个例子:项目中有
packageA、packageB、packageC、packageD。packageA依赖packageX 1.0和packageY 1.0,packageB依赖packageX 2.0和packageY 2.0,packageC依赖packageX 1.0和packageY 2.0,packageD依赖packageX 2.0和packageY 1.0。
在npm3+和yarn中,由于存在hoist机制,所以X和Y各有一个版本被提升了上来,目录结构如下
- package X => 1.0版本
- package Y => 1.0版本
- package A
- package B
- packageX 2.0
- packageY 2.0
- package C
- packageY 2.0
- package D
- packageX 2.0
而pnpm的依赖管理是采用了网状 + 平铺的目录结构,pnpm install 后我们可以从本地项目的 node_modules 看到,实际上pnpm 是将包装在了 node_modules/.pnpm/xx 中 使用symlink的形式去软链在 node_modules 下。
如上所示的packageX 2.0和packageY 2.0被重复安装多次,从而造成 npm 和 yarn 的性能一些性能损失。
yarn & npm vs pnpm
- pnpm 网状 + 平铺的node_modules结构解决Phantom dependencies和NPM doppelgangers问题!
Store+Links解决包之间寻址和储存问题,磁盘利用效率高效- 天生的很好的支持workspace,可以光速建立 monorepo管理工具
- 比npm和yarn安装包都要快
- Electron 应用无法使用 pnpm
- 部署在 AWS Lambda 上的应用无法使用 pnpm
- 现在还属于小众,无论是兼容性,还是功能丰富度,社区生态,都是非常弱小的
以下为npm、yarn、pnpm对比图
| 功能 | pnpm | Yarn | npm |
|---|---|---|---|
| 工作空间支持(monorepo) | ✔️ | ✔️ | ✔️ |
隔离的 node_modules | ✔️ - 默认 | ✔️ | ✔️ |
提升的 node_modules | ✔️ | ✔️ | ✔️ - 默认 |
| Plug'n'Play | ✔️ | ✔️ - 默认 | ❌ |
| 零安装 | ❌ | ✔️ | ❌ |
| 修补依赖项 | ❌ | ✔️ | ❌ |
管理 Node.js 版本(pnpm独有) | ✔️ | ❌ | ❌ |
| 有锁文件 | ✔️ - pnpm-lock.yaml | ✔️ - yarn.lock | ✔️ - package-lock.json |
| 支持覆盖 | ✔️ | ✔️ - 通过 resolutions | ✔️ |
内容可寻址存储(CAS)(pnpm独有) | ✔️ | ❌ | ❌ |
| 动态包执行 | ✔️ - 通过 pnpm dlx | ✔️ - 通过 yarn dlx | ✔️ - 通过 npx |
总结
总的来说目前pnpm解决了很多问题,包括现在一些大型的开源库也在用,如vue相关的,决定是否使用可以从以下几点考虑
- 团队的使用情况,如果大家都是用yarn,且yarn能够很好解决团队之间的协作和代码问题。
- 项目历史包袱问题,如果要重构,可以考虑使用pnpm
参考文章
NPM 与 Yarn:你应该选择哪个包管理器?
pnpm 解决了我的哪些痛点?
为什么我选择了pnpm?
都2022年了,pnpm快到碗里来!
关于现代包管理器的深度思考——为什么现在我更推荐 pnpm 而不是 npm/yarn?
npm link的使用
字节的一个小问题 npm 和 yarn不一样吗?
Yarn v2 介绍
package.json 与package-lock.json的关系
新一代包管理工具 pnpm 使用心得
npm 和 yarn 那个好用