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

Posted

技术标签:

【中文标题】使用 Yarn 工作区/nohoist 时,如何控制 Yarn 为依赖项的 peerDependency 选择哪个版本?【英文标题】:How do I control which version Yarn chooses for a dependency's peerDependency when using Yarn workspaces/nohoist? 【发布时间】:2020-03-22 11:13:25 【问题描述】:

我有一个带有两个包的 Yarn 工作区,watermelon-webwatermelon-native,它们使用最新版本的 react-redux,但使用不同版本的 react。问题是我无法控制react Yarn 为react-reduxpeerDependency 选择哪个版本。

工作区package.json:


    "private": true,
    "workspaces": 
        "packages": [
            "watermelon-web",
            "watermelon-native"
        ],
        "nohoist": [            
            "**/watermelon-native/react-redux"
        ]
    

(需要 nohoist 来防止运行时错误)

watermelon-web/package.json:


  "name": "watermelon-web",
  "dependencies": 
    "react": "^16.12.0",
    "react-redux": "^7.1.3"
  

watermelon-native/package.json:


  "name": "watermelon-native",
  "dependencies": 
    "react": "16.8.3",
    "react-redux": "^7.1.3"
  

同时,react-redux 有一个 peerDependency "react": "^16.8.3"

我想要发生的事情: Yarn 安装后,watermelon-native/node_modules/react-redux/node_modules 不包含react。这样,当react-redux 在运行时尝试导入react 时,它会从watermelon-native/node_modules 获得react@16.8.3

实际发生的情况: Yarn 将 react@16.12.0 安装在 watermelon-native/node_modules/react-redux/node_modules 中。当我运行 watermelon-native 时,React 报告“无效的钩子调用”,因为 watermelon-native 正在使用 react@16.8.3,但 react-redux 正在使用 react@16.12.0。 (两个包必须使用完全相同的 React 实例才能使 React 挂钩工作。)

如何让 Yarn 按我想要的方式工作?

我尝试过使用Yarn selective dependency resolutions,也就是package.json 中的“决议”元素,几乎所有可能的方式,但Yarn 的行为没有明显变化。例如,我尝试添加

"resolutions": 
    "**/watermelon-native/react-redux/react": "16.8.3"

到工作区package.json

两个简单的“解决方案”是在我的所有包中使用相同的 React 版本(需要将 watermelon-web 降级到 16.8.3)或放弃使用 Yarn 工作区。如果可能,我希望避免这些缺点。

(注意:我的代码示例来自 React Native 开发,但问题本身仅适用于 Yarn,与 React 无关。reactreact-redux 可以替换为具有足够相似依赖关系的任何其他包.)

【问题讨论】:

【参考方案1】:

认为这个问题的答案只是“Yarn 不能那样工作”,至少目前是这样。

与此同时,我找到了一个简单的解决方法。由于从watermelon-native/node_modules/react-redux/node_modules/react 中删除react 文件夹可以解决问题,因此我添加了一个postinstall 脚本,该脚本会在每次安装后删除react 文件夹。

我的 PowerShell 脚本(使用你喜欢的任何 shell)

function TryRemove-Path($path) 
    if(Test-Path $path) 
        Remove-Item -Recurse -Force $path
    



TryRemove-Path("$PSScriptRoot/node_modules/react-redux/node_modules/react")

这很 hacky,但即使是 Expo 项目也依赖 postinstall magic 来让他们的 React Native 应用程序与 yarn 工作区一起工作。所以也许这个解决方法还不错。

【讨论】:

以上是关于使用 Yarn 工作区/nohoist 时,如何控制 Yarn 为依赖项的 peerDependency 选择哪个版本?的主要内容,如果未能解决你的问题,请参考以下文章

带有 Nextjs 和 React-native 的 monorepo 中的 Nohoist:无法解决反应

纱线工作区:nohoist exclude

工作空间仍在吊装的 nohoist

使用 yarn 工作区和 react-router-dom v6 时如何正确继承上下文?

Zeppelin 坚持在 YARN 工作

如何使用 Yarn 2+ 列出每个公共工作区?