Search code examples
reactjswebpacktsconfig

How to tell npm to ignore installing react when user installs package


I'm bundling a typescript react component package, and i want to know if there is a way to ignore react and react-dom when a user installs the react component package.

If i do not remove react and react dom from node modules, user will have this issue

Error: Invalid hook call. Hooks can only be called inside of the body of a function component. This could happen for one of the following reasons:

If i have react and react dom removed from node modules, component will work fine. I do not want to keep deleting node modules back and forth. How can i simplify this ?

How do i tell package.json to ignore react and react dom from node modules ?

tsconfig.json

{
  "compilerOptions": {
    "outDir": "dist",
    "sourceMap": true,
    "noImplicitAny": true,
    "esModuleInterop": true,
    "module": "esnext",
    "target": "es6",
    "moduleResolution": "node",
    "jsx": "react"
  },
  "exclude": ["examples"]
}

package.json

{
  "name": "commentbox-simple-demo",
  "version": "1.0.0",
  "description": "",
  "main": "dist/index.js",
  "scripts": {
    "start": "webpack-dev-server --mode development",
    "transpile": "tsc",
    "prepublishOnly": "npm run transpile"
  },
  "author": "",
  "license": "ISC",
  "devDependencies": {
    "@babel/core": "^7.11.6",
    "@babel/preset-env": "^7.11.5",
    "@babel/preset-react": "^7.10.4",
    "@types/react": "16.9.23",
    "@types/react-dom": "16.9.5",
    "awesome-ts-loader": "^1.3.1",
    "babel-core": "^6.26.3",
    "babel-preset-env": "^1.7.0",
    "babel-preset-react": "^6.24.1",
    "css-loader": "^4.3.0",
    "html-webpack-plugin": "^4.4.1",
    "react": "^16.13.1",
    "react-dom": "^16.13.1",
    "style-loader": "^1.2.1",
    "ts-loader": "6.2.1",
    "typescript": "3.8.3",
    "webpack": "^4.44.1",
    "webpack-cli": "^3.3.12",
    "webpack-dev-server": "^3.11.0"
  },
  "peerDependencies": {
    "react": "^16.3.0",
    "react-dom": "^16.3.0"
  },
  "dependencies": {
    "@material-ui/core": "^4.11.0",
    "@material-ui/icons": "^4.9.1",
    "@material-ui/types": "^5.1.0"
  }
}

webpack.config.js

const path = require("path");
const HtmlWebpackPlugin = require("html-webpack-plugin");
const htmlWebpackPlugin = new HtmlWebpackPlugin({
  template: path.join(__dirname, "examples/index.html"),
  filename: "./index.html",
});
module.exports = {
  entry: path.join(__dirname, "examples/index.tsx"),
  output: {
    path: path.join(__dirname, "dist"),
    filename: "index.js",
  },
  module: {
    rules: [
      {
        test: /\.(ts|tsx|js|jsx)$/,
        use: "ts-loader",
        exclude: /node_modules/,
      },
      {
        test: /\.css$/,
        use: ["style-loader", "css-loader"],
      },
    ],
  },
  plugins: [htmlWebpackPlugin],
  resolve: {
    extensions: [".js", ".jsx", ".ts", ".tsx"],
  },
  devServer: {
    port: 3001,
  },
};

Solution

  • You've essentially already told npm to do that by putting react and react-dom under peerDependencies. This tells npm not to install react and react-dom for your package, but to assume the project in which your package is being used already has react and react-dom as dependencies.

    Try adding react and react-dom to the externals property of the webpack config. That tells webpack not to package them along with your component, and it should reduce version conflicts.