开发外部组件时如何避免“loaded two copies of React”错误?

Posted

技术标签:

【中文标题】开发外部组件时如何避免“loaded two copies of React”错误?【英文标题】:How to avoid `loaded two copies of React` error when developing an external component? 【发布时间】:2016-01-14 11:08:38 【问题描述】:

我正在开发一个外部组件(比如说my-component,我用npm link 链接到项目(因为它正在进行中,我需要包来反映更改)。

my-component 文件夹中有node_modules/reactnode_modules/react-dom,因为它们是它的依赖项。但是它们是 peerDependences,所以我不打算将它们带入链接此包的项目中。

但是,当使用npm link 时,它会链接整个目录,包括node_modules。因此,当项目构建时,它包含 2 次包:来自 node_modules/* 和来自 node_modules/my-component/node_modules/*

这开始影响组件在使用ReactDOM.findDOMNode时,会导致这个错误:

Warning: React can't find the root component node for data-reactid value `.0.2.0`. If you're seeing this message, it probably means that you've loaded two copies of React on the page. At this time, only a single copy of React can be loaded at a time.

此外,了解正在发生的事情可能会有所帮助:仅当同时存在 node_modules/my-component/node_modules/reactnode_modules/my-component/node_modules/react-dom 时才会出现问题。如果只有其中一个,则没有错误消息。

通常的包安装不会出现没有node_modules/react-dom这样的错误。

应该如何同时开发外部组件和项目?

【问题讨论】:

我也遇到了同样的问题,我使用React.renderReact.findDOMNode 并忽略了弃用警告。只要我不require/importreact-dom,就不会出现这个错误。 另外,这并不特定于npm link,一旦你npm install 你正在开发的那个组件也会发生在你身上。 所以我的问题最终与您的问题大不相同——我将我的部门与我的其他资产分开汇总,并在我的部门列表中错过了 react-dom 单独汇总。由于react-dom 依赖于react,我最终得到了两份副本,一份在我的deps rollup 中,一份在我的主应用程序包中。更多here. @Varvara Stephanova:你找到解决方案了吗?我好像遇到了同样的问题。 @Varvara Stephanova ***.com/questions/33398396/… 【参考方案1】:

问题是双重的:

    您不能加载 2 个 react 副本。 npm 链接创建一个符号链接,但是“要求”不尊重 符号链接,当它尝试向上导航目录时,它永远不会 找到父项目的反应。

解决方案:

您所要做的就是将组件中的 react 和 react-dom 链接到父项目的 node_modules 文件夹中。

转到你的组件项目并删除 react 和 react-dom 然后做

npm link ../myproject/node_modules/react
npm link ../myproject/node_modules/react-dom

【讨论】:

它有效。但是您的陈述的第 2 条令人困惑。根据我的理解,当你在主项目中加载包时,它会创建一个与主项目不同的 React 实例,这是不允许的。如果我错了,请纠正我。【参考方案2】:

通过将 react-dom 作为别名添加到我的 webpack 配置来修复它

alias: 

    react$: require.resolve(path.join(constants.NODE_MODULES_DIR, 'react')),
    'react-dom': require.resolve(path.join(constants.NODE_MODULES_DIR, 'react-dom'))


【讨论】:

这似乎是一个肮脏的黑客,但它对我有用。谢谢! :) 知道为什么要将键命名为react$'react-dom'?将它们命名为ReactReactDOM 有意义吗? 这很好用。在我的情况下,父项目只是链接这个开发目的,所以它不会在生产中,但即使是,它仍然可以很好地工作。【参考方案3】:

我相信答案是在您的外部组件的package.json 中将reactreact-dom 指定为peerDependencies。尽我所能关注here 和here,npm link 应该(截至npm@3)不再安装peerDependencies(或`devDependencies)。

啊,我刚刚更仔细地阅读了您的帖子,并意识到您已经将它们指定为peerDependencies。因此,我认为答案归结为:

升级到npm@3:

npm install -g npm@3.0-latest

【讨论】:

如果 react 和 react-dom 不在组件的 node_modules 中,browserify 将找不到它们(由于某种原因)。您必须创建指向项目副本的符号链接。 当然,如果链接的组件被不同的项目共享,那么符号链接只会对其中一个是正确的。您甚至不能拥有该组件的两个副本,因为 npm 只允许您链接到一个副本。目前的情况有点糟。唯一好的解决方案是使用 npm 私有模块。【参考方案4】:

比我聪明的人 (@mojodna) 提出了这个解决方案:从外部组件中删除重复的依赖项,并使用项目的这些依赖项的副本解决它们。

第 1 步:从外部组件的 node_modules 中删除依赖项

作为@cleong noted,您不能只从外部组件的node_modules 中删除依赖项,因为您的项目的构建步骤会在遇到外部组件中现在缺少的依赖项时失败。

第 2 步:将项目的 node_modules 添加到 NODE_PATH

要解决此问题,您可以在运行构建步骤时将项目的 node_modules 附加到 NODE_PATH 环境变量。像例如这个:

NODE_PATH=$(pwd)/node_modules/ npm start

(其中npm start 是捆绑外部组件的脚本,例如通过 Browserify、Webpack 等)

事实上,您始终可以将 NODE_PATH 添加到您的构建脚本中,无论您是否已 npm linked 任何内容,它都可以工作。 (让我想知道它是否不应该是默认的 npm 行为......)

注意:我留下了我现有的答案,因为那里有一些对话,这是一个不同(更好)的解决方案。

【讨论】:

这是天才。它真的应该成为 npm 的一部分。【参考方案5】:

问题出在 npm 链接上。 https://github.com/npm/npm/issues/5875

npm 不会将链接目录视为父项目的子项目。

尝试 npm 链接的替代方案:

1) 在package.json中使用相对路径依赖

2) 在你的项目 node_modules 目录中手动包含你的依赖项

3) 使用url路径

基本上除了 npm 链接之外的任何东西

【讨论】:

【参考方案6】:

在我的webpack.config.js 中添加以下内容对我有用:

resolve: 
    alias: 
        react: path.resolve(__dirname, 'node_modules', 'react')
    

我还尝试了DedupePlugin(作为一种可能的补救措施here),但我无法让它发挥作用。

同样有趣的是,当在依赖关系图中的多个位置找到一个模块时,我遇到了相同问题的不同(也许更隐蔽)表现。

一个这样的情况是我的React.PropTypes.instanceOf(SomeType) 约束会发出警告,即使我传入的类型是正确的。这是因为模块存在于node_modules 目录树中的多个位置。由于鸭子打字,代码仍然可以工作,但我的控制台被这些警告弄得一团糟。采用resolve.alias 的方式也会让那些人沉默。

YMMV

【讨论】:

【参考方案7】:

如果您在主项目中使用 Webpack,this solution 可能会起作用。就我而言,project-a 需要project-b。两者都需要 React 和 ReactDOM 0.14.x

我有这个在project-a/webpack.config.js:

resolve: 
  modulesDirectories: ['node_modules'],
  fallback: path.join(__dirname, 'node_modules')
,
resolveLoader: 
  fallback: path.join(__dirname, 'node_modules')
,
project-b 需要 React 和 ReactDOM 作为 peerDependencies in project-b/package.json project-aproject-a/package.json 中需要project-b 作为devDependency(也应该作为dependency 工作) 本地project-b 链接到project-a,如下所示:cd project-a; npm link ../project-b

现在当我在project-b 中运行npm run build 时,更改会立即出现在project-a

【讨论】:

【参考方案8】:

我正在使用ReactJS.net 并从那里的教程中设置 webpack,并在我开始收到此错误时也开始使用 react-bootstrap。我发现在webpack.config.jsexternals 列表中添加'react-dom': 'ReactDOM' 解决了这个问题,然后外部列表如下所示:

  externals: 
    // Use external version of React (from CDN for client-side, or
    // bundled with ReactJS.NET for server-side)
      react: 'React',
      'react-dom': 'ReactDOM'

这似乎是谷歌上关于这个错误的第一个堆栈溢出链接,所以我认为这个答案可能会对这里的人有所帮助。

【讨论】:

【参考方案9】:

我得到这个是因为我已经在我的 html 标记中包含了 reactreact-dom 作为外部脚本。

该错误是由向组件模块添加import ReactDOM from 'react-dom' 引起的。删除导入后错误就消失了,并且模块工作正常,因为组件已经可用。

【讨论】:

以上是关于开发外部组件时如何避免“loaded two copies of React”错误?的主要内容,如果未能解决你的问题,请参考以下文章

在 Firemonkey 组件中旋转时如何避免重复图像?

在 MSYS 环境中使用 MSVC 工具链(例如:CL.EXE)时,如何避免“未解析的外部符号 _mainCRTStartup”错误?

路由更改时如何避免构造函数调用?

如何重构我的代码以避免从类外部引发事件?

StackStorm简介及其部署

StackStorm简介及其部署