为什么要使用 pnpm
当我们使用 npm 或 yarn 来安装项目依赖,如果我们的电脑里有很多的项目依赖了同个包,比如 axios,那么 axios 的包文件就会在电脑上存在多份,造成硬盘空间的浪费。使用 pnpm 则可以有效解决这一问题,因为所有的依赖包,都会存放在硬盘上的某一位置(pnpm-store),同一依赖包只会有一份文件,即使版本不同,也只会将不同版本间有差异的文件更新进存储库。当多个项目需要依赖某个包时,只需要创建到包文件的硬链接即可,而不需要重复地复制包。
那么什么是硬链接呢?
硬链接
硬链接(hard link)就是存储在硬盘里的一个文件的一个或多个文件名。在 Windows 电脑中,可以通过命令 mklink /H 创建硬链接后生成的文件 源文件
来实现创建硬链接,比如要通过 a.js 创建 b.js:
powershell
mklink /H b.js a.js
执行结果如下:
当修改了 a.js 或 b.js,本质上都是修改了硬盘里的文件数据,所以一个文件修改了,另一个文件也会被修改。删除了 a.js,并不会影响 b.js 的访问,因为硬盘里的文件数据还在,只有当所有的硬链接都被删除了,硬盘里的文件数据才会被真正删除。图示如下:
软链接
既然有硬链接,那么相对应的,就有软链接(soft link)又叫符号链接(symbolic link),这个文件包含了另一个文件的路径名(绝对路径或相对路径)。在 Windows 电脑中,可以通过命令 mklink 创建软链接后生成的文件 源文件
来实现创建软链接,比如要通过 a.js 创建 c.js:
powershell
mklink c.js a.js
执行结果如下:
图示如下:
创建后的 c.js 在 vs code 中显示时,可以看到右边有个 ↳
,表明这是一个软链接:
如果直接去文件夹里查看,可以看到 c.js 有个快捷方式的图标,并且指向的目标为 a.js:
修改 c.js 的内容,实际上是通过软链接找到 a.js 再通过硬链接找到硬盘里的数据进行修改。如果删除了 a.js,那么 c.js 也就失效了。
pnpm 的安装与使用
说完硬链接和软链接的概念,我们来看看 pnpm 到底是如何使用的。首先是安装:
powershell
npm install -g pnpm
注意最新的 pnpm 8 需要的 node 版本至少是 16:
在项目中使用时,也需要像 npm 那样先 init
创建 package.json 文件,但用不着跟上 -y
来表示默认配置初始化项目:
powershell
pnpm init
安装包时使用的命令是 add
,比如要安装 axios:
powershell
pnpm add axios
安装成功后显示的信息比较多,如下图:
下面对其中一些信息做下说明:
- "Content-addressable store is at: D:.pnpm-store\v3" 表明默认的 pnpm 的存储仓库的地址,实际上是在 D:.pnpm-store\v3,它们都是一些指向存储在硬盘中具体文件的硬链接:
我们也可以通过命令 pnpm store path
来查看 pnpm-store:
之所以在 D 盘,是因为我电脑上 D 盘是机械硬盘,项目都存放于此,C 盘为固态硬盘,而硬链接是无法跨磁盘的;
- "reused 0" 表示这次安装复用了 0 个依赖(因为是首次使用 pnpm 下载 axios);
- "downloaded 9" 表示下载了 9 个依赖;
- "added 9" 表示往默认的 pnpm 的存储仓库中添加了 9 个依赖;
- "resolved 9" 表示解析了 9 个依赖,如果是使用 npm 安装的 axios,就可以清晰地看到这 9 个依赖了:
因为 npm 的 node_modules 目录是扁平的,即使我们只安装了 axios,但是 axios 本身又依赖 3 个包:
这 3 个包又有依赖其它包,依次类推,总共 9 个,都会被提升到 node_modules 的根目录。这会导致一个理论上的问题,就是我们可以在编写代码时引用到并没有在 package.json 的 dependencies
里声明的包,比如 import followRedirects from 'follow-redirects'
。而 pnpm 的 node_modules 目录是非扁平的,就可以解决这个问题。
非扁平的 node_modules 目录
同样是只安装了 axios,pnpm 的 node_modules 目录如下:
可以看到 node_modules 根目录下能找到的只有 axios,这样就无法在我们的项目中通过诸如 import followRedirects from 'follow-redirects'
来引用其它包了。并且 axios 右边还有个 ↳
符号,说明这是个软链接,它链接到的是 .pnpm 下的 axios@1.4.0,"1.4.0 "为 axios 的版本号。
axios@1.4.0 目录下还有个 node_modules,所以 pnpm 的 node_modules 是非扁平的,里面除了 axios 是硬链接,其它 3 个包又是软链接,指向的是 .pnpm 根目录下的对应的目录:
其它命令
除了 pnpm add <pkg>
,还有些其它常见的命令,列于下方,更多可参加官方文档。
pnpm install
,用于安装项目的所有依赖,后面是不跟上某个具体的包的;pnpm remove <pkg>
,用于卸载某个包;pnpm run
,运行脚本命令,如果脚本名不与已有的 pnpm 命令名字相同,还可以省略run
;pnpm store prune
,从存储(pnpm-store)中删除未引用的包。