top

A Step by Step Guide To Deploy React Component As An NPM Library

IntroductionSince the advent of Node.js in 2009, everything we knew about JavaScript changed. The seemingly dying language made a phoenix-like comeback, growing to become the most popular language in the world.JavaScript was earlier seen as a web-browser’s language, but Node.js came and made it server-side. In essence, Node.js allows developers to develop web-servers with JavaScript. Thus, JavaScript was not only used in browsers, but also in the development of web servers.In January 2010, NPM was introduced to the Node.js environment. It makes Node.js easier for developers to publish and share the source code of JavaScript libraries. The developers can then use the code by installing the library and importing it into their code.NPM has since been the de-facto software registry for JavaScript and Node.js libraries. Many frameworks have emerged using NPM to distribute their library. React, Vue, Angular, and many other apps are developed using NPM. You either install their boilerplates or install their official CLI tool. All this happens through NPM, and of course, Node.js must be installed.Right now, there are billions of libraries in NPM. Angular, React and its cousins are all imported from NPM, and modules dependent on these frameworks are also hosted in NPM. Normally, it is quite easier to write and host a JS library in NPM because it is not dependent on any other framework. The challenge here is how do we write and publish a module dependent on a JS framework to be used as an NPM library.That’s what we are going to solve here and we will be developing a library for the React.js framework.In this tutorial, we are going to see how to create a React component library and publish it on NPM.As a demo, we are going to build a countdown timer.A countdown timer is used to display the countdown to any event. Like, in wedding anniversary, countdown timers can be used to cut the cake. You know the popular: “10! 9! 8! …0!”So, we are going to develop our own countdown timer for the React framework, so that it can be used by other devs in their React apps. They just need to pull in our library, instead of re-inventing the wheel.The source code we are going to build in this article can be found here.Project goalsHere is a list of things we are going to achieve in this article:Configure Babel to transform JSX to JS.Configure Rollup to produce efficient, minified code that works in all browsers(both old and new browsers).Deploy our React component to NPM.AssumptionsI’ll assume you are familiar with these tools and frameworks:Node.js, NPM, Babel, RollupReact.jsGitJavaScript, ES6, and CSSAlso, make sure you have Node.js, IDE (Visual Studio Code, Atom), and Git all installed. NPM comes with Node.js and it doesn’t need a separate installation.Project setupLet’s set up our project directory. I’ll call mine countdown-timer. Inside that, we will create src directory for sources and test directory for unit tests:mkdir countdown-timer cd countdown-timer mkdir srcAfter that, the directory countdown-timer will look like this:+- countdown-timer +- srcNext, we are going to make our directory i.e a Node.js project directory:This command creates a package.json file with the basic information we supplied to NPM. -y flag makes it possible to bypass the process of answering questions when using only the npm init command.package.json is the most important file in a Node.js project. It is used to let NPM know some basic things about our project and, crucially, the external NPM packages it depends on.Install DependenciesWe install libraries that are important to our development process:npm i react -DWe installed the react library as a dev Dependency since we don't want NPM to download it again when the user installs our library. This is because the user would have already installed the react library in his React app.So after the above command, our package.json will look like this:{ "name": "countdown-timer", "version": "1.0.0", "description": "A React library used to countdown time", "main": "index.js", "scripts": { "test": "echo \"Error: no test specified\" && exit 1" }, "repository": { "type": "git", "url": "git+https://github.com/philipszdavido/countdown-timer.git" }, "keywords": [], "author": "Chidume Nnamdi <kurtwanger40@gmail.com>", "license": "ISC", "bugs": { "url": "https://github.com/philipszdavido/countdown-timer/issues" }, "homepage": "https://github.com/philipszdavido/countdown-timer#readme", "devDependencies": { "react": "^16.3.2" } }Next, we create countdown.js in the src folder:countdown.js will contain our code implementation. We won't go down to explain our code. You can just add anything, maybe a text, "Holla! My First Component". It doesn't matter, all you have to know is the essential configurations needed to deploy and use a React component as a library.To build a React component for NPM, we must first import React and Component from the react library.// src/countdown.js import React, { Component } from 'react'Next, we defined our component, CountDown:// src/countdown.js import React, { Component } from 'react' class CountDown extends Component { }We defined CountDown which extends Component i.e it overrides and inherits all props and methods from the Component class. The reason we imported the Component from react is that it can be used by our module bundler to make React global.Paste this code in our class, CountDown:// src/component.js ... class CountDown extends Component { constructor(props) { super(props) this.count = this.count.bind(this) this.state = { days: 0, minutes: 0, hours: 0, secounds: 0, time_up:"" } this.x = null this.deadline = null } count () { var now = new Date().getTime(); var t = this.deadline - now; var days = Math.floor(t / (1000 * 60 * 60 * 24)); var hours = Math.floor((t % (1000 * 60 * 60 * 24)) / (1000 * 60 * 60)); var minutes = Math.floor((t % (1000 * 60 * 60)) / (1000 * 60)); var seconds = Math.floor((t % (1000 * 60)) / 1000); this.setState({days, minutes, hours, seconds}) if (t < 0) { clearInterval(this.x); this.setState({ days: 0, minutes: 0, hours: 0, seconds: 0, time_up: "TIME IS UP" }) } } componentDidMount() { this.deadline = new Date("apr 29, 2018 21:00:00").getTime(); this.x = setInterval(this.count, 1000); } render() { const { days, seconds, hours, minutes, time_up } = this.state return ( <div> <h1>Countdown Clock</h1> <div id="clockdiv"> <div> <span className="days" id="day">{days}</span> <div className="smalltext">Days</div> </div> <div> <span className="hours" id="hour">{hours}</span> <div className="smalltext">Hours</div> </div> <div> <span className="minutes" id="minute">{minutes}</span> <div className="smalltext">Minutes</div> </div> <div> <span className="seconds" id="second">{seconds}</span> <div className="smalltext">Seconds</div> </div> </div> <p id="demo">{time_up}</p> </div> ) } } export default CountDownStarting at the constructor, we bound the count function to the class instance. We have declared our state object which contains days, minutes, hours, seconds, and time_up properties. They will store the current values when our timer ticks(.i.e. counts down). We defined the this.x variable which will hold a reference to a setInterval function. The this.deadline will store the time or the deadline that our timer will tick down to.We used componentDidMount to start our timer. You know, the constructor first executes, followed by componentDidMount and finally, the render method comes last. That's the reason we delegated initialization to the constructor then started the timer at componentDidMount, render then displays the values: hours, days, minutes, seconds.constructor ==> componentDidMount ==> renderFinally, we have successfully exported our CountDown class. So now our users can import the CountDown component in their React project when they install our library.Now, we are done with our component, next step is to bundle our component using Rollup.Install Rollup and create a configuration fileRollup is a module bundler that takes all our JS files in our project and bundles them up into one JS file.First, we install the rollup library:NB: You can use -D or --save-dev flag. -D is shortcut notation for --save-dev.This downloads the rollup library from npm registry into node_modules folder and registers it in the devDependencies section in our package.json.... "devDependencies": { "react": "^16.3.2", "rollup": "^0.58.2" } ...To let rollup know how to bundle our JS files, we have to create a configuration file, rollup.config.js:We can actually pass our options to rollup using commands. But, to save ourselves from the stress of repeating, we created the js file, rollup.config.js to pass all our options to it. Upon execution, rollup reads the options in it and responds accordingly.So, now we open up the rollup.config.js and add these following code:// rollup.config.js const config = { input: 'src/countdown.js', external: ['react'], output: { format: 'umd', name: 'countdown', globals: { react: "React" } } } export default config Let’s talk about what each of these does:input: This is the bundle's entry point. It reads the file, then through it imports, draws up a list of files to bundle.external: This is the array of modules that should remain external to our bundle.output: This property defines how our output file will look like.output.format: Defines the JS format to use (umd, cjs, es, amd, iife, system).output.name: The name by which other scripts can access our module.output.globals: Defines external dependency that our module relies on.Babel/Rollup configurationRollup made it possible for devs to add their own functionalities to Rollup. These additional functionalities are called plugins. plugins allow you customize Rollup's behavior, by, for example, minifying your code for size or transpiling your code to match old browsers.We will need some plugins to:minify our codeadd ES5 supportadd JSX supportTo minify our code we will use rollup-plugin-uglify . To add ES5 features and JSX support, Babel got us covered.Babel is a project that transpiles ES5, ES6, ES7, and beyond into ES5, which can run on any browser.Let’s talk about the Babel JSX supportJSX is a JS-XML formatting popularised by React.js used to render HTML on browsers. Our component, CountDown in its render method returns HTML-like syntax.// src/countdown.js ... render () { return ( <div> <div> <h1>Countdown Clock</h1> <div id="clockdiv"> ... </div> ) } ...It’s called JSX. JSX produces React elements from it. Before, React components are bundled and executed in browser there JSX compositions are transformed to React.createElement() calls. React uses Babel to transform the JSX. Our above code compiles down to:... render () { return ( React.createElement('div',null, React.createElement('div',null, React.createElement('h1',null,'Countdown Clock'), React.createElement('div', props: { id: "clockdiv" }, ... ) ) ) } ...React.createElement returns an object which ReactDOM uses to generate virtual DOM and render it on browser’s DOM.So, before we bundle our component it has to be first transpiled to JS from its JSX. To do that we will need the babel plugin, babel-preset-react. To transpile to ES5 features we will need, rollup-plugin-babel.Install rollup/babel pluginsList of our proposed plugins:rollup-plugin-uglifyrollup-plugin-babelbabel-preset-reactNB: Babel preset is a set of plugins used to support a particular JS features.All babel plugins or presets need the babel-core in order to work. So, we go ahead to install the babel-core module:Next, we install our plugins:npm i rollup-plugin-uglify rollup-plugin-babel babel-preset-react -DAll installed a dev dependency, not needed in production.Create a .babelrcTo use babel plugins, there are two ways to configure it. The first is in package.json:// package.json { babel: { "presets": [ "react" ] } }\Second is in a file, .babelrc.For this project, we are going to use the .babelrc approach. Configuring babel plugins is a way to tell babel which preset should be used in transpiling.We create .babelrc in our project's root directory:Inside, add the following:{ "presets":[ "react" ] }Update rollup.config.jsTo use plugins, it must be specified in the plugins key of the rollup.config.js file.First, we import the plugins:// rollup.config.js import uglify from 'rollup-plugin-uglify' import babel from 'rollup-plugin-babel' ...Then, we create a plugins array key and call all our imported plugins functions there:// rollup.config.js import uglify from 'rollup-plugin-uglify' import babel from 'rollup-plugin-babel' ... plugins: [ babel({ exclude: "node_modules/**" }), uglify() ], ...We added exclude key to babel function call to prevent it from transpiling scripts in the node_modules directory.Update package.jsonWe will add a build key in our package.json scripts section. We will use it to run our rollup build process.Open up package.json file and add the following:... "scripts": { "build": "rollup -c -o dist/countdown.min.js", "test": "echo \"Error: no test specified\" && exit 1" }, ... The command "rollup -c -o dist/countdown.min.js" bundles our component to dist folder, with the name countdown.min.js. Here, we overrode the name we gave it in rollup.config.js, so whatever Rollup doesn't get from command it gets from rollup.config.js if it exists.Next, we will point our library entry point to dist/countdown.min.js. The entry point of any NPM library is defined in its package.json main key.... "main": "dist/countdown.min.js", ... Rollup our ComponentNow, we are done setting up our Rollup/Babel and their configurations. Let’s compile our component:This command will run "rollup -c -o dist/countdown.min.js". Like it was given it will create a folder dist/ in our project's root directory and put the bundled file countdown.min.js in it.Deploy to NPMWe are done bundling our library. It is now time to deploy it to NPM registry. But before we do that, we have to ignore some files from publishing alongside our library.Our project directory by now will contain files and folders used to build the library:dist/ src/ node_modules/ .babelrc package.json rollup.config.jsThe dist folder is the folder we want to publish, so we don't want other folders and files to be also included alongside the dist folder. To do that we have to create a file, .npmignore. As the name implies, it tells NPM which folders and files to ignore when publishing our library.So, we create the file:Next, we add the folders/files we want to ignore to it:src/ test/ .npmignore .babelrc rollup.config.jsNotice, there is no node_modules in it. NPM automatically ignores it.Before we publish an NPM library, we must host the project on Git before publishing.Create a new repository in any Version control website of your choice, then run these commands in your terminal:git init && git add. git commit -m 'First release' && git add remote origin YOUR_REPO_GIT_URL_HERE git pull origin master && git push origin masterThese commands initialize an empty repo, stages your files/folders, adds a remote repo to it and uploads your local repo to the remote repo.Now, we run npm publish to push our library to NPM:npm publish + @chidumennamdi/countdown-timer@0.0.1See here!! we have successfully published a React library.If the project name has already been taken in NPM. You can choose another name by changing the name property in package.json.// package.json ... "name": "countdown-timer" ... To consume our library, you can create a new React project, then pull in our library:create-react-app react-lib-test cd react-lib-test npm i countdown-timerThen, we import the component and render it:// src/App.js import React, { Component } from 'react'; import CountDown from 'countdown-timer' class App extends Component { render() { return ( <CountDown /> ) } } export default AppConclusionI know this article is fairly complex to understand, that is what it takes to develop apps using modern JS development method.We saw a lot of tools and their uses:Rollup: used to bundle and minify our libraryBabel: used to transform/transpile our library to run on any browser.In the end, we saw how easy it was to extract a React JS component and publish it on NPM. All we did was write the library, bundle it using Rollup with help from Babel, tell Rollup to bundle it as a React dependency, and then run the npm publish command. That's all!!Please, feel free to ask if you have any questions or comments in the comment section.Thanks !!!
Rated 4.5/5 based on 20 customer reviews
Normal Mode Dark Mode

A Step by Step Guide To Deploy React Component As An NPM Library

Chidume Nnamdi
Blog
26th Jun, 2018
A Step by Step Guide To Deploy React Component As An NPM Library

Introduction

Since the advent of Node.js in 2009, everything we knew about JavaScript changed. The seemingly dying language made a phoenix-like comeback, growing to become the most popular language in the world.

JavaScript was earlier seen as a web-browser’s language, but Node.js came and made it server-side. In essence, Node.js allows developers to develop web-servers with JavaScript. Thus, JavaScript was not only used in browsers, but also in the development of web servers.

In January 2010, NPM was introduced to the Node.js environment. It makes Node.js easier for developers to publish and share the source code of JavaScript libraries. The developers can then use the code by installing the library and importing it into their code.

NPM has since been the de-facto software registry for JavaScript and Node.js libraries. Many frameworks have emerged using NPM to distribute their library. React, Vue, Angular, and many other apps are developed using NPM. You either install their boilerplates or install their official CLI tool. All this happens through NPM, and of course, Node.js must be installed.

Right now, there are billions of libraries in NPM. Angular, React and its cousins are all imported from NPM, and modules dependent on these frameworks are also hosted in NPM. Normally, it is quite easier to write and host a JS library in NPM because it is not dependent on any other framework. The challenge here is how do we write and publish a module dependent on a JS framework to be used as an NPM library.

That’s what we are going to solve here and we will be developing a library for the React.js framework.

In this tutorial, we are going to see how to create a React component library and publish it on NPM.

As a demo, we are going to build a countdown timer.

A countdown timer is used to display the countdown to any event. Like, in wedding anniversary, countdown timers can be used to cut the cake. You know the popular: “10! 9! 8! …0!”

So, we are going to develop our own countdown timer for the React framework, so that it can be used by other devs in their React apps. They just need to pull in our library, instead of re-inventing the wheel.

The source code we are going to build in this article can be found here.


Project goals

Here is a list of things we are going to achieve in this article:

  • Configure Babel to transform JSX to JS.

  • Configure Rollup to produce efficient, minified code that works in all browsers(both old and new browsers).

  • Deploy our React component to NPM.


Assumptions

I’ll assume you are familiar with these tools and frameworks:

  • Node.js, NPM, Babel, Rollup

  • React.js

  • Git

  • JavaScript, ES6, and CSS

Also, make sure you have Node.js, IDE (Visual Studio Code, Atom), and Git all installed. NPM comes with Node.js and it doesn’t need a separate installation.


Project setup

Let’s set up our project directory. I’ll call mine countdown-timer. Inside that, we will create src directory for sources and test directory for unit tests:

mkdir countdown-timer
cd countdown-timer mkdir src

After that, the directory countdown-timer will look like this:

+- countdown-timer
+- src

Next, we are going to make our directory i.e a Node.js project directory:

This command creates a package.json file with the basic information we supplied to NPM. -y flag makes it possible to bypass the process of answering questions when using only the npm init command.

package.json is the most important file in a Node.js project. It is used to let NPM know some basic things about our project and, crucially, the external NPM packages it depends on.


Install Dependencies

We install libraries that are important to our development process:

npm i react -D

We installed the react library as a dev Dependency since we don't want NPM to download it again when the user installs our library. This is because the user would have already installed the react library in his React app.

So after the above command, our package.json will look like this:

{ "name": "countdown-timer", "version": "1.0.0", "description": "A React library used to countdown time", "main": "index.js", "scripts": { "test": "echo \"Error: no test specified\" && exit 1" }, "repository": { "type": "git", "url": "git+https://github.com/philipszdavido/countdown-timer.git" }, "keywords": [], "author": "Chidume Nnamdi <kurtwanger40@gmail.com>", "license": "ISC", "bugs": { "url": "https://github.com/philipszdavido/countdown-timer/issues" }, "homepage": "https://github.com/philipszdavido/countdown-timer#readme", "devDependencies": { "react": "^16.3.2" } }

Next, we create countdown.js in the src folder:

countdown.js will contain our code implementation. We won't go down to explain our code. You can just add anything, maybe a text, "Holla! My First Component". It doesn't matter, all you have to know is the essential configurations needed to deploy and use a React component as a library.

To build a React component for NPM, we must first import React and Component from the react library.

// src/countdown.js
import React, { Component } from 'react'

Next, we defined our component, CountDown:

// src/countdown.js
import React, { Component } from 'react'
class CountDown extends Component { }

We defined CountDown which extends Component i.e it overrides and inherits all props and methods from the Component class. The reason we imported the Component from react is that it can be used by our module bundler to make React global.

Paste this code in our class, CountDown:

// src/component.js
...
class CountDown extends Component {
    constructor(props) {
        super(props)
        this.count = this.count.bind(this)
        this.state = {
            days: 0,
            minutes: 0,
            hours: 0,
            secounds: 0,
            time_up:""
        }
        this.x = null
        this.deadline = null
    }
    count () {        
        var now = new Date().getTime();
        var t = this.deadline - now;
        var days = Math.floor(t / (1000 * 60 * 60 * 24));
        var hours = Math.floor((t % (1000 * 60 * 60 * 24)) / (1000 * 60 * 60));
        var minutes = Math.floor((t % (1000 * 60 * 60)) / (1000 * 60));
        var seconds = Math.floor((t % (1000 * 60)) / 1000);
        this.setState({days, minutes, hours, seconds})
        if (t < 0) {
                clearInterval(this.x);
                this.setState({ days: 0, minutes: 0, hours: 0, seconds: 0, time_up: "TIME IS UP" })
            }
    }
    componentDidMount() {
        this.deadline = new Date("apr 29, 2018 21:00:00").getTime();
 
        this.x = setInterval(this.count, 1000);
    }
    
    render() {
        const { days, seconds, hours, minutes, time_up } = this.state
        return ( 
            <div> 

            <h1>Countdown Clock</h1>
            <div id="clockdiv">
            <div>
                <span className="days" id="day">{days}</span>
                <div className="smalltext">Days</div>
                
            </div>
            <div>
                <span className="hours" id="hour">{hours}</span>
                <div className="smalltext">Hours</div>
                
            </div>
            <div>
                <span className="minutes" id="minute">{minutes}</span>
                <div className="smalltext">Minutes</div>
                
            </div>
            <div>
                <span className="seconds" id="second">{seconds}</span>
                <div className="smalltext">Seconds</div>
                
            </div>
            </div>
            
            <p id="demo">{time_up}</p>
            </div>
        )
    }
}

export default CountDown


Starting at the constructor, we bound the count function to the class instance. We have declared our state object which contains days, minutes, hours, seconds, and time_up properties. They will store the current values when our timer ticks(.i.e. counts down). We defined the this.x variable which will hold a reference to a setInterval function. The this.deadline will store the time or the deadline that our timer will tick down to.

We used componentDidMount to start our timer. You know, the constructor first executes, followed by componentDidMount and finally, the render method comes last. That's the reason we delegated initialization to the constructor then started the timer at componentDidMount, render then displays the values: hours, days, minutes, seconds.

constructor ==> componentDidMount ==> render

Finally, we have successfully exported our CountDown class. So now our users can import the CountDown component in their React project when they install our library.

Now, we are done with our component, next step is to bundle our component using Rollup.


Install Rollup and create a configuration file

Rollup is a module bundler that takes all our JS files in our project and bundles them up into one JS file.

First, we install the rollup library:

NB: You can use -D or --save-dev flag. -D is shortcut notation for --save-dev.

This downloads the rollup library from npm registry into node_modules folder and registers it in the devDependencies section in our package.json.

... "devDependencies": { "react": "^16.3.2", "rollup": "^0.58.2" } ...

To let rollup know how to bundle our JS files, we have to create a configuration file, rollup.config.js:

We can actually pass our options to rollup using commands. But, to save ourselves from the stress of repeating, we created the js file, rollup.config.js to pass all our options to it. Upon execution, rollup reads the options in it and responds accordingly.

So, now we open up the rollup.config.js and add these following code:

// rollup.config.js 
const config = { input: 'src/countdown.js', external: ['react'], output: { format: 'umd', name: 'countdown', globals: { react: "React" } } } export default config

Let’s talk about what each of these does:

  • input: This is the bundle's entry point. It reads the file, then through it imports, draws up a list of files to bundle.

  • external: This is the array of modules that should remain external to our bundle.

  • output: This property defines how our output file will look like.

  • output.format: Defines the JS format to use (umd, cjs, es, amd, iife, system).

  • output.name: The name by which other scripts can access our module.

  • output.globals: Defines external dependency that our module relies on.


Babel/Rollup configuration

Rollup made it possible for devs to add their own functionalities to Rollup. These additional functionalities are called plugins. plugins allow you customize Rollup's behavior, by, for example, minifying your code for size or transpiling your code to match old browsers.

We will need some plugins to:

  • minify our code

  • add ES5 support

  • add JSX support

To minify our code we will use rollup-plugin-uglify . To add ES5 features and JSX support, Babel got us covered.

Babel is a project that transpiles ES5, ES6, ES7, and beyond into ES5, which can run on any browser.

Let’s talk about the Babel JSX support

JSX is a JS-XML formatting popularised by React.js used to render HTML on browsers. Our component, CountDown in its render method returns HTML-like syntax.

// src/countdown.js ... 
render () { return ( <div> <div> <h1>Countdown Clock</h1> <div id="clockdiv"> ... </div> ) } 
...

It’s called JSX. JSX produces React elements from it. Before, React components are bundled and executed in browser there JSX compositions are transformed to React.createElement() calls. React uses Babel to transform the JSX. Our above code compiles down to:

... render () { return ( React.createElement('div',null, React.createElement('div',null, React.createElement('h1',null,'Countdown Clock'), React.createElement('div', props: { id: "clockdiv" }, ... ) ) ) } ...

React.createElement returns an object which ReactDOM uses to generate virtual DOM and render it on browser’s DOM.

So, before we bundle our component it has to be first transpiled to JS from its JSX. To do that we will need the babel plugin, babel-preset-react. To transpile to ES5 features we will need, rollup-plugin-babel.

Install rollup/babel plugins

List of our proposed plugins:

  • rollup-plugin-uglify

  • rollup-plugin-babel

  • babel-preset-react

NB: Babel preset is a set of plugins used to support a particular JS features.

All babel plugins or presets need the babel-core in order to work. So, we go ahead to install the babel-core module:

Next, we install our plugins:

npm i rollup-plugin-uglify rollup-plugin-babel babel-preset-react -D

All installed a dev dependency, not needed in production.

Create a .babelrc

To use babel plugins, there are two ways to configure it. The first is in package.json:

// package.json { babel: { "presets": [ "react" ] } }\

Second is in a file, .babelrc.

For this project, we are going to use the .babelrc approach. Configuring babel plugins is a way to tell babel which preset should be used in transpiling.

We create .babelrc in our project's root directory:

Inside, add the following:

{ "presets":[ "react" ] }

Update rollup.config.js

To use plugins, it must be specified in the plugins key of the rollup.config.js file.

First, we import the plugins:

// rollup.config.js
import uglify from 'rollup-plugin-uglify'
import babel from 'rollup-plugin-babel'
...

Then, we create a plugins array key and call all our imported plugins functions there:

// rollup.config.js 
import uglify from 'rollup-plugin-uglify' import babel from 'rollup-plugin-babel' ... plugins: [ babel({ exclude: "node_modules/**" }), uglify() ], ...

We added exclude key to babel function call to prevent it from transpiling scripts in the node_modules directory.

Update package.json

We will add a build key in our package.json scripts section. We will use it to run our rollup build process.

Open up package.json file and add the following:

... "scripts": { "build": "rollup -c -o dist/countdown.min.js", "test": "echo \"Error: no test specified\" && exit 1" }, ...

The command "rollup -c -o dist/countdown.min.js" bundles our component to dist folder, with the name countdown.min.js. Here, we overrode the name we gave it in rollup.config.js, so whatever Rollup doesn't get from command it gets from rollup.config.js if it exists.

Next, we will point our library entry point to dist/countdown.min.js. The entry point of any NPM library is defined in its package.json main key.

... "main": "dist/countdown.min.js", ...


Rollup our Component

Now, we are done setting up our Rollup/Babel and their configurations. Let’s compile our component:

This command will run "rollup -c -o dist/countdown.min.js". Like it was given it will create a folder dist/ in our project's root directory and put the bundled file countdown.min.js in it.


Deploy to NPM

We are done bundling our library. It is now time to deploy it to NPM registry. But before we do that, we have to ignore some files from publishing alongside our library.

Our project directory by now will contain files and folders used to build the library:

dist/ src/ node_modules/ .babelrc package.json rollup.config.js

The dist folder is the folder we want to publish, so we don't want other folders and files to be also included alongside the dist folder. To do that we have to create a file, .npmignore. As the name implies, it tells NPM which folders and files to ignore when publishing our library.

So, we create the file:

Next, we add the folders/files we want to ignore to it:

src/ test/ .npmignore .babelrc rollup.config.js

Notice, there is no node_modules in it. NPM automatically ignores it.

Before we publish an NPM library, we must host the project on Git before publishing.

Create a new repository in any Version control website of your choice, then run these commands in your terminal:

git init && git add.
git commit -m 'First release' && git add remote origin YOUR_REPO_GIT_URL_HERE
git pull origin master && git push origin master

These commands initialize an empty repo, stages your files/folders, adds a remote repo to it and uploads your local repo to the remote repo.

Now, we run npm publish to push our library to NPM:

npm publish
+ @chidumennamdi/countdown-timer@0.0.1

See here!! we have successfully published a React library.

If the project name has already been taken in NPM. You can choose another name by changing the name property in package.json.

// package.json ... 
"name": "countdown-timer" 
...

To consume our library, you can create a new React project, then pull in our library:

create-react-app react-lib-test
cd react-lib-test npm i countdown-timer

Then, we import the component and render it:

// src/App.js
import React, { Component } from 'react';
import CountDown from 'countdown-timer'
class App extends Component { render() { return ( <CountDown /> ) } }
export default App


Conclusion

I know this article is fairly complex to understand, that is what it takes to develop apps using modern JS development method.

We saw a lot of tools and their uses:

  • Rollup: used to bundle and minify our library

  • Babel: used to transform/transpile our library to run on any browser.

In the end, we saw how easy it was to extract a React JS component and publish it on NPM. All we did was write the library, bundle it using Rollup with help from Babel, tell Rollup to bundle it as a React dependency, and then run the npm publish command. That's all!!

Please, feel free to ask if you have any questions or comments in the comment section.

Thanks !!!

Chidume

Chidume Nnamdi

Author

JavaScript Ninja | Angular Archangel | Guest Writer @auth0 | Machine Learning freak | AI enthusiast | Technical Writer

Leave a Reply

Your email address will not be published. Required fields are marked *

SUBSCRIBE OUR BLOG

Follow Us On

Share on