最近是不是经常听到pnpm,我也是。今天研究了一下它的机理,果然厉害。可以说是对yarn和npm的一次降维打击。这有什么好?一起来看看吧。先从npm2说起,根据包管理工具的发展历程:npm2使用node版本管理工具,将node版本降到4,那么npm版本就是2.x。然后找到一个目录,执行npminit-y,快速创建一个package.json。然后执行npminstallexpress,就会下载express包及其依赖:展开express,它还有node_modules:展开几层,每个依赖都有自己的node_modules:也就是说npm2的node_modules是嵌套的。这是正常的吗?怎么了?这其实是有问题的。多个包之间不可避免地会存在共同的依赖关系。如果这样嵌套,相同的依赖会被复制很多次,会占用比较大的磁盘空间。这不是最大的问题。致命问题是windows最长的文件路径超过260个字符,所以嵌套会超过windows路径的长度限制。当时npm还没解决,社区又想出了一个新的解决方案,就是yarn:yarnyarn是怎么解决重复依赖和嵌套路径长的问题的?铺平。所有的依赖不再一层层嵌套,而是都在同一层,这样就不存在重复依赖的问题,也不存在路径过长的问题。我们把node_modules删掉,用yarn重新安装,执行yarnaddexpress:此时node_modules是这样的:都铺在一层,下面的包大部分都不是二级node_modules:当然也有有些包里面还有node_modules,比如这个:为什么会有嵌套?因为一个包可能有多个版本,只能升级一个,所以后面遇到同一个包的不同版本时,还是采用嵌套的方式。npm升级到3之后,也采用了这种铺路方案,和yarn很像:当然yarn也实现了yarn.lock锁定依赖版本的功能,但是这个npm也实现了。yarn和npm都采用了paving方案,这个方案没有问题吗?不,扁平化解决方案也有相应的问题。最主要的问题是ghostdependencies,就是你明明没有在dependencies中声明的依赖,但是你可以在代码中require它们。这个也很好理解,因为都是铺好了,依赖的依赖也能找到。但是这种方式存在隐患,因为没有明确的依赖。如果有一天其他包不依赖这个包,你的代码将无法运行,因为你依赖这个包,但现在不会安装它。这就是Spectre依赖项的问题。而且还有一个问题,就是当上述依赖包有多个版本时,只会升级一个,其他版本的包还是要复制很多次,仍然存在浪费磁盘的问题空间。社区有解决这两个问题的想法吗?当然有,不就是pnpm出来了吗。那么pnpm是如何解决这两个问题的呢?回忆一下pnpm,为什么npm3和yarn需要扁平化node_modules?不就是因为同一个依赖会被复制多次,而且路径太长,所以在windows下有问题吗?如果您不复制它怎么办,例如通过链接。首先介绍一下链接,即软链接和硬链接。这是操作系统提供的一种机制。硬链接是对同一个文件的不同引用,而软链接则是新建一个文件,文件内容指向另一个路径。当然,这两个链接的使用是类似的。如果不拷贝文件,只把npm包的内容保存在全局仓库,其余地方链接起来怎么办?这样就不会因为多次拷贝而浪费磁盘空间,也不会有路径太长的问题。因为太长路径的限制本质上是不能有太深的目录层级,现在是链接到各个位置的目录,而不是同一个目录,所以没有长度限制。没错,pnpm就是通过这个思路实现的。再次删除node_modules,然后用pnpm重新安装,执行pnpminstall。你会发现它打印了这样一句话:Thepackageishardwiredfromtheglobalstoretothevirtualstore,这里的虚拟商店是node_modules/.pnpm。我们打开node_modules看看:确实不平,依赖express,所以node_modules下只有express,没有ghost依赖。展开.pnpm看看:所有的依赖都在这里铺好了,而且都是从全局store中硬链接出来的,然后通过软链接来组织package之间的依赖。比如expresss在.pnpm下,这些都是软链接,也就是说所有的依赖都是从全局store硬链接到node_modules/.pnpm,然后通过软链接相互依赖。官方给了一个示意图,大家一起看看就明白了:这就是pnpm的实现原理。那么回过头来看,为什么pnpm优秀呢?首先,最大的好处就是节省磁盘空间。全局只保存一份包,其余都是软硬连接。将节省多少磁盘空间。作者:zxg_神说必有光链接:https://juejin.cn/post/712729...来源:稀土掘金版权归作者所有。商业转载请联系作者授权,非商业转载请注明出处。
