在使用npm link测试组件之前,作为npm包发布时,可能会出现ReactJS重复导入的问题。

13

我有一个像这样简单的组件。

import React, {useState} from 'react';

function MyComponentWithState(props) {
    const [value, setValue] = useState(0);

    return (
        <p>My value is: {value}</p>
    ) 
}

export default MyComponentWithState;

我想将其作为单独的包发布到NPM。因此,为了实现这一点,我准备了以下的 package.jsonwebpack.config.js 文件。

package.json:

{
  "name": "try-to-publish",
  "version": "0.0.1",
  "description": "Just a test",
  "main": "build/index.js",
  "scripts": {
    "start": "webpack --watch",
    "build": "webpack"
  },
  "author": {
    "name": "Behnam Azimi"
  },
  "license": "ISC",
  "peerDependencies": {
    "react": "16.9.0",
    "react-dom": "16.9.0"
  },
  "dependencies": {
    "react": "16.9.0",
    "react-dom": "16.9.0",
    "prop-types": "15.7.2",
    "react-scripts": "3.1.1",
    "webpack": "4.39.3"
  },
  "devDependencies": {
    "@babel/core": "7.6.0",
    "@babel/plugin-proposal-class-properties": "7.5.5",
    "@babel/preset-env": "7.6.0",
    "@babel/preset-react": "7.0.0",
    "babel-loader": "8.0.6",
    "babel-plugin-transform-object-rest-spread": "6.26.0",
    "babel-plugin-transform-react-jsx": "6.24.1",
    "css-loader": "3.2.0",
    "node-sass": "4.12.0",
    "sass-loader": "8.0.0",
    "style-loader": "1.0.0",
    "webpack-cli": "3.3.8",
    "webpack-external-react": "^1.1.2"
  }
}

webpack.config.json:

const path = require('path');

module.exports = {
    entry: './src/index.js',
    output: {
        path: path.resolve(__dirname, 'build'),
        filename: 'index.js',
        libraryTarget: 'commonjs2'
    },
    module: {
        rules: [
            {
                test: /\.(js|jsx)$/,
                exclude: /node_modules/,
                include: path.resolve(__dirname, 'src'),
                use: {
                    loader: "babel-loader"
                }
            },
        ]
    },
    resolve: {
        alias: {
            'react': path.resolve(__dirname, 'node_modules/react'),
            'react-dom': path.resolve(__dirname, 'node_modules/react-dom'),
        }
    },
    externals: {
        'react': "commonjs react",
        'react-dom': "commonjs react-dom"
    },
};

这是我的 .babelrc:

{
  "presets": [
    "@babel/preset-env",
    "@babel/preset-react"
  ],
  "plugins": ["@babel/plugin-proposal-class-properties"]
}

当我将组件发布到NPM并在我的另一个ReactJs项目中使用`npm install`安装时,这些配置都能正常工作,但我想本地测试!

在发布之前,我想要测试组件/库。为了做到这一点,我使用`npm link`功能将我的组件链接到我的主ReactJS项目。

正如你在上面看到的那样,我的组件是可运行的,并且我也使用了hooks。所以当我将本地链接库注入到我的主ReactJs项目中时会出现以下错误:

无效的hook调用。Hooks只能在函数组件的主体内部调用。这可能由于以下原因之一: 1. React和渲染器(例如React DOM)的版本不匹配 2. 您可能正在违反Hooks规则 3. 您可能在同一应用程序中有多个React副本

我的问题与第三个原因有关。我的项目使用ReactJs并导入它一次,而我的组件也将导入React!也就是说,在一个项目中导入了两次React!

我的Webpack配置文件中还有关于`react`和`react-dom`的`externals`配置。

我应该怎么做才能解决这个问题?我的错误在哪里?

更新: 我也尝试了@sung-m-kim和@eddie-cooro所说的方法,但它没有起作用!也就是说,我更改了package.json并从`dependencies`中删除了`react`和`react-dom`,然后将它们添加到了`devDependencies`。


1
FYI - 我已经删除了我的答案,因为它没有起作用。 - dance2die
npm ls react 的结果是什么? - Fateme Fazli
@FatemeFazli,-- UNMET DEPENDENCY react@16.9.0,这是npm ls react的结果。 - Behnam Azimi
@FatemeFazli,我做了一些更改,然后遇到了 -- react@16.9.0 作为 npm ls react 的结果。 - Behnam Azimi
https://reactjs.org/warnings/invalid-hook-call-warning.html#duplicate-react - tim-phillips
显示剩余2条评论
4个回答

9

我通过以下步骤最终解决了这个问题。

<your-library-package>/node_modules/react目录下运行npm link命令。

然后也在<your-library-package>/node_modules/react-dom目录下运行npm link命令。

接着,在你的应用根目录下运行npm link reactnpm link react-dom命令。

同时别忘了在库中将react和react-dom保持为外部模块。

// webpack.config.js

const externals = {
    "react": "react",
    "react-dom": "react-dom",
}

module.exports = {
    .
    .
    .

   externals
   }

你也可以从你正在尝试链接库的目录中运行以下命令:npm link ../library-package-dir/node_modules/react ../library-package-dir/node_modules/react-dom ../library-package-dir - Nathan

2

reactreact-native包仅设置在package.json文件的peerDependencies部分,而非dependencies。此外,在本地开发时(当您的包未被包含在任何其他react项目中且您想要在本地运行它时),可以使用devDependencies字段。


2
我已经解决了我的问题。我使用RollupJS来打包,而不是使用Webpack作为打包工具。

这是我的rollup.config.js文件:

import {uglify} from 'rollup-plugin-uglify'
import babel from 'rollup-plugin-babel'

export default {
    input: "./src/index.js",
    external: ['react', 'react-dom'],
    output: {
        name: 'test-lib',
        format: "cjs",
    },
    plugins: [
        babel({
            exclude: "node_modules/**"
        }),
        uglify(),
    ],
};

还有我的package.json文件:

{
  "name": "test-lib",
  "version": "1.0.0",
  "main": "dist/test-lib.min.js",
  "scripts": {
    "build": "rollup -c -o dist/test-lib.min.js"
  },
  "author": "Behnam Azimi",
  "license": "ISC",
  "peerDependencies": {
    "react": "^16.9.0",
    "react-dom": "^16.9.0"
  },
  "devDependencies": {
    "@babel/core": "^7.6.0",
    "@babel/preset-env": "^7.6.0",
    "@babel/preset-react": "^7.0.0",
    "rollup": "^1.21.4",
    "rollup-plugin-babel": "^4.3.3",
    "rollup-plugin-commonjs": "^10.1.0",
    "rollup-plugin-uglify": "^6.0.3"
  }
}

在进行这些更改之后,npm link 真正地在我的 ReactJS (Hooks) 项目中起作用了。
请注意,这只是一个简单的 Rollup 配置,展示了我的解决方案,您可以将许多内容添加到配置中,例如热重载、样式加载器和许多其他插件。

这似乎与 Lerna 结合使用无法正常工作。 - Robert Cabri

1

我在一个typescript react项目中解决了这个问题。

可能是因为使用 npm link 时从主应用程序项目和组件项目中同时使用了 react

因此,在您的 package.json 中,从 dependencies 和/或 devDependencies 中移除 react

查看答案:https://dev59.com/ylYN5IYBdhLWcg3whIbz#62807950


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接