发现依赖的依赖要升级怎么办?

2,758 阅读3分钟

有时候你可能会遇到依赖包版本的冲突问题,项目依赖了两个不同版本的同一个依赖包,这时候就可能会出现问题,例如,我们有以下包及其依赖项:

package-a@1.0.0
 |_ package-d1@1.0.0
     |_ package-d2@1.0.0

package-a@2.0.0
 |_ package-d1@2.0.0
     |_ package-d2@1.0.0

package-b@1.0.0
 |_ package-d1@2.0.0
     |_ package-d2@1.0.0

package-c@1.0.0
 |_ package-a@2.0.0
     |_ package-d1@2.0.0
         |_ package-d2@1.0.0

此时你可能发现package-d1package-d2等node_moudles中的子包需要更新(下面我们称其为间接依赖包),但又不能改变package-apackage-bpackage-c等直接依赖的包,你会怎么做呢?

答案是,你可以使用yarn的resolutions字段解决这个问题,resolutions允许你指定一个特定的依赖包版本,以便确保在项目中使用的所有依赖包都使用相同的版本。它可以在package.json文件中定义,用于覆盖其他依赖包的版本。在以下情况下,你可能需要使用yarn的resolutions:

  1. 当你遇到依赖包版本冲突时,使用resolutions可以解决这些冲突。
  2. 当你需要强制使用一个特定版本的依赖包时,使用resolutions可以实现这一点。
  3. 当你需要升级依赖包版本时,使用resolutions可以指定一个新版本,以确保它与其他依赖包兼容。

下面我们来具体看看如何设置resolutions。

更新所有指定的间接依赖包

假如你想要更新所有名为package-d1的间接依赖包,你可以在package.json中按下面这样设置:

// package.json
"dependencies": {
    "package-a": "1.0.0",
    "package-b": "1.0.0"
},
"resolutions": {
    "**/package-d1": "2.0.0"
}

yarn将用于package-d1@2.0.0每个嵌套的依赖项,并且通过不重复安装package-d1 来按照预期对文件夹进行操作。

更新指定依赖包的依赖包

也可能你只希望更某个特定位置的间接依赖包,你可以通过指定依赖包来定位它,如下:

// package.json
"dependencies": {
    "package-a": "1.0.0",
    "package-b": "1.0.0"
},
"resolutions": {
    "package-a/package-d1": "3.0.0"
}

这样设置,yarn 将package-d1@3.0.0只用于package-a并且package-b仍然有package-d1@2.0.0它自己的node_modules

当一个依赖包被直接和间接依赖时

例如我们开头的包结构中,package-a被项目直接依赖,同时被package-c依赖时,如果你只希望更新被package-c依赖的间接依赖包,你可以按下面这样设置:

// package.json
"dependencies": {
    "package-a": "1.0.0",
    "package-c": "1.0.0"
  },
  "resolutions": {
    "**/package-a": "3.0.0"
  }

直接依赖包package-a还是保持1.0.0,只是package-c中的package-a会被更新为3.0.0。

无效设置

如果你未指定间接依赖包所在的路径,而是直接写间接依赖包名的话,这样的设置是无效的。

// package.json
"dependencies": {
    "package-a": "1.0.0",
    "package-c": "1.0.0"
},
"resolutions": {
    "package-a": "3.0.0"
}

规律总结

你应该总是使用 glob 模式来设置,以下为resolutions的设置总结:

  1. a/b表示项目依赖a的直接嵌套依赖b。
  2. **/a/b表示项目所有依赖的直接嵌套依赖b和嵌套依赖a。
  3. a/**/b表示项目的依赖a的所有嵌套依赖b。
  4. **/a表示项目的所有嵌套依赖a。
  5. a**/a 的别名(为了追溯兼容性,因为如果它不是这样的别名,它就没有任何意义,因为它代表了一个非嵌套的项目依赖项,它不能被覆盖为下面解释)。
  6. ** 表示项目的所有嵌套依赖项。