How to publish a React component in npm with React Hooks

Let's assume that you created a React component AwesomeComponent.js while working in one of your projects:

jsx
import React, { useState } from 'react';

const AwesomeComponent = () => {
    
    const [name, setName] = useState('The world');
    
    return (
        <div>{name} needs this awesome component.</div>
    );
    
}

export default AwesomeComponent;

Now you want to publish in npm.

1. Create package.json

Create a new and empty folder and rename it like your component. This will be the component's main directory.

Open the Terminal, go to the main directory and run:

shell
npm init -y

You have created a package.json describing the component:

jsx
{
  "name": "AwesomeComponent",
  "version": "1.0.0",
  "description": "The best component ever",
  "main": "index.js",
  "scripts": {
    "test": "echo \"Error: no test specified\" && exit 1"
  },
  "keywords": [],
  "author": {
    "name": "Erik Martín Jordán",
    "url": "https://erikmartinjordan.com/"
  },
  "license": "MIT"
}

You'll need to rename the fields name, author and description.

At this point you can create a srcfolder to include the source code of your component.

The main directory will have a tree like:

shell
|____package-lock.json
|____package.json
|____src
| |____AwesomeComponent.js

2. Install Wepack

The next step is to install Webpack:

shell
npm install --save-dev webpack webpack-dev-server webpack-cli

Your awesome component has only one script, but in most cases you will have several additional files. Webpack will pack all the scripts in one single file.

After installing Webpack, you need to create a webpack.config.js. Go to the main directory and run:

shell
touch webpack.config.js

The webpack.config.js should have this config:

jsx
module.exports = {
  entry: [
    './src/AwesomeComponent.js'
  ],
  module: {
    rules: [
      {
        test: /\.(js|jsx)$/,
        exclude: /node_modules/,
        use: ['babel-loader']
      },
      {
        test: /(\.css$)/,  
        loaders: ['style-loader', 'css-loader']
      }
    ]
  },
  externals: {
    react: {
        root: 'React',
        commonjs2: 'react',
        commonjs: 'react',
        amd: 'react'
    },
    'react-dom': {
        root: 'ReactDOM',
        commonjs2: 'react-dom',
        commonjs: 'react-dom',
        amd: 'react-dom'
    }
  },
  resolve: {
    extensions: ['*', '.js', '.jsx']
  },
  output: {
    path: __dirname + '/build',
    publicPath: '/',
    filename: 'index.js',
    libraryTarget: 'commonjs2'
  },
  devServer: {
    contentBase: './build'
  }
};

Modify only the entry field.

Notice that the output field indicates that the output will be generated in a folder build (you don't need to create it manually) and the filename will be index.js.

3. Install Babel

Babel translates ES6 and modern syntax into compatible JavaScript between browsers.

shell
npm install --save-dev @babel/core @babel/preset-env @babel/preset-react babel-loader style-loader css-loader

Create .babelrc:

shell
touch .babelrc

Add this configuration to .babelrc:

shell
{
    "presets": [
        "@babel/preset-env",
        "@babel/preset-react"
    ]
}

After all these steps, package.json will look like this:

jsx
{
  "name": "AwesomeComponent",
  "version": "1.0.0",
  "description": "The best component ever",
  "main": "./build/index.js",
  "author": {
    "name": "Erik Martín Jordán",
    "url": "https://erikmartinjordan.com/"
  },
  "scripts": {
    "test": "echo \"Error: no test specified\" && exit 1",
    "build": "webpack"
  },
  "keywords": [],
  "license": "MIT",
  "devDependencies": {
    "@babel/core": "^7.11.0",
    "@babel/preset-env": "^7.11.0",
    "@babel/preset-react": "^7.10.4",
    "babel-loader": "^8.1.0",
    "css-loader": "^4.2.0",
    "style-loader": "^1.2.1",
    "webpack": "^4.44.1",
    "webpack-cli": "^3.3.12",
    "webpack-dev-server": "^3.11.0"
  },
  "peerDependencies": {
    "react": "^16.13.1"
  }
}

Important: Notice that you should add React as a peer dependency, because otherwise, you'll have two React modules after downloading the package from npm and this will generate an error.

The file tree will look like:

shell
|____package-lock.json
|____package.json
|____webpack.config.js
|____.babelrc
|____src
| |____AwesomeComponent.js

4. Build and publish

At this point you can build the component:

shell
npm run build

A index.js will be generated and it's ready to publish in npm.

Terminal
|____package-lock.json
|____package.json
|____webpack.config.js
|____.babelrc
|____src
| |____AwesomeComponent.js
|____build
| |____index.js

From the root, open the Terminal and run:

shell
npm publish

Ready!

Note

It's recommended to create a new React project to test the component locally before to publish the component:

  1. Create a new React app:
Terminal
npx create-react-app Test
  1. Link the component to the new React app:
terminal
# From the component folder
cd AwesomeComponent
npm link
    
# From the new React project folder
cd Test
npm link AwesomeComponent
  1. Run it!
terminal
 npm run start

Hi, I'm Erik, an engineer from Barcelona. If you like the post or have any comments, say hi.