JavaScript包管理器NPM 与 YARN 与 PNPM的区别

January 20, 2024

什么是包管理器

包管理器是处理计算机软件包的安装、升级和删除的软件。

包管理器将包存储在硬盘或网络驱动器的中心位置。它允许多个用户共享包的单个副本。

包管理器,如 npm install 和 yarn add,通常是基于 CLI 的。通常,JavaScript 应用程序有许多依赖项,这些依赖项由包管理器管理。

Node 默认使用 NPM。但是,NPM 没有一些高级功能非常适合更高级的应用程序,或者在安装包或解决包依赖关系时速度很慢。

Yarn 和 PNPM 是社区制作的包管理器,它们的存在就是为了解决上述问题。在过去的几年里,纱线变慢了,但今天它可能是最受欢迎的选择。

在包管理领域,PNPM 是最新出现的玩家,它使安装和升级包的速度更快。

npm 、yarn 和 pnpm 比较

NPM 是最初由 Node.js 项目开发的 JavaScript 包管理器。它使开发人员能够更轻松地在不同项目之间共享代码,并在自己的项目中使用其他人的代码。

Yarn 是 JavaScript 的包管理器,由 Facebook 开发。它快速、可靠且安全。

PNPM 是一个新的 JavaScript 包管理器,它构建在 npm 之上,以简化节点应用程序中包的安装过程。PNPM 是 NPM 的替代品。它遵循与 NPM 相同的原则,但它具有一些附加功能,使其比其前身更强大。

1 性能和磁盘效率

npm:与 Yarn 和 PNPM 相比,它有点慢。

yarn: Yarn 使用相同的扁平化 node_modules 目录,但在速度和并行安装包方面与 NPM 相当。

pnpm: PNPM 比 NPM 快 3 倍,效率更高。使用冷缓存和热缓存,PNPM 比 Yarn 更快。

Pnpm 只是从全局存储中链接文件,而 yarn 从其缓存中复制文件。软件包版本永远不会在磁盘上多次保存。

pnpm 的算法没有使用扁平化的依赖树,这使得它更容易实现、维护,并且需要更少的计算。

这是 NPM 3 及更早版本中使用的方法,但嵌套存在问题,因此必须为每个依赖它们的包复制多次包。

node_modules └─ foo ├─ index.js ├─ package.json └─ node_modules └─ bar ├─ index.js └─ package.json
md

与 NPM 相比,PNPM 通过硬链接和符号链接解决了上述问题。PNPM 按符号链接对所有依赖项进行分组,但保留所有依赖项。

a symlink (or junction on Windows) node_modules ├─ foo -> .registry.npmjs.org/foo/1.0.0/node_modules/foo └─ .registry.npmjs.org ├─ foo/1.0.0/node_modules | ├─ bar -> ../../bar/2.0.0/node_modules/bar | └─ foo | ├─ index.js | └─ package.json └─ bar/2.0.0/node_modules └─ bar ├─ index.js └─ package.json
md

与其他两个包管理器相比,PNPM 还可以节省大量空间。

2 安全

NPM:由于 npm 处理坏包的方式,一些安全漏洞直接影响了许多项目。

YARN:存储在 yarn.lock 中的校验和一直被 Yarn Classic 和 Yarn Berry 使用。Yarn 还可以防止您安装恶意软件包;如果检测到不匹配,安装将中止。

PNPM:与 Yarn 类似,PNPM 也使用校验和,除了使用校验和之外,pnpm 还在执行代码之前验证其代码的完整性

3 Monorepository 支持

Monorepository 由多个独立的代码存储库组成,所有这些代码存储库都位于一个存储库中,以避免管理多个存储库。

NPM:NPM 包管理器通过各种 CLI 命令提供 monorepo 支持来管理多个包。但是,与其他包管理器不同,它不支持高级过滤或多个工作区。

YARN:它还提供 monorepo 支持作为功能工作区。在工作区功能可用之前,使用第三方应用程序 Lerna 是在多包项目中使用包管理器的唯一方法。

PNPM:NPM 的分身问题只能用 PNPM 来解决。Monorepos 有时会受到分身的困扰,因此 PNPM 在这方面具有优势。

4 安装工作流程

正如我之前所说,必须首先在本地安装包管理器和 CI/CD。

NPM:它是世界上最大的包注册中心之一,应该与 Node.js 一起安装。它使用 package.json 和 package.lock.json 文件。

要下载软件包,请打开终端并输入以下命令:

``shell npm install "package_name"


默认情况下,npm 会创建一个名为 package.json 的文件夹,并且每当您使用 npm 下载一个包时,该文件夹就会放置在这里。

> <strong>YARN</strong>:为了解决 NPM 的问题,开发了 YARN。它提供了许多后来与
> npm 合并的新功能,例如带有版本的锁定文件、缓存等。

Yarn 使用 package.jsonand yarn.lock files。

您可以通过不同的方式安装 Yarn - 使用 npm 作为 npm 包:

```shell
npm install -g yarn

PNPM:您可以使用 npm 包轻松安装 PNPM。

npm install -g pnpm
shell

5 项目结构

一旦安装过程结束,它将生成可以轻松查看的相应文件,并且所有重要的元信息都存储在名为 package.json 的文件中。

NPM:使用 npm install 一个 package-lock.json 并生成一个 node_modules 文件夹。您可以手动将 .npmrc 配置文件放在根级别。

. ├── node_modules/ ├── .npmrc ├── package-lock.json └── package.json
js

YARN:这还将创建 yarn.lock 文件和 node_modules 文件夹。您还可以使用**.yarnrc 文件配置您的纱线;Yarn Classic 也承认.npmrc**文件。

. ├── .yarn/ │ ├── cache/ │ └── releases/ │ └── yarn-1.22.17.cjs ├── node_modules/ ├── .yarnrc ├── package.json └── yarn.lock
md

除了 .yarn/cache/ 之外,还可以使用其他存储 yarn 经典版本的位置(.yarn/releases/)。

PNPM:与 NPM 不同,PNPM 不会创建扁平的依赖关系树。在 node_modules 中,所有东西在 package.json 中都有自己的 node_modules 文件夹,并且每个依赖项都在 package.json 中精确指定。在 npm 版本 3 之前,node_modules 结构是可预测的。

这种方法的问题是双重的:

  1. windows 经常遇到由依赖树太深的包引起的长目录路径问题
  2. 多次复制包以满足多个依赖项

PNPM 解决了这个问题而没有展平依赖树。每个包的依赖项都在一个 node_modules 文件夹中组合在一起,并且符号链接用于将依赖项组合在一起,因此目录树是扁平的。

. ├── node_modules/ │ └── .pnpm/ ├── .npmrc ├── package.json └── pnpm-lock.yml
md

使用 安装依赖项后会创建一个 package.json 文件 pnpm i,还会 node_modules 生成一个文件夹,但由于其内容可寻址存储方法,它的结构将与 npm 和 yarn 完全不同。

例子:
node_modules └── .pnpm ├── bar@1.0.0 │ └── node_modules │ └── bar -> <store>/bar │ ├── index.js │ └── package.json └── foo@1.0.0 └── node_modules └── foo -> <store>/foo ├── index.js └── package.json
md

结果

包管理器目前处于良好状态。几乎所有主要的包管理器都实现了功能对等。引擎盖下存在差异。

虽然 PNPM 与 NPM 有一些相似之处,但它们管理依赖关系的方法却大不相同。PNPM 的方法提供了更好的性能和更好的磁盘空间效率。

很快,Yarn Classic 可能会停止支持,因为它被视为遗留软件。

作为最新的包管理器竞争者,Yarn Berry PnP 仍未充分发挥其潜力来彻底改变包管理领域。

依赖关系在 JavaScript 应用程序中很常见。包管理器通常用于管理这些依赖项。默认情况下,节点使用 NPM。

尽管 NPM 缺少一些高级功能,但它在解决包依赖和安装包方面做得很好。