在子位置运行时反应脚本父文件夹node_modules错误

Posted

技术标签:

【中文标题】在子位置运行时反应脚本父文件夹node_modules错误【英文标题】:react-scripts parent folder node_modules error when running in child location 【发布时间】:2020-03-22 05:07:29 【问题描述】:

当在子文件夹 (c:\Repos\web_app1\api_ui) 中运行 react-scripts build (Create-React-App) 和它自己的 package.jsonnode_modules 文件夹等时,我收到以下错误:

 react-scripts build


There might be a problem with the project dependency tree.
It is likely not a bug in Create React App, but something you need to fix locally.

The react-scripts package provided by Create React App requires a dependency:

  "babel-loader": "8.0.4"

Don't try to install it manually: your package manager does it automatically.
However, a different version of babel-loader was detected higher up in the tree:

  c:\Repos\web_app1\node_modules\babel-loader (version: 7.1.4)
将父文件夹的 (c:\Repos\web_app1) babel-loader 更新到 v8.0.4 不是一个选项,因为 web_app1 依赖于 babel-loader v7.1.4 不能删除 c:\Repos\web_app1 中的 node_modules。这是父应用程序,需要自己的node_modules。 我的解决方法是将SKIP_PREFLIGHT_CHECK=true 添加到.env 文件中。这似乎是一个 hack,我想要另一个涉及通过预检检查构建的修复程序。 子文件夹(c:\Repos\web_app1\api_ui)中的package-lock.json有正确的babel-loader版本(8.0.4),那为什么会去父文件夹呢?

在子文件夹中构建 react-scripts 时,有没有办法忽略父文件夹或更高的树 node_modules

【问题讨论】:

我也遇到了同样的问题,你解决了吗? 这能回答你的问题吗? react-script problem while having a node_module folder in the parent directory 【参考方案1】:

这也让我很困惑,我做了一些研究,查看了react-scripts版本4.0.3的源代码。此版本需要babel-loader v. 8.1.0。安装了storybook(需要版本^8.0.0),我们在顶层node_modules 中得到一个不同的babel-loader,因此我们最终得到:

|-src
|-node_modules
  |
  |-storybook 6.3.12
  |-babel-loader 8.2.6
  |-react-scripts 4.0.3
    |
    |-node_modules
      |
      |-babel-loader 8.1.0

我收到与很多人看到的相同的错误消息,我想我自己,不应该在react-scripts 中使用babel-loader 在它自己的babel-loader 中获得babel-loader,即版本8.1.0?我可以多次删除node_modulespackage-lock.json,而且问题似乎一直存在。

您在问题中如何描述它实际上是包管理器(至少npm)如何工作,例如从react-scripts 导入babel-loader 会从它自己的node_modules 给它版本8.1.0...但是我们忘记了两件事,它们结合起来会导致问题:

包吊装 传递依赖

吊装

我不会详细说明何时发生包裹提升,但它确实发生了。基本上,它相当于将依赖包A 的依赖包B 添加到项目根node_modules(或其他一些父node_modules),而不是添加到Anode_modules

所以不是

|-src
|-node_modules
  |
  |-A
    |
    |-node_modules
      |
      |-B

...我们得到...

|-src
|-node_modules
  |
  |-A
    |
    |-node_modules (might exist anyway)
  |-B

由于npm 的工作方式(并且正如您在问题中正确理解的那样),如果在node_modules/A/node_modules 中找不到B,它将在node_modules 中查找包,这使得它可以工作。当许多包都需要兼容的依赖项时,提升可以是一种优化,这样我们就可以只存储一个,而不是存储 N 个相似版本的依赖项。它还简化了项目根目录node_modules 的文件夹结构,从而更易于调试。事实上,默认是吊起任何可以吊起的包,例如node_modules 中尚不存在要提升到的对象。

通常,每当我们有冲突的包版本时,都会使用“包的所有依赖项都在它自己的node_modules”中的天真的策略。这就是上面例子中发生的情况,有两个不同版本的babel-loaderstorybook 确实由几个包组成,其中多个包使用babel-loader 版本^8.0.0。当storybook 安装在react-scripts 之前时,它会采用满足约束的babel-loader 的最新版本,并将其提升到顶层node_modules。这会在安装react-scripts 时导致常见的问题。我有另一个具有相同设置的项目,但是在storybook 之前安装了react-scripts。在那里,babel-loader 版本 8.1.0 被吊起,并且由于这个包也满足 storybook (^8.0.0) 的要求,因此不再需要 babel-loader。在这里,create-react-scripts 没有抱怨。当然,npm 可以自己计算出这个顺序当然是可取的,这从存储的角度来看也是最佳的(只有一个 babel-loader 而不是两个),但据我所知,npm 使用字母顺序时处理依赖关系。

传递依赖

尽管包 A 是我项目的依赖项,A 也可以拥有自己的依赖项。这些是关于我的项目的传递依赖项。

为什么它不起作用?

react-script 版本4.0.3 的源代码中,文件verifyPackageTree 负责运行检查帽,导致问题中出现无聊的错误消息。这个文件在以后的预发布中不再存在,但在它的顶部,我们可以找到评论:

// We assume that having wrong versions of these
// in the tree will likely break your setup. 
// This is a relatively low-effort way to find common issues.

下面几行写着:

// These are packages most likely to break in practice.
// See https://github.com/facebook/create-react-app/issues/1795 for reasons why.
// I have not included Babel here because plugins typically don't import Babel (so it's not affected).

查看引用的线程,讨论了为什么create-react-app在安装不兼容的依赖项时会中断,问题与上述相同... 为什么不起作用?

最后的结论似乎是,例如,如果react-scripts 导入一个已被提升的包X,则该包不会驻留在react-scripts 下的node_modules 中,而是位于根@ 987654389@,其中(相对于最上面的示例)还有babel-loader 版本8.2.6 驻留(与react-scriptsnode_modules 文件夹中的版本8.1.0 相对)。现在如果 X 要导入 babel-loader,它会得到错误的 babel-loader,例如不是预期的版本8.1.0,而是8.2.6。在线程中,这被认为是npm 中的一个错误,即使我不完全知道为什么它会是一个错误。也许,可能会有一些标志表明是否可以吊起一个包裹,因为如果完全吊装被认为是一个错误,这似乎是一种倒退。

因为create-react-app 的编写者不知道某些依赖项是否被提升,所以他们实现了这个简单的检查,它会抛出一个警告。对于高级用户,他们有机会使用SKIP_PREFLIGHT_CHECK 标志选择退出检查。另外,最好记住错误来自create-react-app,而不是npm,所以它实际上并没有说明npm 的工作原理,只是create-react-app 的创建者认为的问题(这是最初确实同样令人困惑)。

【讨论】:

以上是关于在子位置运行时反应脚本父文件夹node_modules错误的主要内容,如果未能解决你的问题,请参考以下文章

将 node_modules 文件夹移动到父文件夹并收到此错误

如何将值从子脚本传递给同时运行的父脚本?

请问用C#编写的MDI程序,为啥我从父窗口通过按钮打开子窗口时,父窗口的按钮会在子窗口中显示?

运行节点脚本时出错,找不到模块 'mongodb/node_modules/bson'

阻止写入标准输出

在父组件中反应 HandleClick