pnpm 介绍
# 一、pnpm 是什么
pnpm (performant npm,意思是高性能的 npm)是 Node.js 的替代包管理器。它是 npm 的直接替代品,速度更快、效率更高。为什么效率更高?当你安装一个包时,pnpm 将它保存在你机器上的一个全局存储中,然后我们从它创建一个硬链接而不是复制。对于模块的每个版本,磁盘上只保存一个副本。
例如,当使用 npm 或 yarn 时,如果您有 100 个使用 lodash 的包,那么磁盘上将有 100 个 lodash 副本。pnpm 可让您节省千兆字节的磁盘空间!
它由 npm/yarn 衍生而来,但却解决了 npm/yarn 内部潜在的 bug,并且极大了地优化了性能
# 二、pnpm 特性有哪些
- 速度快
官方的 benchmark 数据是这样的,但是实际使用发现 pnpm 的第一次下载包速度跟 yarn 是差不多的,其优势体现在第二次下载相同的包更快
- 高效利用磁盘空间
pnpm 内部使用基于内容寻址的文件系统来存储磁盘上所有的文件,这个文件系统出色的地方在于:
1、不会重复安装同一个包。用 npm/yarn 的时候,如果 100 个项目都依赖 lodash,那么 lodash 很可能就被安装了 100 次,磁盘中就有 100 个地方写入了这部分代码。但在使用 pnpm 只会安装一次,磁盘中只有一个地方写入,后面再次使用都会直接使用 hardlink(硬链接)
2、即使一个包的不同版本,pnpm 也会极大程度地复用之前版本的代码。举个例子,比如 lodash 有 100 个文件,更新版本之后多了一个文件,那么磁盘当中并不会重新写入 101 个文件,而是保留原来的 100 个文件的 hardlink,仅仅写入那一个新增的文件
- 支持monorepo
随着前端工程的日益复杂,越来越多的项目开始使用 monorepo。之前对于多个项目的管理,我们一般都是使用多个 git 仓库,但 monorepo 的宗旨就是用一个 git 仓库来管理多个子项目,所有的子项目都存放在根目录的 packages 目录下,那么一个子项目就代表一个 package。
# 三、pnpm 依赖原理
npm、yarn 安装包的问题
在 pnpm 出现以前,npm 和 yarn 为了提高包的复用率,都采用了扁平化的装包策略。扁平化的安装方式会导致我们的 node_modules 文件夹和 package.json 存在很大的出入,比如你 install 一个包 express,但是你的 node_modules 下会有很多包
这个时候会有一些问题:
- 幽灵依赖
从目前的包引用方式来说,import 的时候我们会从 node_modules 的文件夹中寻找,按照上面的图中所示,如果我们在 package.json 中没有 accepts,其实我们也是可以引用到的,因为她确实存在,这时候我们访问的就是未申明 npm 包,如果某一天 express 主包不再依赖 accepts,这个时候项目就会有依赖缺失的问题。 我们把这种主包依赖的子包,未被申明而在项目中使用,可以理解成是主包夹带的包,我们称之为 幽灵依赖。
- 包版本的不确定性
这个很好理解,如果 A、B 两个主包都依赖 accepts 包,但是 A 依赖 accepts@1.0,B 依赖 accepts@2.0 ,那 node_modules 下的扁平结构是展示 1.0 还是 2.0 呢?目前的方式是谁后安装的谁就显示。 这种不确定性在开发中引起的问题也不在少数 「别人用这个包可以解决这个问题,但是我安装这个包就不能解决」,往往就是这个原因导致的
- 依赖重复安装
这个也很好理解,AB 都依赖 accepts,依赖不同的版本,无论 node_modules 的顶层提升了哪个版本,这个包都是会被安装两次的
# 四、pnpm 的安装包方式
同样的,使用pnpm安装一个express,安装结构如下:
可以看到 node_modules 结构非常清晰,但是这个 express 文件夹只是一个软链接, 它的真正存储的地方在图中的 .pnpm 文件夹中
我们看一下pnpm官方对这一现象的图示说明:
顶级外层来看,格式很清晰,.pnpm 中也是嵌套的。这是因为 pnpm 的 node_modules 布局使用的是符号链接来创建依赖关系的嵌套结构。.pnpm 内部的每个包中的每个文件都是只用硬链接指向了 .pnpm store 中的文件
这样的好处就是会让我们的 node_modules 很清晰,内部的包可以和 package.json 中的依赖对应起来,一目了然,我们安装什么里面就有什么
这样幽灵依赖的问题就解决了,包版本不确定性的问题也就解决了。毕竟顶层就只有我们手动安装的包,其他依赖包都收在 .pnpm 中。这样无论是哪个版本都会平铺在这里供你使用。这个平铺的方式就是通过链接的形式进行引用
问题是上面的软链接、硬链接是啥呢?简单说明一下:
软链接:类似 windows 系统的快捷方式;软链接里面存放的是源文件的路径,指向源文件;
硬链接:是计算机文件系统中的多个文件平等地共享同一个文件存储单元(如MFT条目、inode),可以实现多对一的关系,pnpm主要利用的是这一特性,这就很容易说明多个项目用到同一个包,就不用再重复下载包了,只需要管理好 .pnpm store 中的对应源文件就可以了