本文会以尽量简洁的语言来描述当下主流包管理工具 npm、yarn、pnpm 的管理策略以及进化史,不涉及任何晦涩的代码。

npm - 先锋

2010 年 1 月,一款名为 npm 的包管理器诞生。

很多人认为 npm 是 node package manager 的缩写,其实不是,而且 npm 根本也不是任何短语的缩写。

npm 官方辟谣:

它的前身其实是名为 pm(pkgmakeinst) 的 bash 工具,它可以在各种平台上安装各种东西。

硬要说缩写的话,也应该是 node pm 或者 new pm。

嵌套的 node_modules 结构

npm 在早期采用的是嵌套的 node_modules 结构,直接依赖会平铺在 node_modules 下,子依赖嵌套在直接依赖的 node_modules 中。

比如项目依赖了A 和 C,而 A 和 C 依赖了不同版本的 B@1.0 和 B@2.0,node_modules 结构如下:

node_modules
├── A@1.0.0
│   └── node_modules
│       └── B@1.0.0
└── C@1.0.0
    └── node_modules
        └── B@2.0.0

复制

如果 D 也依赖 B@1.0,会生成如下的嵌套结构:

node_modules
├── A@1.0.0
│   └── node_modules
│       └── B@1.0.0
├── C@1.0.0
│   └── node_modules
│       └── B@2.0.0
└── D@1.0.0
    └── node_modules
        └── B@1.0.0

复制

可以看到同版本的 B 分别被 A 和 D 安装了两次。

依赖地狱 Dependency Hell

在真实场景下,依赖增多,冗余的包也变多,node_modules 最终会堪比黑洞,很快就能把磁盘占满。而且依赖嵌套的深度也会十分可怕,这个就是依赖地狱