pnpm
相较于npm
和yarn
,pnpm
通过其独特的依赖管理模式解决了两大长期困扰着开发者的问题:幽灵依赖和NPM分身,除此之外还在依赖的安装速度上得到了大幅的提升。
在详细介绍pnpm
实现原理之前,让我们先聚焦一下上文所提到的问题是指怎样的场景。
幽灵依赖(Phantom dependencies)
无论是npm
还是yarn
,为了尽量减少重复模块的安装都采用了扁平化的node_modules
设计。即使我们的项目中只安装一个模块,最终在node_modules
中还是会看到成百上千的子模块,首先这种观感体验不佳,寻找某个指定模块时非常麻烦,更重要的是我们的源代码中可以直接引用这些子模块来使用,这是个很不好的哲学,当后续高版本的父模块不再依赖这些子模块时,我们就需要调整代码来适应这些变化,在大型项目中碰到这种情况还是很麻烦的。
npm分身(npm doppelgängers)
npm
和yarn
的扁平化的设计是为了减少重复的模块,但是并不能完全避免,我们还会碰到这种情况(即npm 分身)。
如当我们已经安装了A@1.0
时,如果依赖的模块B和模块C都依赖于A@2.0
,此时只能分别在模块B和模块C的node_modules
下安装A@2.0
,因此难免造成体积的增大。
pnpm的依赖管理
为了介绍pnpm
的原理,最简单的方式就是我们创建一个新项目来看看实际的效果,通过pnpm i
安装模块时,会发现node_modules
中存在两个文件夹,分别是.pnpm
和模块A,模块A实际上是一个符号连接(软连接)指向着.pnpm/A
,.pnpm
中是各种子模块。这样我们的代码中就无法直接引用这些子模块了,并且整个node_modules
结构更加清晰了,从而解决了幽灵依赖的问题。
而.pnpm
中的文件,本质上是一个硬链接,当我们通过pnpm
安装某个模块时,会首先安装在~/.pnpm-store/v3
下,然后创建在项目的node_modules/.pnpm
中创建一个硬链接,因此不管怎样同一个版本的某个包我们总是只会安装一次,后续需要时不需下载直接生成硬链接即可,从而解决了NPM分身的问题。
由此可以看出,pnpm
不仅解决了上述的两大棘手问题,带来了更加简洁的node_modules
,只要全局中已经安装了某个模块,后续在某个项目中安装时无需下载,直接创建硬链接即可,大大减少下载时长。
命令
pnpm link --global
pnpm link --global <name>