为什么选择pnpm

399 阅读3分钟

pnpm 是什么

本文已参与「新人创作礼」活动,一起开启掘金创作之路。

pnpm - 速度快、节省磁盘空间的软件包管理器。

同类工具有我们熟悉的npm、yarn。新工具的出现并流行,一定是解决了旧工具的痛点。我们先简单回顾一下npm和yarn的发展以及存在的问题。

npm 和 yarn

npm

在 npm1 和 npm2 中依赖管理是嵌套结构的,如图:

在项目 node_medules 下安装了 express 包,express 又有自己的 node_modules,同样在 express 的 node_modules 中的依赖也会有自己的 node_modules。

存在的问题:

  • 依赖层级深,会导致文件路径过长。windows 的文件路径最长是 260 多个字符,这样嵌套是会超过 windows 路径的长度限制的。

  • 公共的依赖不能复用,会重复安装很多次,导致文件体积过大,占用大量磁盘空间。

针对这些问题社区有了新的解决方案:yarn。

yarn

通过将依赖铺平,用扁平化依赖管理的方式解决这个问题。

我们用 yarn 重新安装 express 包,项目的 node_modules 如图:

可以看到所有的依赖都安装到项目的 node_modules 下,express 下没有自己的 node_modules 了,没有了很深的依赖嵌套,相同版本的包也不会重复安装。这样解决了公共依赖重复安装的问题,也不会因为很深的依赖层级导致文件路径过长。

npm3 也采用了这种铺平的方案,扁平化依赖管理的方式存在的问题:

  • 扁平化算法耗时较长;

  • 多个版本的依赖包,只会提升一个,其他版本的依赖包还会重复安装并嵌套使用;

  • 项目中可以非法访问未声明的依赖包,也就是幽灵依赖问题。

幽灵依赖问题,就是说在 package.json 中未声明的依赖,可以在代码中引入并使用。原因是依赖都铺平在项目的 node_modules 下,依赖的依赖也可以在 node_modules 下找到。存在的隐患:我们未声明的情况下使用一个依赖包,等哪天这个依赖包不再被其他声明的包依赖,我们的代码就跑不通了,因为这个依赖包没有安装。

针对这些问题,pnpm 出现了。

pnpm的实现方式

同样,我们再用 pnpm 安装 express 包,可以看到有如下提示:

安装包是从内容可寻址存储到虚拟存储的硬链接,内容可寻地址是计算机的文件路径,虚拟存储就是项目 node_modules 下的 .pnpm,是通过硬链接(硬链接指同一个文件的不同引用)。内容可寻地址相当于全局的 store,虚拟存储相当于本地的 store。

项目的 node_modules 如图:

可以看到不再是扁平化结构,只有我们声明的 express。

.pnpm 展开如图:

所有的依赖都在 .pnpm 下铺平了,并且这些依赖全都是从全局 store 硬连接过来的,然后包和包之间的依赖关系是通过软链接(软链接指新建一个文件,文件内容指向另一个路径)组织的。比如 express@4.18.1 的 node_modules 虽然是嵌套结构,但是依赖都是软链接;项目 node_modules 下的 express 也是软链接的方式组织的。

pnpm 就是使用软硬链接的方式解决 npm/yarn 的问题,项目所有的依赖都是从全局 store 硬链接到 node_modules/.pnpm 本地 store 下,然后通过软链接来组织依赖关系。

项目的 node_modules 下不再是各种被铺平的依赖,而是与 package.json 中声明的依赖基本保持一致,结构清晰了也解决了幽灵依赖的问题。

一个依赖包只在全局 store 中保存一份,剩下的都是软硬链接,大大节省了磁盘空间,使用软硬链接方式组织依赖也比复制依赖的速度快了很多。