当前位置: 首页 > 科技观察

高性能包管理器Pnpm你学会了吗?

时间:2023-03-22 11:40:34 科技观察

概念性能npm。高性能npm。它的口号是:快速、磁盘空间高效的包管理器。快速、节省磁盘空间的包管理工具。特点快。pnpm比替代数据源[1]效率快2倍。Node_modules中的文件链接自单个内容可寻址存储。可以理解为是从一个globalstore中获取的,后面会详细说到。支持单体仓库。pnpm内置了对一个仓库多个包的支持。类似--filter后跟子包名的意思是只有新安装的包才会包含在这个包里等等。简单做法参考[2]。严格的。pnpm默认创建一个非平铺的node_modules,因此代码无法访问任意包。npm和yarn的包管理机制npm@3之前采用的是嵌套安装方式。如下图所示:node_modules└─foo├─index.js├─package.json└─node_modules└─bar├─index.js└─package.json缺点:package中经常会创建太深的依赖树,将导致Windows上的目录路径过长问题。当不同的依赖中需要一个包时,会多次复制粘贴,生成多个文件。npm@3+和Yarn扁平化依赖关系:node_modules├─foo|├─index.js|└─package.json└─bar├─index.js└─package.json缺点:幻影依赖。幻影依赖指的是node_modules中没有package.json的依赖包。在依赖结构中声明非确定性的情况下,使用其他包的依赖关系。为什么这里提升的是D@2.0.0而不是D@10.0?有可能跟安装顺序有关。详情请参考[3]。避免此问题的解决方案:锁定文件。npm包克隆。同理,因为node_modules中的依赖被扁平化了,相同版本的子依赖在依赖不同的项目依赖时会被安装两次(即上图中B/C包都依赖D@2.0.0).安装很慢。同一个包安装两次,占用磁盘空间,安装速度变慢。不是单身狗。当两个不同的组件调用require("library-f")时,可能会得到两个不同的库实例,这意味着可能突然有两个单例实例(换句话说,底层的“全局”变量被赋值给两个不同的闭包)。会让我们的调试变得非常困难。pnpm方案的pre-knowledgeinode每个文件都有一个唯一的inode,里面包含了文件的meta信息。当访问文件时,会将相应的元信息复制到内存中,实现对文件的访问。您可以使用stat命令查看文件的元信息。statREADME.mdhardlink硬链接可以理解为相互指针。创建的硬链接指向源文件的inode,系统不会为其重新分配inode。无论有多少个硬链接,它们都指向同一个inode节点,也就是说当你修改源文件或者链接文件时,都会同步修改。每创建一个新的硬链接,节点连接数就会增加。只要节点链接数不为零,文件就会一直存在,不管你是删除源文件还是hradlink。只要一个存在,文件就存在。.pnpm中的每个文件都是来自内容可寻址存储的硬链接。软链接可以理解为单向指针,是一个独立的文件,有独立的inode,始终指向源文件,类似于Windows系统的快捷方式。删除源文件,软链接失效。如果软链接或硬链接文件被修改,其他硬链接或软链接和源文件也会改变。感觉这里需要注意一下,尤其是调试修改文件的时候,记得还原,不然别的项目会用到,可能会出现问题。几个关键结果显示,项目根目录下的node_modules中只有直接依赖的包,没有间接依赖的包。通过软链接进入.pnpm目录。.pnpm虚拟存放目录——.pnpm,所有直接和间接的依赖都链接到这个目录下。该目录使用@来实现同一模块不同版本之间的隔离和复用。Storepnpm通过Store全局存储所有的node_modules依赖,将项目的硬链接存储在.pnpm中。使用pnpm在项目上安装依赖时,如果sotre目录下有依赖,会直接从store目录转到hard-link,避免二次安装带来的时间消耗。如果依赖在store目录下不存在,则会下载一次。如果全局包变得非常大怎么办?使用方法是pnpmstoreprune,它提供了删除一些没有被全局工程引用的包的功能。比如一个包axios@1.0.0被一个项目引用了,但是某个修改使得项目中的包更新为1.0.1,那么store中的1.0.0axios就变成了一个未引用的包,并且可以通过执行pnpmstoreprune删除它存储在商店中。原理分析先看一张示意图:我们的项目中有一个依赖bar@1.0.0。bar@1.0.0也依赖于foo@1.0.0。node_modules下有bar@1.0.0和.pnpm目录,没有foo@1.0.0。bar@1.0.0通过软链接指向.pnpm/bar@1.0.0/node_modules/bar@1.0.0。.pnpm/bar@1.0.0/node_modules/bar@1.0.0又通过硬链接指向商店。bar@1.0.0所依赖的foo@1.0.0将安装在与其自身相同的级别。这里的设计,我理解是基于node的require机制。bar中require('foo')时,会先@1.0.0查找foo,而不是向上查找,避免依赖包版本不一致的问题。.pnpm/bar@1.0.0/node_modules/foo@1.0.0。并通过软链接指向。foo@1.0.0用于下一级别的pnpm。.pnpm/foo@1.0.0通过硬链接指向Store。迁移和问题我们现在可能正在使用npm或者yarn,那么如何更好的过渡到pnpm呢?或者会不会有什么问题?迁移:迁移锁定文件。可以通过pnpm导入。参考[4]。只允许pnpm。参考[5]。解决冲突。与npm和yarn相同。只需要解决package.json冲突,然后重新安装即可。更多...问题:CI/CD中的全局存储问题。可能会命中不同的机器,也可能存在权限问题。与npm和yarn相比。社区还没有那么活跃。硬链接在window系统中存在兼容性问题。更多...总结pnpm通过硬链接和软链接的巧妙结合,充分实现了依赖树形结构的node_modules,并严格遵循Node.js模块解析标准,解决了幻象依赖和npm克隆问题。并且通过在~/.pnpm-store全局只保存一份,在不同项目中安装的速度也会变得更快,磁盘空间占用的问题也会得到解决。参考资料pnpm:最先进的包管理工具[6]中文官网[7]npm的问题及pnpm的处理方式[8][1]数据来源:https://github.com/pnpm/benchmarks-of-javascript-package-managers[2]简单实践参考:https://zhuanlan.zhihu.com/p/373935751[3]参考:http://npm.github.io/how-npm-works-docs/npm3/non-determinism.html[4]参考:https://pnpm.io/zh/cli/import[5]参考:https://pnpm.io/zh/only-allow-pnpm[6]pnpm:最高级包管理工具:https://www.aisoutu.com/a/1218460[7]中文官网:https://www.pnpm.cn/[8]npm的问题及pnpm的处理方式:https://www.yuexunjiang.me/blog/problems-with-npm-and-how-pnpm-handles-them/