从一次依赖下载失败理解npm、yarn install策略

从一次依赖下载失败理解npm、yarn install策略

工具版本

  • nodejs: v14.21.2
  • npm: 6.14.17
  • yarn: 1.22.19

问题现象

在一次删除lock文件重新下载依赖时,原本能够正常下载的依赖,现在却报错:node版本太低,导致下载依赖失败。特记录此次问题出现的原因。

假设现在项目有两个依赖 marked, simplemde

1
2
3
4
"dependencies": {
"marked": "^0.3.19",
"simplemde": "^1.11.2"
}

simplemde 内部又依赖了marked

1
2
3
4
"dependencies": {
...
"marked": "*"
},

发现marked有两个依赖版本marked@*, marked@^0.3.19, 也可以说项目添加marked依赖的目的就是为了控制simplemde中的依赖marked的版本。然而yarn在下载依赖的时候,将依赖中的子依赖也平铺开了下载。

此时:marked@* 指定的依赖版本是 5.0.4 而 自2023-05-02发布的marked@5.0.0开始, 对node的版本要求直接从 12 升至 18,导致engines.node版本校验不通过,下载报错。

1
2
3
4
5
6
7
// marked/v5.0.0/package.json
{
...
"engines": {
"node": ">= 18"
}
}

对比 npmyarn 下载依赖

通过npm install下载依赖 (npm version: 6.14.17)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
...
// package-lock.json
"marked": {
"version": "0.3.19",
...
},
"simplemde": {
"version": "1.11.2",
...
"requires": {
...
"marked": "*"
}
},
...

package-lock.json中, 将marked 锁在 version: 0.3.19

通过 yarn 下载依赖 (yarn version: 1.22.19)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
// yarn.lock
...
marked@*:
version "5.0.4"
...

marked@^0.3.19:
version "0.3.19"
...

simplemde@^1.11.2:
version "1.11.2"
...
dependencies:
...
marked "*"
...

yarn.lock 中确有两个marked依赖版本

问题原因

而一开始在项目中指定marked: ^0.3.19也就是为了限制子依赖版本在0.3.*, 但是现在使用yarn下载会校验子依赖中的marked@*,导致下载中断, 但是使用npm下载却不会有这个问题。

虽然可以通过配置忽略版本校验,但是根本原因还是yarn重复校验下载了依赖。

了解yarninstall流程

  • Resolving packages: 分析包的依赖关系及版本信息
  • Fetching packages: 下载依赖项,存储到缓存中
  • Linking dependencies: 将缓存中的包扁平化的安装到项目当中去
  • Building fresh packages: 构建安装, 执行install阶段的scripts

测试校验

  • 首先清空缓存

yarn 查看缓存路径:yarn cache dir, 清空缓存:yarn cache clean --force

npm 查看缓存路径:npm config get cache, 清空缓存:npm cache clean --force

使用yarn下载,下载失败

pPiXFjH.png

pPiXAud.png

这里倒是可以通过忽略engines来通过下载

1
2
# 忽略engines校验
yarn config set ignore-engines true

npm install的过程发生了什么

当存在嵌套依赖和根级依赖冲突时,npm会根据以下规则来确定使用哪个依赖项:

  • 直接依赖优先: 根级依赖的优先级更高,它们将覆盖任何嵌套依赖中的相同包。
  • 版本范围解析: 如果根级依赖和嵌套依赖都有对同一个包的依赖,并且它们的版本范围不冲突,npm会尽量满足两者的依赖关系,并使用符合两者版本要求的最高版本。
  • 版本冲突解析: 如果根级依赖和嵌套依赖对同一个包有不兼容的版本要求,npm会尝试解决版本冲突,通常会选择满足所有依赖关系的最高版本,并通过符号链接或软链接来确保正确的依赖关系。

npm如何解决有版本冲突的依赖包

现在我一个项目有两个依赖, marked@^0.3.19, 和 自己发的包 avatar0813-pkg-t

其中avatar0813-pkg-t包依赖 marked@^5.1.2

pPiOQmR.png

pPiOKX9.png

pPr2oJs.md.png

问题: node_modules 中的avatar0813-pkg-t 包中间还有个node_modules

这正是npm install解决版本冲突策略,因为两个依赖marked@^0.3.19,marked@^5.1.2版本不兼容导致的,两个依赖都要,但是不能扁平化安装

pPiOnl4.png

如果将avatar0813-pkg-t 包中依赖改为的marked@*以兼容外部版本则不会出现这个问题。

亦或这指定resolutions依赖从而解决冲突

pPixWGV.md.png


从一次依赖下载失败理解npm、yarn install策略
https://avatar0813.github.io/2023/08/03/frontEnd/从一次依赖下载失败理解npm、yarn install策略/
作者
avatar
发布于
2023年8月3日
许可协议