Author avatar

Chris Parker

How to Publish ES6 React Modules to NPM

Chris Parker

  • Apr 10, 2019
  • 10 Min read
  • 1,280 Views
  • Apr 10, 2019
  • 10 Min read
  • 1,280 Views
React
ES6

Introduction

In this guide, we will come to understand how to write our custom React component as an npm package and publish the same.

Getting Started

We can start with an empty directory and name it “my-react-app”. Then, we will run some commands within this directory. Let's start by running npm init. The console will prompt us to provide a few inputs. Enter the same and keep hitting ENTER until it is finished asking for the information.

Next, we would install the dependencies for our app.

1
npm install --save react webpack 

Since we are writing a React component, we need the React library as well as Webpack to transpile ES6/JSX to ES5 JavaScript code.

Next, we'll install the devDependencies

1
npm install -D webpack-cli babel-cli babel-core babel-loader babel-plugin-transform-object-rest-spread babel-plugin-transform-react-jsx babel-preset-env

When our package is published and someone wants to consume it, they'll just run npm install my-react-app and all the dependencies will automatically get installed. However, "devDependencies" will not get installed.

Then we'll update package.json to setup React as peerDependencies. "peerDependencies" are special dependencies that come into the picture only when we are publishing our package. Declaring "peerDependencies" implies that our package needs a dependency version which is the same exact version as someone who will be consuming our package. In terms of publishing React modules, this can prove to be very useful, as we can just have a single copy of "react-dom" and the same version will be used by someone installing our package.

We set "main" or entry point as index.js and also set the "build" and "start" scripts. Also, this should match with the output filename which is created by Webpack, once our code is transpiled from ES6 or JSX code into ES5 code, as that is what browsers widely support.

This is what our package.json would look like:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
{
  "name": "my-react-app",
  "version": "1.0.0",
  "description": "How to publish ES6 React modules to NPM!",
  "main": "./index.js",
  "peerDependencies": {
    "react": "^16.4.0"
  },
  "scripts": {
	"start": "webpack --watch",
	"build": "webpack",
	"test": "echo \"Error: no test specified\" && exit 1"
  },
  "author": "Pluralsight",
  "license": "ISC",
  "keywords": [
    "promise",
    "async",
    "Virtual reality (VR)",
    "Augmented reality (AR)"
  ],
  "dependencies": {
	"react": "^16.8.6",
	"webpack": "^4.29.6"
  },
  "devDependencies": {
	"babel-cli": "^6.26.0",
	"babel-core": "^6.26.3",
	"babel-loader": "^8.0.5",
	"babel-plugin-transform-object-rest-spread": "^6.26.0",
	"babel-plugin-transform-react-jsx": "^6.24.1",
	"babel-preset-env": "^1.7.0",
	"webpack-cli": "^3.3.0"
  }
}
json

Here the "keywords" property is an array of keywords with string values. It can be a collection of keywords used to describe our module. When our package is published, it can really be helpful in identifying our package.

We'll then need to configure webpack for transpiling our code. To do this, we'll update the webpack.config.js and .babelrc files as below:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
// webpack.config.js
var path = require('path');
var ExtractTextPlugin = require('extract-text-webpack-plugin');

module.exports = {
  entry: './index.js',
  output: {
    path: path.resolve(__dirname, 'build'),
    filename: 'index.js',
    libraryTarget: 'commonjs2'
  },
  module: {
    rules: [
      {
        test: /\.js$/,
        include: path.resolve(__dirname, 'src'),
        exclude: /(node_modules|bower_components|build)/,
        use: {
          loader: 'babel-loader',
          options: {
            presets: ['env']
          }
        }
      }, {
        test: /\.*css$/,
        use : ExtractTextPlugin.extract({
            fallback : 'style-loader',
            use : [
                'css-loader',
                'sass-loader'
            ]
        })
       },
    ]
  },
  externals: {
    'react': 'commonjs react' 
  }
};
javascript

It is important to set the output => libraryTarget as "commonjs2". This would set the module.exports property in our output file to the React component. This is required for our custom component to be used as an npm package.

Next, we set .baberc as below:

1
2
3
4
5
6
7
{
    "presets": ["env"],
    "plugins": [
        "transform-object-rest-spread",
        "transform-react-jsx"
    ]
}
json

This is used to configure the presets used by Babel for transpiling our custom React component ES6/JSX code to ES5.

If you look into the webpack.config.js file above, you'll notice that we are configuring webpack to apply 'babel-loader' on all *.js files in the modules.rules section.

We'll also create .npmignore file as below:

1
2
3
4
src
demo
.babelrc
webpack.config.js
json

By adding the above, we just instruct our npm cli as to which files it should exclude while publishing to npm package repo. It essentially helps in keeping our package clean by only having the files required to run our custom React component in Production. You'll notice there is no node_modules entry here, as that is automatically ignored by NPM.

Create a Basic React Component

Let's create a very basic component. We'll create a new "src" folder and inside that create index.js which would be the entry point for webpack.

Below is how the component looks like:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
import React from "react";

const MyReactApp = props => {
  const { width, height, bgColor, content } = props;
  return (
    <div
      style = {{
        width: width || 200,
        height: height || 200,
        backgroundColor: bgColor || "green",
		color: color || "black"
      }}
    >
      {content}
    </div>
  );
};

export default MyReactApp;
javascript

We run npm start and verify that the component has no errors. Now let us test the component as a npm package before we actually publish it. To do this, in our package.json, we'll specify the name of our package. We can also set the author and git repo. If you do not have npm account, you can sign up by navigating to https://www.npmjs.com/signup. It is free to sign up.

Test Our Package Locally

We now have the npm package created above. Let's test it out. To do that, we'll run the command npm run build inside our project folder. This will build our custom component. We then run npm link, which would link our package to npm dependencies. This would allow us to use the package in other projects, but it is restricted to your local machine for now. To start consuming in any other React app, we just run npm link my-react-app. We would then be able to import the package just like any other dependency. Below is the code:

1
2
3
4
5
6
7
8
9
10
11
12
import React, { Component } from "react";
import MyReactApp from "react-box";

class App extends Component {
  render() {
    return (
        <MyReactApp height={150} bgColor="black" color="white" text="How to publish ES6 React modules to NPM!" />
    );
  }
}

export default App;
javascript

In the above example, we just pass the values for height, bgColor, color, and text to our component "MyReactApp", which just renders a "div" element applying the arguments which it receives.

We can just use npm run build to build our project and see the changes.

Publish Our Package

Once we are done with local testing and see that the component is working as expected, we can publish the same. For that, we'll navigate inside our project folder and run "npm login". We'll sign in using our credentials. Once authentication is done, we just need to run the command "npm publish".

That is all. Our React component is now live and can be consumed by anyone.

We can check our published React component on npm website.

To see the metadata info about our package from the command line, we can just run npm info PACKAGE_NAME.

In case we want to update our component, we can increment the version number in our package.json (major / minor / patch depending on the update itself) and then just run npm publish again.

We can also make use of the following commands to update the version automatically instead of manually updating them each time there is some update:

1
2
3
npm version patch
npm version minor
npm version major

The above commands are actually based on semantic versioning or semver.

A few more points to remember whenever you are ready for publishing: Remove the attribute "private": true from your package.json, if it was added at any point. Also remove react, react-dom, and react-scripts from the "dependencies" object and instead move them to "devDependencies". We can add react and react-dom to "peerDependencies". Finally, add the following to package.json:

1
2
3
4
5
"files": [ "dist", "README.md" ],
"repository": {
	"type": "git",
	"url": "YOUR_GIT_REPO_URL"
}
json

The "repository" field will have a link to your repo on Github. We can also add a "bugs" field which would have the link to our Github issues page. This will be useful to people who consume our package because they can report bugs here and can also make requests to add any new features they might want.

And finally, delete the default README.md file and instead add a new one with some info about your component. It can look something like below:

1
2
3
4
5
my-react-app
A library of custom React components created using create-react-app
Installation
To install, run the following command:
npm install my-react-app

Conclusion

Thus, we learned how to set up a new React project, how to write React components as npm package, verify the component locally, and publish the same. We also learned about the significance of various attributes in package.json such as keywords, dependencies, devDependencies, peerDependencies, and the repository fields.

8