Luciano Ropero
Luciano Ropero

Reputation: 65

How to build your React component as a dependency library using Webpack?

I created a small proof of concept React component and pushed it here -> https://github.com/lropero/poc

I'd like to be able to import this component within a different React project by doing: npm install git+https://github.com/lropero/poc.git and then import Poc from 'poc' and be able to render the component (i.e. <Poc />). The thing is I'm getting React's invariant violation error #321 because I'm using hooks (useEffect in this example). I tried commenting this hook out and I'm able to see the <p>TEST</p> element rendered fine. I'm guessing it's a Webpack issue when building Poc's bundle?

Relevant files shown below (everything at https://github.com/lropero/poc):

./src/index.jsx:

import React, { useEffect } from 'react'
import ReactDOM from 'react-dom'

const App = () => {
  useEffect(() => {
    console.log('SUCCESS')
  }, [])
  return <p>TEST</p>
}

if (!process.env.NODE_ENV || process.env.NODE_ENV === 'development') {
  ReactDOM.render(<App />, document.getElementById('app'))
}

export default App

./package.json:

{
  "name": "poc",
  "version": "0.1.0",
  "description": "Proof of concept importing React bundle.",
  "module": "./dist/bundle.js",
  "scripts": {
    "build": "rm -rf dist && npx webpack --config webpack.prod.js",
    "clean": "rm -f npm-*.log && rm -f package-lock.json && rm -rf node_modules && npm cache verify",
    "nuke": "npm run clean && npm install",
    "start": "npx webpack-dev-server --config webpack.dev.js"
  },
  "devDependencies": {
    "@babel/core": "^7.11.6",
    "@babel/plugin-transform-runtime": "^7.11.5",
    "@babel/preset-env": "^7.11.5",
    "@babel/preset-react": "^7.10.4",
    "babel-loader": "^8.1.0",
    "html-webpack-plugin": "^4.4.1",
    "react": "^16.12.0",
    "react-dom": "^16.12.0",
    "source-map-loader": "^1.1.0",
    "webpack": "^4.44.2",
    "webpack-cli": "^3.3.12",
    "webpack-dev-server": "^3.11.0",
    "webpack-merge": "^5.1.4"
  },
  "peerDependencies": {
    "react": "^16.12.0",
    "react-dom": "^16.12.0"
  },
  "license": "UNLICENSED",
  "private": true
}

./webpack.config.js (webpack.common.js and webpack.prod.js merged together):

{
  entry: './src/index.jsx',
  mode: 'production',
  module: {
    rules: [
      {
        test: /\.jsx?$/,
        exclude: path.resolve(__dirname, 'node_modules'),
        use: [
          {
            loader: 'babel-loader',
            options: {
              presets: ['@babel/preset-env', '@babel/preset-react']
            }
          }
        ]
      }
    ]
  },
  output: {
    filename: 'bundle.js',
    library: 'Poc',
    libraryTarget: 'umd',
    path: path.resolve(__dirname, 'dist')
  },
  resolve: {
    alias: {
      [name]: path.resolve(__dirname, 'src')
    },
    extensions: ['.js', '.jsx']
  }
}

Upvotes: 1

Views: 3633

Answers (2)

Mauricio
Mauricio

Reputation: 11

The configuration from tmhao will make your module build not work on Linux, it wont be able to find react because of case sensitive issues. Just a heads up, amd should be 'react'

externals: {
  'react': {
    commonjs: 'react',
    commonjs2: 'react',
    amd: 'react',
    root: 'React'
  },
  'react-dom': {
    commonjs: 'react-dom',
    commonjs2: 'react-dom',
    amd: 'react-dom',
    root: 'ReactDOM'
  }    
}

Upvotes: 0

tmhao2005
tmhao2005

Reputation: 17474

It looks like you forgot to exclude React + ReactDOM out of your bundle file as you build with production mode.

As you publish your code as React component, apart from set React as peer dependency you have to set the react as externals to use the react at the consumer library.

Add more external property in your webpack.prod.js:

externals: {
  'react': {
    commonjs: 'react',
    commonjs2: 'react',
    amd: 'React',
    root: 'React'
  },
  'react-dom': {
    commonjs: 'react-dom',
    commonjs2: 'react-dom',
    amd: 'ReactDOM',
    root: 'ReactDOM'
  }    
},

Upvotes: 3

Related Questions