如何使用 `yarn` 覆盖嵌套依赖项?

Posted

技术标签:

【中文标题】如何使用 `yarn` 覆盖嵌套依赖项?【英文标题】:How do I override nested dependencies with `yarn`? 【发布时间】:2017-03-06 17:11:07 【问题描述】:

如果我的包有这些依赖项

 "name": "my-package",
  "dependencies":  "foobar":"~1.0.3", "baz":"2.0.9" 

foobar 包有这些依赖

 "name": "foobar",
  "dependencies":  "baz":"^2.0.0" 

最新发布的baz 版本是2.1.0,第一次运行yarn 将在baz@2.1.0 中安装baz@2.1.0

我如何强制 yarn 为 foobar 使用 baz@2.0.9 包?

我的理解是,使用npm shrinkwrap(也就是this question)可以做到这一点。


我的问题的总结可能是:Yarn 创建了可重复的、确定性的安装,但我如何自定义该安装?

【问题讨论】:

你们找到答案了吗? @atomman 实际上我认为我在这个问题的基础上是错误的。 Yarn 已经确定我的***包版本号和另一个依赖项的子依赖项之间存在不兼容。所以它正确地决定为依赖提供它自己版本的库。 感谢您的回答。虽然我不确定我是否同意,因为 baz@2.0.9 会满足所有要求。虽然它可以被视为一个特性,即纱线总是为子模块提供最新的依赖关系。然而,我确实觉得 yarn 应该为这些情况提供依赖解决机制,但那是另一个讨论。 :) @atomman 哦,是的,我同意你的看法(以及我的问题中的前提),但我认为我实际上遇到的真正问题与那个略有不同我在我的问题中描述了。 【参考方案1】:

如果您确实有一个子依赖项,它在接受哪些版本方面受到过度限制,您可以使用 yarn 覆盖它们。

更新编辑: 现在,从 1.0 开始,officially supports“分辨率”块。所以覆盖分辨率的方法就是在package.json中添加这样的块:

"resolutions": 
      "package-a": "2.0.0",
      "package-b": "5.0.0",
      "package-c": "1.5.2"

您有时会收到有关“不兼容”版本的警告,但我发现某些软件包(如 socket.io)过度限制了它们接受的版本,因此我很乐意选择当它实际上并没有破坏时的最新版本。

下面是原始但过时的答案。

听起来原来的问题并不完全正确,但原来的问题实际上我想要回答的问题,我找到了答案,所以这里是为了后代: p>

我正在使用 socket.io 库,它具有 component-emitter 作为依赖项。但它有一对它需要的版本。这是我更改任何内容之前 yarn.lock 文件的样子:

component-emitter@1.1.2:
  version "1.1.2"
  resolved "https://registry.yarnpkg.com/component-emitter/-/component-emitter-1.1.2.tgz#296594f2753daa63996d2af08d15a95116c9aec3"

component-emitter@1.2.0:
  version "1.2.0"
  resolved "https://registry.yarnpkg.com/component-emitter/-/component-emitter-1.2.0.tgz#ccd113a86388d06482d03de3fc7df98526ba8efe"

所以它在我的客户端代码中包含了组件发射器的两个副本。我看了看,在 1.1.2 和 1.2.0(或当前的 1.2.1)之间似乎没有任何重大变化。我首先尝试更改 yarn.lock 文件:

component-emitter@1.2.1, component-emitter@^1.2.1, component-emitter@1.1.2:
  version "1.2.1"
  resolved "https://registry.yarnpkg.com/component-emitter/-/component-emitter-1.2.1.tgz#137918d6d78283f7df7a6b7c5a63e140e69425e6"

这行得通,但文件有关于它被自动生成的警告,这意味着我添加的每个更新或新包都会踩到这个更改。稍作搜索发现yarn --flat选项,这将强制yarn在整个项目中选择不超过每个包中的一个。这对我来说似乎有点矫枉过正,因为我确信旧包和新包之间存在不兼容的实际情况。我只是想从我的客户端代码中删除一个冗余包,以使下载更小;我仍然希望开发包能够正确地工作

但在yarn --flat 的文档中,我找到了对可以放入 package.json 的“解决方案”块的引用:

"resolutions": 
  "package-a": "2.0.0",
  "package-b": "5.0.0",
  "package-c": "1.5.2"

所以我尝试将"component-emitter" : "1.2.1" 放在我的 package.json 中的一个新“分辨率”块中,实际上它在所有需要它的地方将组件发射器扁平化为 1.2.1,现在我只有一个副本我的客户代码。

(现在yarn 完全支持resolutions 块,所以你甚至不需要使用--flat。)

【讨论】:

非常感谢您的回答。所以我想解决方案至少部分是“编辑 yarn.lock 文件”,这是我一开始就害怕做的事情。但是,yarn 不会特意去核对那个文件是有道理的。 为我工作而不接触package.json。拥有async-busboy dep 并想更改其子dep 的版本-busboy。所以我只是用busboy "mscdex/busboy#76c3d58" 替换了busboy "0.2.13",运行yarn install,瞧,一切正常。奇怪的是,yarn 并没有更新锁文件中的“busboy”块,但这并没有让我太困扰,只要它有效。 当然,只要你只使用纱线。但是,如果其他人出现并运行npm install,他们会得到错误的版本。我认为如果你修改这两个它可能仍然有效,虽然不像使用纱线那样细粒度 - 如果你正在安装的是你添加的另一个包的依赖项,“解决方案" 至少应该覆盖新的包依赖关系,这样你就不会得到同一个包的多个版本。 不会以稳健的长期方式工作。只要yarn upgrade 运行,yarn.lock 文件就会被覆盖,并且package.json 中的resolutions 部分会被嵌套依赖项忽略。 @MichaelPlotke 现在 Yarn 1.0 正式支持“分辨率”部分,所以我的回答又有效了。 :)【参考方案2】:

现在可以使用 yarn 的 selective version resolution feature。

在您项目的package.json 中,使用resolutions

  "resolutions": 
    "foobar/**/baz": "2.0.9"
  

这会覆盖 foobar 的包 foobar(以及它下的任何其他包)版本的 baz,强制其为版本 2.0.9。

【讨论】:

不适用于工作区 :( 请参阅我上面的评论。 @Marecky 它确实适用于工作区,但您必须将分辨率放在*** package.json 中【参考方案3】:

编辑:现在已弃用,请改为阅读此答案:

https://***.com/a/46615878/2398593


@SomeCallMeTime 的answer 很棒,我们已经在工作中这样做了一个月。

不幸的是,这在 v0.24.x 之后不再可能(请参阅 comment)。

有一个已打开的 PR on Github 带有 RFC 建议,以便有一种简单的方法来处理该用例,而无需密切关注生成的锁定文件。

【讨论】:

我的答案从 1.0 开始再次起作用。请参阅更新的编辑。 :) 注意:这个答案已经过时了

以上是关于如何使用 `yarn` 覆盖嵌套依赖项?的主要内容,如果未能解决你的问题,请参考以下文章

使用 Yarn 工作区/nohoist 时,如何控制 Yarn 为依赖项的 peerDependency 选择哪个版本?

如何使用 npm install 或 yarn 仅安装具有自己版本的 package.json 依赖项

yarn 如何找到作为开发依赖项安装的模块

如何强制 Yarn 重新安装软件包?

如何解决 Yarn.lock 中开发依赖项的特定依赖项

在 docker 容器内安装依赖项后如何复制回主机 package-lock.json/yarn.lock?