pnpm 是什么?

4,649 阅读3分钟

我们为什么要使用 pnpm ?

速度快,效率高,省空间

pnpm 是 Node.js 的替代包管理器。它是 npm 的直接替代品,速度更快、效率更高。

为什么效率更高?当你安装一个包时,pnpm 将它保存在你机器上的一个全局存储中,然后我们从它创建一个硬链接而不是复制。对于模块的每个版本,磁盘上只保存一个副本。

例如,当使用 npm 或 yarn 时,如果您有 100 个使用 lodash 的包,那么磁盘上将有 100 个 lodash 副本。Pnpm 可让您节省千兆字节的磁盘空间!

npm2 的问题

node_modules 中的每个依赖项都有自己的 node_modules 文件夹。

这种方法有两个严重的问题:

    • 包经常创建太深的依赖树,这会导致 Windows 上出现长目录路径问题
    • 包在不同的依赖项中需要时被多次复制粘贴

npm3 、Yarn 如何解决 npm2 的问题

全部拍平

为了解决这些问题,npm 重新考虑了 node_modules 结构并提出了扁平化。如果使用npm3,node_modules结构看起来就会像这样:

image.png 有关 npm v3 依赖解析的更多信息,请参阅npm v3 依赖解析

Yarn 只是对 npm 的一个小改进。尽管它使安装速度更快并且具有一些不错的新功能,但它使用与 npm3 相同的扁平 node_modules 结构。

npm3 、Yarn 方案的隐患

二向箔的隐患

扁平化的依赖树会带来很多问题:

    1. 模块可以访问它们不依赖的包
    2. 扁平化依赖树的算法非常复杂
    3. 一些包必须复制到一个项目的node_modules文件夹中

\

此外,Yarn 不打算解决许多问题问题,例如磁盘空间使用问题。

pnpm 如何解决 npm2 的问题

我附庸的附庸,就是我的附庸

pnpm 与 Yarn 的相同点

pnpm 具有 Yarn 相对于 npm 的所有附加功能:

  1. 安全。 与 Yarn 一样,pnpm 有一个特殊文件,其中包含所有已安装包的校验和,以在执行每个已安装包的代码之前验证其完整性。
  2. 离线模式。 pnpm 将所有下载的包 tarball 保存在本地注册表镜像中。当包在本地可用时,它从不发出请求。使用该--offline参数,可以完全禁止 HTTP 请求。
  3. 速度。 pnpm 不仅比 npm 快,而且比 Yarn 快。无论是冷缓存还是热缓存,它都比 Yarn 快。Yarn 从缓存中复制文件,而 pnpm 只是从全局存储中链接它们。

虚拟目录+平铺结构+包隔离

如果用 pnpm 安装 express,安装目录长这样:

image.png

可以看到 express 里面并没有 node_modules 文件夹,也就是说 express 的依赖,并不在 express 包里,

如果express 没有 node_modules 文件夹,那 express 的所有依赖又装在哪里呢 ?

这里的 express 只是一个符号链接。 当 Node.js 解析依赖的时候,它使用这些依赖的真实位置,它不保留符号链接。 但是你可能就会问了,express 的真实位置在哪呢?

在这里:node_modules/.pnpm/express@4.17.1/node_modules/express

所以我们现在知道了 .pnpm/ 文件夹的用途。 .pnpm/ 以平铺的形式储存着所有的包,所以每个包都可以在这种命名模式的文件夹中被找到:

.pnpm/<name>@<version>/node_modules/<name>
我们称之为虚拟存储目录。

这个平铺的结构避免了 npm v2 创建的嵌套 node_modules 引起的长路径问题,但与 npm v3,4,5,6 或 yarn v1 创建的平铺的 node_modules 不同的是,它保留了包之间的相互隔离。

软连接

现在让我们看看 express 的真实位置:

image.png

还是没有 node_modules! pnpm 的 node_modules 结构的第二个关键就是包的依赖项与依赖包的实际位置位于同一目录级别。 所以 express 的依赖不在 .pnpm/express@4.17.1/node_modules/express/node_modules/ 而是在 .pnpm/express@4.17.1/node_modules/

image.png

express 所有的依赖都软链到了 node_modules/.pnpm/ 中的对应目录。 把 express 的依赖放置在同一级别避免了循环的软链。