npm、cnpm、yarn、pnpm

740 阅读7分钟

看了很多相关文章,对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 正在迅速加剧这种竞争。

已经进行了几个基准测试来比较这两个堆栈的速度。例如,下面这张表总结了一个测试的结果,比较了不同条件下安装一些简单依赖项的速度:

image.png

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 举个例子:项目中有packageApackageBpackageCpackageDpackageA依赖packageX 1.0和packageY 1.0packageB依赖packageX 2.0和packageY 2.0packageC依赖packageX 1.0和packageY 2.0packageD依赖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 dependenciesNPM doppelgangers问题!
  • Store + Links 解决包之间寻址和储存问题,磁盘利用效率高效
  • 天生的很好的支持workspace,可以光速建立 monorepo管理工具
  • 比npm和yarn安装包都要快
  • Electron 应用无法使用 pnpm
  • 部署在 AWS Lambda 上的应用无法使用 pnpm
  • 现在还属于小众,无论是兼容性,还是功能丰富度,社区生态,都是非常弱小的

以下为npm、yarn、pnpm对比图

功能pnpmYarnnpm
工作空间支持(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 那个好用