大家好我是堂主,今天水一篇文章,探索下主流包管理工具的依赖安装机制和问题。
(同步发布在我的公众号:咪仔和汤圆
,欢迎关注~)
到目前流行的三种安装和管理工具:npm
、yarn
和pnpm
,通过一个例子来进行演示,创建一个pm-demo
工程,工程里面包含两个dependencies
:
"dependencies": {
"@awefeng/state-machine": "1.1.2",
"@awefeng/npm-template": "1.0.1"
},
其中,state-machine
是用npm-template
作为模版写的,这两个包的有相同的依赖。
npm1.0+的安装机制
npm1.0+
版本采用的是树形结构进行安装,没有对依赖进行优化,使用到的库的依赖里面如果有相同的库,则会重复下载:
pm-demo
├─ @awefeng/state-machine
| ├─ @babel/runtime-corejs3
└─ @awefeng/npm-template
├─ @babel/runtime-corejs3
可以从图上看到,重复安装了相同版本的@babel/runtime-corejs3
,优点就是结构清晰,缺点很明显就是重复下载、占用过大、依赖包层级太深(路径过长在window
系统下会出问题,详见参考[1])。
npm3.0+、yarn
npm3.0+
以后采用了和yarn
一样的机制,将所有依赖包都进行扁平化处理,即将所有的依赖包都放在工程根目录下的node_modules。如果有相同库但是版本要求不一样,则是将某一个版本的先放到根目录的node_modules
下,遇见库的其他版本的时候,再放到对应依赖的node_modules
下。
pm-demo
├─ @awefeng
| ├─ state-machine
| ├─ npm-template
└─ @babel/runtime-corejs3
上面两张图分别是在npm8
和yarn1.22.x
安装依赖生成的。
针对需要安装不同版本的情况,很好验证,我们在工程根目录里添加低于7.18.3
的@babel/runtime-corejs3
(吐槽这个包最低版本都是7.x
,本来想安装个6.x
进验证),看一下怎么安装的:
"dependencies": {
"@awefeng/state-machine": "1.1.2",
"@awefeng/npm-template": "1.0.1",
"@babel/runtime-corejs3": "7.4.5"
},
没错,安装了3次,7.4.5
的安装了一次,7.21.0
的分别在state-machine
和npm-template
下又各安装了一次,所以这种依赖安装机制只能说是优化了,但是没完全优化。
还引入了新的问题(下一节讨论),并且也没有很好的解决window
下路径过长的问题:
这里有个小的tip
就是怎么确定哪一个版本放在根目录的node_modules
扁平化?
幽灵依赖
npm3.0+
和yarn
的依赖安装机制引入了“幽灵依赖”问题,在项目中package.json
本来没有引入某一个包,由于扁平化的原因,在代码中却能使用,比如我们项目没有引入core-js-pure
,却能在代码中使用:
“幽灵依赖”问题会在项目某些包升级或者某些依赖包更新等情况下出现严重问题(详见参考[2])。
pnpm
如何很好的解决路径过长、重复安装、幽灵依赖的问题?
pnpm
给出了答案:通过硬链接和软链接(详见参考[3],软链接也叫符号链接)来连接依赖,将依赖统一存储在一个store
里并且进行了相同依赖不同版本的文件复用。
pnpm安装依赖大致有以下几个步骤:
- 解析依赖树并下载依赖到全局
store
(可以通过pnpm store path
查看) - 计算出根目录的文件结构
- 链接依赖
第一步解析下载没什么好说的,其中要注意的就是相同库的不同版本之间相同文件的复用,以及pnpm
中解析,下载两个阶段是并行的(注意链接阶段不是,链接阶段至少是要确定好了目录以后):
第二步是计算出文件结构,pnpm
分析出具体需要的依赖树和文件复用,pnpm
首先会将node_modules
初始化为.pnpm
和直接依赖项
第三步在.pnpm
中通过硬链接连接所有的依赖项,然后和.pnpm
同级下只出现项目的直接依赖,直接依赖通过软链接连接到.pnpm
下。
更详细的解释查看官网阐述的基于符号链接的node_modules
(详见参考[4])。
同样举例我们的demo
,生存的node_modules
文件目录如下:
end
下一篇探索下workspace
机制和在有peer
依赖下的安装机制。
参考文章:
[1] Window最大路径长度限制:learn.microsoft.com/zh-cn/windo…
[2] 幽灵依赖:www.kochan.io/nodejs/pnpm…
[3] 硬链接和符号链接:abcfy2.gitbooks.io/linux_basic…
[4] 基于符号链接的node_modules结构:pnpm.io/symlinked-n…