当前位置:网站首页 > Node.js开发 > 正文

升级node后yarn安装依赖提示node-sass报错(node install 下载依赖报错)



感谢神奇的 Semver 动态规则,npm 社区经常会发生依赖包更新后引入破坏变更的情况(应用没有使用依赖锁的话),而应用开发者就要在自己的依赖声明里先临时绕过,避免安装到有问题的版本,如果是一级依赖,只需要改 package.json 的声明就可以了,但如果是子依赖,就需要进行版本重写(overrides/resolution)了。

本文是一篇针对版本重写功能的指南性文章,当你遇到如下的问题时,就可以按照对应的依赖重写语法,解决这些依赖问题了:

  1. 临时版本修复:需要临时把有问题的子依赖(依赖的依赖)版本降级或升级到正常的版本上。如降级有 Breaking Change 的 @babel/generator。
  2. 强制升级子依赖:使用的 一个包更新频率较慢,想更新其子依赖时。如一个老的构建依赖依赖的 css-loader 需要更新到新版本。
  3. 依赖多版本统一:React/Webpack 等包出现多个版本,造成构建或运行时问题,需要统一项目对应依赖的版本到一个版本上。
  4. 子依赖重写:某个子依赖 A 依赖特定版本的 B 时会造成问题,仅需要重写依赖 A 下 B 的版本时。
  5. 删除子依赖:想删除某些子依赖不正确的依赖时,如子依赖把 devDependencies 写到 dependencies 里,或者写错 semver 的,开发者又没有权限发布这个不规范的包,需要删除或者替换子依赖的 Semver 声明。如不规范的依赖包中把应该在 devDependencies 里的包写在了 dependencies 里。
  • 一级依赖:直接声明在 package.json 的 (dev | optional | peer) dependencies 中的依赖。
  • 子依赖:一级依赖的依赖,无法由应用开发者直接指定版本。
  • 嵌套重写:指仅重写某个依赖下的一级依赖或者子依赖(限制 Scope 重写依赖版本)。

阿里的前端开发者使用的包管理软件,除了社区常用的 npm, yarn 以及 pnpm 外,还有阿里内部特有的 tnpm 及其不同 mode。他们各自都有不同的依赖安装模式及依赖版本重写的语法,按大版本及语法的不同,把他们分为如下几类:

npm

yarn

tnpm

pnpm

npm@5-6

tnpm@8 (npm mode)

npm@8

tnpm@9 (npm mode)

yarn@1 (classic)

tnpm@* (yarn mode)

yarn@3 (berry)

tnpm@*

pnpm@<6.3.1

pnpm@>6.3.1

依赖重写语法

不支持(需 Hack)

overrides

resolutions

resolutions (yarn 3 语法)

resolutions (yarn 1 语法)

resolutions (pnpm 语法)

pnpm.overrides

锁文件版本

package-lock.json@1

package-lock.json@2

yarn.lock@1

yarn.lock@6

不支持

pnpm-lock.yaml

本部分针对每一种语法都进行了详细的解释与简单的案例,在最后还有实际的例子可以供读者更好的理解使用场景。如果是紧急解决问题,建议先看对应包管理软件的语法,补充参考案例,以更快的解决问题。

注:该字段主要在 npm 8 最新版上被支持,npm 7 及以下的版本中并没有这个能力,不过到还是有办法在旧版 npm 上用上这个能力,如果一定要使用 npm 6,请跳转到下一个子标题 Npm 6 Overrides (Hack)。

基本语法

使用前记得更新 npm 到最新版:npm i -g npm@latest

基本的语法有点类似于 CSS 的选择器 - 声明语法,选择器用于匹配到包,声明用于重写版本声明。

在如下的例子中,示范了所有选择器和重写版本的语法:

这个例子中的声明,都是全局替换,无论是子依赖还是子依赖的依赖,只要匹配到选择符,就会应用规则。

嵌套重写

除了全局替换之外,也可以对特定包的子依赖进行重写。在嵌套结构中,用 “.“ 代表嵌套的包本身,有点像 less 里的 &。

当出现多个规则应用到同一个包上时,嵌套越深的规则优先级越高:

最后安装的结果是:

  1. 所有 foo 包的版本被设定成 1.0.0
  2. foo 下的所有 boo 包被设定成 3.0.0
  3. 除了 foo 下的,所有其它的 boo 包被设定成 1.0.0

另外需要注意的是,成文时的 npm 版本有个小问题,在嵌套重写中判断一个规则是否被删除时,判断的是父依赖的规则是否存在,下面的变动将不会把原来的嵌套重写规则从锁中删除:

首次重写:

仅删除嵌套重写,锁文件依赖保持被重写的状态:

删除父级依赖的声明,才会把依赖状态修正成无修改的状态:

特殊规则

Overrides 有几条特殊规则,一般在简单情况下遇不到,但还是要学习下,以避免发生预期外的行为。

首次从 package-lock v1 升级到 package-lock v2 时,overrides 可能不生效

如开头的表格中提到的,package-lock v1 是 npm@6 生成的锁,package-lock v2 是 npm@8 生成的锁。在升级 Node 或者主动升级 npm 后,可能见到下面这个提示:

overrides 可能并没有生效,重新再跑一次 npm i 就可以了。

另外,当选择器带版本范围时(如 "ms@^2": "1"),从老锁升级的新锁也有可能不应用 overrides 规则(是 npm 的 bug,如果用到了要观察一下锁文件更新的状态)。如果没生效,把版本范围去了,或者删除锁重新生成即可。

一个相关的 Issue:https://github.com/npm/cli/issues/5051

重写不能与 dependencies 声明冲突

overrides 与各类在 package.json 中直接声明的 dependencies 不能出现冲突,如:

会出现 EOVERRIDE 的报错:

一个包只能被一条规则匹配

也可以理解为:当一个包先匹配了一个选择器后,就会停止后续的匹配。也即先遇到的规则优先级最高,如:

如果我们调转上面这个例子的顺序,会产生另一个问题:

比如依赖中有一个 debug@4,他会被重写到 debug@3,此时,要不要继续应用 debug@3 的重写规则呢?

答案是:会继续应用,因为重写之后重新从上至下匹配时,会先匹配到上面的规则,进而应用 ms 的重写规则。最后的结果是,debug@4 变成 debug@3debug@3 依赖的 ms@2 也会被重写到 ms@1

不过笔者非常不建议在 overrides 中这样写,会造成理解上的混乱。

一个包只要匹配了选择器或者重写的目标,就算该规则被匹配

成文时 npm@8.19 尚未完全实现这个能力,目前遇到多重重写的,这些重复的规则都会被忽略。但 overrides 设计文档中标注了这个行为,所以还是解释一下。

我们把上面的的例子再稍加修改,加入双层对包自身版本的重写:

注意:"debug": "3" 的语法只是 "debug": { ".": "3" } 的语法糖。

此时,debug@4.3.4 最终的版本是 4.3.3 还是 4.3.2 呢?

npm 引入了另一条规则:如果一个包匹配了选择器(debug@4.3.4),或者匹配了重写目标(debug@4.3.3),都算是这个规则被应用了。结合上面的遇到第一个应用的规则即停止的逻辑,就可以得到确定性的结果,即:

  1. 先匹配 debug@4.3.4,得到 debug@4.3.3
  2. 进行下一轮匹配, debug@4.3.3 与首条规则的 ".": "4.3.3"  匹配,则 debug@4.3.4 整条规则视为已匹配,结束后续匹配。
  3. 最后的重写结果就是 4.3.3

npm 6,7 本身并没有类似于 overrides 的能力,但我们可以利用 npm 8 的算法,生成一颗应用 overrides 规则的依赖树后,再生成 npm 6 兼容的锁文件,来间接达到在 npm 6 上使用 overrides 的能力。

利用 @ali/tnpm-lock-adapter@1.6.0 及以上的版本,可以帮我们利用 npm 8 的算法生成 npm 6 的锁。

配置好 overrides 后,在项目目录下执行如下命令,即可生成应用了 overrides 的兼容 npm 6 的 v2 版本 pacakge-lock.json,此时再利用 npm 6 进行安装,就可以安装到重写后的版本了。

项目如果要持续使用 npm 6,可以在 package.json 的 scripts hook 中配置上面 tnpm-lock-adapter 这个命令,以持续应用 overrides 规则,避免失效。

Yarn 1.x (Classic) 已不再持续维护,Yarn 现在活跃的维护版本是 3.x (Berry)。新老版本的重写语法不一样。

基本语法

与 npm 的选择器不同,yarn 仅支持匹配包名,不支持在选择器中使用版本范围来选择特定包的特定版本。语法与案例如下:

特殊规则

dependencies 声明的优先级高于 resolutions

如果 dependencies 中的一个依赖 a 出现在 resolutions 中,则这个依赖 a 的版本依然是按 dependencies 中的声明安装,但其它包的子依赖中的 a 则应用 resolutions 规则,如:

会得到如下的依赖树:

npminstall mode(默认安装模式)

npminstall 是 tnpm 8,tnpm 9 的默认安装模式。什么都不配的情况下 tnpm 跑的就是这种安装方式。与 yarn 1 的语法一致,不再赘述。

npm mode

即在 package.json 中配置了:

在 tnpm 8 中,npm mode 使用的 npm 版本为 6,不支持 overrides,如果仍需要使用,请参考本文 npm 6 overrides Hack 部分,并开启 lockfile。

在 tnpm 9 中,npm mode 使用的 npm 版本为 8,可以直接像用 npm 8 那样配置 overrides。

yarn mode

即在 package.json 中配置了:

tnpm 自带的版本是 yarn 1,如果仓库没有切换过 yarn 3,则使用的就是 yarn 1 的 resolutions 语法。

不过 yarn 因为自带了版本切换机制,如果你的仓库额外配置了 yarn 3,还是要按 yarn 3 的语法进行配置。

rapid mode

在 tnpm 9 中,使用 rapid mode 安装时:

无论模拟的文件目录结构是 npm(--by=npm) 还是 npminstall,重写的语法与 npm 8 的 overrides 一致,直接使用即可。

基本语法

与 yarn 1 的语法相似,不过在选择器中支持了版本,且不再支持重写嵌套依赖。

另外,可以用 yarn set resolution -s  来修改 resolutions 字段。

特殊规则

resolutions 的优先级比 dependencies 高

当这两个字段中都有同一个包时,dependencies 中的版本声明会被替换掉。

基本语法

pnpm 的语法与 yarn 1 类似,但又不完全一样;另外 "pnpm.overrides" 和 "resolutions" 字段的功能相同,后者是前者的别名,直接看例子:

特殊规则

overrides 的优先级高于 dependencies

如果 dependencies 和 overrides 中都声明了一个包的版本,则 overrides 会覆盖 dependencies 中的声明。如:

会生成如下的 pnpm-lock.yaml

嵌套依赖只会重写一级,不会覆盖全部子依赖

与 yarn 和 npm 的重写规则不同,pnpm 在嵌套使用时,只会重写一级,有点类似于 Less 中的 “>” 语法。如有这样的依赖结构:

在使用如下 overrides 重写时:

会得到这样的依赖树,仅有 qar 的直接依赖被重写了。

假设 @babel/core 依赖的 @babel/generator@7.19.0 出了 Bug,应用需要临时降级到 7.18.0

npm/tnpm npm mode overrides

tnpm/yarn1/yarn3/pnpm resolutions

node-saas 因为其对 Node 版本有强要求,所以经常会在升级 Node 的过程中出现 node-sass 无法安装的问题(gyp Build Error)。

首先我们建议应用开发者更换 sass 实现到 dart-sass,可以从 sass 官网上获取。如果是子依赖中的 node-sass 版本与 node 冲突,则可以使用依赖重写来解决这个问题。

如原使用的 node-sass 为 4.12 ,不支持 Node 16+,即可利用重写强行写到 6.x。假设有如下的依赖树:

npm/tnpm npm mode overrides

tnpm/yarn1/yarn3/pnpm resolutions

一些不规范的包会引入低版本的 webpack,与其它依赖引用的高版本 webpack 冲突,进而造成问题。如下面这个案例,因为项目中存在多个 webpack 版本,提升(hoist)依赖后,根目录的 webpack 版本不一样,导致另一个不规范引用 webpack 的包(mini-css-extract-plugin)引用的版本不兼容。

要修复,需要将项目中的 webpack 版本保持统一,或者升级 @ali/jstracker 中的 webpack 版本。

npm/tnpm npm mode overrides

tnpm/yarn1 resolutions

yarn3 resolutions

pnpm overrides

不知道 npm 有一天能不能真的像它们代码里写的,干掉其它包管理软件,减少点前端开发者需要学的工具的数量……但看目前 Node 的发展趋势,是打算通过 Corepack 和 packageManager 字段,来兼容不同项目下不同的包管理软件了。

不过也正是因为各有所长,才会百花齐放,One for All 的包管理软件还道阻且长呢。前端同学们学不动也得学,毕竟这就是前端生态的特色之一嘛!

  • npm overrides 文档
  • npm Dependency resolution overrides RFC
  • yarn resolutions 文档
  • yarn 1 Selective Versions Resolution RFC
  • pnpm overrides 文档
  • yarn 3 resolutions 文档
  • yarn 3 cli set resolution
  • https://ascii-tree-generator.com/
到此这篇升级node后yarn安装依赖提示node-sass报错(node install 下载依赖报错)的文章就介绍到这了,更多相关内容请继续浏览下面的相关推荐文章,希望大家都能在编程的领域有一番成就!

版权声明


相关文章:

  • nvm安装node配置源(nvm设置默认node版本)2025-03-02 19:45:08
  • node面试问题(node 面试题)2025-03-02 19:45:08
  • node版本管理工具有哪些功能(node版本管理工具有哪些功能和作用)2025-03-02 19:45:08
  • nvm安装node(nvm安装node版本)2025-03-02 19:45:08
  • 安装node.js环境(node.js安装步骤)2025-03-02 19:45:08
  • 安装node.js后idea新建项目没有node.js(idea安装nodejs插件)2025-03-02 19:45:08
  • node新版本(node 版本)2025-03-02 19:45:08
  • node安装不了怎么解决(node下载了安装不了)2025-03-02 19:45:08
  • 升级node版本命令(linux node升级)2025-03-02 19:45:08
  • linux安装Node.js(linux安装node安装包)2025-03-02 19:45:08
  • 全屏图片