如何在开发外部组件时避免“加载两个React副本”错误



我正在开发一个外部组件(假设是my-component,我将其与npm link链接到项目(因为它正在进行中,我需要包来反映更改)。

my-component文件夹中有node_modules/reactnode_modules/react-dom,因为它们是它的依赖项。然而,它们是peerdependencies,所以我不打算把它们带到链接这个包的项目中。

然而,当使用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

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

问题是双重的:

  1. 你不能有两个副本的react加载
  2. npm link创建了一个符号链接,但是require不尊重当它尝试在目录上导航时,它永远不会查找父项目的反应。

解决方案:

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

找到你的组件项目,删除react和react-dom,然后执行

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

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'))
}

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

步骤1:从外部组件的node_modules

中删除依赖项

正如@cleong所指出的,你不能仅仅从外部组件的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 link,它都会起作用。(让我怀疑它是否应该是默认的npm行为…)

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

我认为答案是在外部组件的package.json中将reactreact-dom指定为peerDependencies。尽我所能遵循这里和这里,npm link应该(作为npm@3)不再安装peerDependencies(或' devDependencies要么)。

aaa,我只是更仔细地阅读了你的帖子,意识到你已经将它们指定为peerDependencies。因此,我认为答案可以归结为:

升级到npm@3:

npm install -g npm@3.0-latest

问题是npm链接。https://github.com/npm/npm/issues/5875

npm不把链接的目录当作父项目的子项目。

尝试npm的替代方法link:

在package.json 中使用相对路径依赖2)在你的项目node_modules目录中手动包含你的依赖项 3)使用url路径

基本上任何东西,但npm链接

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

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

我也尝试了DedupePlugin(这里提到的可能的补救措施),但我不能让它工作。

同样有趣的是,当一个模块出现在依赖关系图的多个位置时,我遇到了相同问题的不同表现(可能更阴险)。

这样的一个例子是,即使我传入的类型是正确的,我的React.PropTypes.instanceOf(SomeType)约束也会发出警告。这是由于模块出现在node_modules目录树中的多个位置。由于使用duck-typing,代码仍然可以工作,但我的控制台被这些警告弄得乱七八糟。用resolve.alias的方式也让这些人沉默了。

YMMV

我正在使用ReactJS.net和设置webpack从那里的教程,并开始使用react-bootstrap以及当我开始得到这个错误。我发现将'react-dom': 'ReactDOM'添加到webpack.config.js中的externals列表中修复了这个问题,外部列表看起来像这样:

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

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

强烈建议使用https://github.com/mweststrate/relative-deps。

从本地签出安装依赖项,并保持它们同步,不受链接的限制。

这个解决了这个问题,因为它像npm install一样安装本地库,满足任何依赖版本,等等。

如果你在主项目中使用Webpack,这个解决方案可能有效。在我的例子中,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作为project-b/package.json中的peerDependencies
  • project-a需要project-b作为devDependency(也应该作为dependency工作)在project-a/package.json
  • cd project-a; npm link ../project-b 本地project-b链接到project-a如下:

现在当我在project-b内运行npm run build时,变化立即出现在project-a

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

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

最新更新