本文已参与「掘力星计划」,赢取创作大礼包,挑战创作激励金。
pnpm
是一个包管理工具。
pnpm
非常适合**「单仓多包」**的项目,即 monorepo
。
pnpm
非常快,官网上有个速度PK结果:
pnpm几乎是其他包管理器的2倍多
在 Vue3.0 里就用到了 pnpm
:
Vue3.0:move to pnpm
除了 Vue3.0,还有很多公司和组织也在用 pnpm
:
pnpm
不仅速度够快,占用的空间更小,尤其是monorepo项目,一个仓库下的多个项目可共用依赖包,各个项目可通过软链索引到依赖包的实际位置(类似文件夹快捷方式),而不需要每个项目都安装一份,大大节省了存储空间。
依赖包的实际安装位置默认是在 .pnpm
里,在windows下我们可以用 dir
命令看到符号链接实际指向的位置:
pnpm
提供了非常多的配置选项,感兴趣的童鞋可以去官网上自行探索:pnpm.io/zh
在npm3和yarn中,为了解决树型依赖层级太深的问题,采用了一种叫“flat node_modules”的扁平结构,简单理解就是把所有依赖包都提升到 node_modules
根目录下,然后各个包再通过软链索引到实际位置。
但是这种做法不仅算法复杂,还会引起新的问题,即 node_modules
里会有很多**「幽灵依赖包」**(Phantom dependency
),可以理解为依赖的依赖(比如我们项目需要依赖 vue
,vue
又依赖了很多其他包,但是这些包并没有在我们自己的 package.json
里声明)。
pnpm
则不会有这个问题。
pnpm
的根目录下的 node_modules
是纯净的,只包含我们在 pakcage.json
中显式声明的依赖包,并且这里实际上保存的是依赖包的软链。
这里以 express
为例,依赖包express
通过软链实际指向了.pnpm\express@4.17.1\node_modules\express
:
至于依赖的依赖,我们去express
依赖包实际所在目录看看:
在.pnpm\express@4.17.1\node_modules
下不仅保存了 实际的 express
包,还保存了 express
所依赖的包的软链。这些软链同样指向了根目录下node_modules.pnpm
中文件夹。
依赖的依赖也是通过软链指向根路径下的包。
这种做法不仅避免了“幽灵依赖包”的问题,同时也从根本上避免了在我们的项目里能随意引用显示声明之外的包的问题,并且真正解决了重复包的问题。
monorepo
管理工具除了本文提到的 pnpm
,还有 lerna
、rush
、bazel
等等。
我们团队之所以选用 pnpm
,除了因为 pnpm
的诸多优点,更因为 pnpm
的使用命令和 npm
类似,迁移学习成本低,基本看一遍官方文档就能上手。
这里可以看到我们项目改用 pnpm
之后仓库的大小对比:
右边为pnpm,占用空间少了好几个G。