为什么 pnpm 比 npm 更快且更省空间?
2024年1月1日
身为前端开发者,你大概一定听过 npm 这个套件管理工具,可能也听过社群许多人会用的 yarn,以及过去两年热门的 bun。但其实还有一个叫 pnpm 的套件管理工具,是在 bun 出来之前,受到许多开发团队亲赖的。这篇文章我们来聊聊 pnpm。
在 pnpm 的官网中是用 Fast, disk space efficient package manager 来介绍 pnpm 的。可以看到,这边强调的是两个特点,一个是在时间维度上快,另一个是在空间维度上有效率。
先来讲快这一点,之所以 pnpm 比起 npm 或者 yarn 来得快,是因为 pnpm 在设计上,共享了依赖,这可以避免重复下载何解压缩已经被处理过的套件,因此在多个不同套件都有相同依赖的状况下,pnpm 会快很多。除此之外,pnpm 也做了本地快取,这能够减少对网路的依赖;在有快取的状况下,即使网路速度慢,如果命中本地快取,一样可以快速完成套件安装。
接着来讲空间上的节省,因为 pnpm 有全局储存 (global store) 的机制,这能有效避免重复储存相同的依赖,因此如果你使用的多个套件有重复依赖,最终这些相同的依赖,都只会在硬碟中存一次,这大幅度降低依赖在硬碟中占据的空间。对比起来,npm 与 yarn 都会在每一个不同的专案复制一份,因此会占用比较多空间。
要理解 pnpm 在依赖结构设计的巧妙上,我们要先懂 Node.js 是如何找到某个依赖的:
首先 Node.js 会先找自己的模组 (例如
fs
),这部分不需要额外路径解析如果不是 Node.js 内建模组,它会从
node_modules
底下开始找,如果没有node_modules
,则会从目前的档案目录中,逐一遍历直到找到最近的node_modules
然后从中找寻某个模组如果找不到,就会继续遍历直到找到,如果遍历完整个目录还是找不到,就会抛出错误
在 pnpm 的设计下,当 Node.js 要开始查找模组时,在 node_modules
底下,大家可能会看到右箭头的符号,这个右箭头是指某个连链接 (link),这个链接会指向上面有提到的全域储存 (global store),所以可以理解成,当 Node 要找该模组时,pnpm 会跟 Node 说去全域的某个位置可以找到。
而这个全域储存的位置,就是在 node_modules
底下的 .pnpm
资料夹中,只有在这个资料夹当中的,是真正的档案,其他的都只是一个指针 (pointer),会指向这个真正存的地方。这样一来,就可以避免同样的依赖被复制一份并且重复存
从 pnpm 的设计可以看到,其实在前端的领域,把资料结构学好,是很有价值的,当换了一种设计,就能大幅度减少使用的空间~