I’ve been looking for a good React.js boilerplate script that helps with building an NPM module of a React Component. I recently came across the NWB Toolkit that makes this whole process incredibly simple. I figured I would document the steps I took to publishing my first React Component to the global NPM directory.
 
Hope this helps someone!

Generate the component project

We’ll start by globally installing the NWB package using NPM:

$ npm install -g nwb
$ nwb new react-component sample-component
  Creating a react-component project...
  ? Do you want to create an ES6 modules build for use by ES6 bundlers? Yes
  ? Do you want to create a UMD build for global usage via <script> tag? No
      create .gitignore
      create .travis.yml
      create CONTRIBUTING.md
      create README.md
      create demo/src/index.js
      create nwb.config.js
      create package.json
      create src/index.js
      create tests/.eslintrc
      create tests/index-test.js
  ✔ Installing react and react-dom
  ✔ Initing Git repo
$ cd sample-component/
$ yarn start
    yarn start v0.27.5
    $ nwb serve-react-demo
    Starting Webpack compilation...

    Compiled successfully in 3703 ms.

    The app is running at http://localhost:3000/

 
As it says, in your browser, go to: http://localhost:3000/
It should look something like this…
 
React Sample Component
 

Edit the code

If you start by opening up the src/index.js file. It should look something like this:

import React, { Component } from 'react'

export default class extends Component {
    render() {
        return <div>
            <h2>Welcome to React components</h2>
        </div>
    }
}

 
Obviously this is an extremely simple component that just outputs some text (as we saw in the screenshot above). Let’s update it to be a little more dynamic. Let’s create a components directory under the src directory to store all of our javascript files. Next let’s create a file called Button.js. In here we’ll create a simple button component that renders a user’s name. That code may look something like this:
 

src/components/Button.js
import React, { Component } from 'react';
import t from 'prop-types'

export default class extends Component {
    static propTypes = {
        user: t.object,
        styles: t.object
    };
    static defaultProps = {
        user: {
            name: 'Bob'
        },
        styles: {
            maxWidth: '120px',
            backgroundColor: 'rgba(0, 0, 0, .2)',
            border: '1px solid darkgray',
            borderRadius: '5px',
            padding: '10px',
            textAlign: 'center',
            color: '#FFF',
            userSelect: 'none',
            cursor: 'default'
        }
    };
    render() {
        return React.DOM.div({ className: 'button-component', style: this.props.styles },
            'Hello ' + (this.props.user.name)
        );
    }
}
src/index.js
import React, { Component } from 'react'
import Button from './components/Button'

export default class extends Component {
    render() {
        return <div>
            <Button/>
        </div>
    }
}

 
React Button Component
 
Now let’s update the index.js file to dynamically pass in the user’s name:

import React, { Component } from 'react'
import Button from './components/Button'

export default class extends Component {
    render() {
        return <div>
            <Button user={ { name: 'Dan' } } />
        </div>
    }
}

 
Reach Sample Button
 
You’ll notice in the code examples that I go back and forth between using JSX (in index.js) and just raw javascript (in Button.js). You have the ability to write your code in either syntax, in the end it will all end up as the raw javascript once it’s compiled. I personally prefer this syntax because it looks more like javascript and less like HTML, but you can use whichever you prefer.
 

Using a CSS Pre-Processor (LESS)

Depending on who you talk to, inline CSS styles are a hot debate topic around the React.js community. I typically use an external stylesheet file along with a CSS Pre-Processor such as LESS or SASS. Here’s an example of how you would do that with the NWB library.
 
First you’ll need to install a LESS plugin that was developed for NWB:

$ npm install --save nwb-less

Then you can directly import a LESS stylesheet in your component file:

src/components/Button.js
import React, { Component } from 'react';
import t from 'prop-types'
import '../styles/base.less';

export default class extends Component {
    static propTypes = {
       user: t.object
    };
    static defaultProps = {
        user: {
            name: 'Bob'
        }
    };
    render() {
        return React.DOM.div({ className: 'button-component' },
            'Hello ' + (this.props.user.name)
        );
    }
}
src/styles/base.less
.button-component {
    max-width: 120px;
    background-color: rgba(0, 0, 0, .2);
    border: 1px solid darkgray;
    border-radius: 5px;
    padding: 10px;
    text-align: center;
    color: #FFF;
    user-select: none;

    &:hover {
        background-color: rgba(0, 0, 0, .6);
        cursor: pointer;
        color: deeppink;
    }
}

 
After your browser reloads, the style should look the same initially. The difference now is that in the LESS file we added some additional code to add a different style once you hover over the button. Hover over it with your mouse and it should look like this:
 
React Styled Button
 

Running Tests

Next we’ll open up the tests/index-tests.js test file. It should look something like this:

import expect from 'expect';
import React from 'react';
import { render, unmountComponentAtNode } from 'react-dom';

import Component from 'src/';

describe('Component', () => {
    let node;

    beforeEach(() => {
        node = document.createElement('div')
    });

    afterEach(() => {
        unmountComponentAtNode(node)
    });

    it('displays a welcome message', () => {
        render(<Component/>, node, () => {
            expect(node.innerHTML).toContain('Welcome to React components')
        })
    });
});

 
You can see that it’s basically just checking that the original text was being displayed. We’ll need to update this now that we have changed the button’s text so our test will pass.
 

import expect from 'expect';
import React from 'react';
import { render, unmountComponentAtNode } from 'react-dom';

import Component from 'src/';

describe('Sample Component Test', () => {
    let node;

    beforeEach(() => {
        node = document.createElement('div')
    });

    afterEach(() => {
        unmountComponentAtNode(node)
    });

    it('default component renders as expected', () => {
        render(<Component/>, node, () => {
            expect(node.innerHTML).toContain('Hello Dan')
        })
    });
});

 

Run the test
$ yarn test
yarn test v0.27.5
$ nwb test-react

START:
23 08 2017 21:04:49.201:INFO [karma]: Karma v1.7.0 server started at http://0.0.0.0:9876/
23 08 2017 21:04:49.204:INFO [launcher]: Launching browser PhantomJS with unlimited concurrency
23 08 2017 21:04:49.236:INFO [launcher]: Starting browser PhantomJS
23 08 2017 21:04:50.774:INFO [PhantomJS 2.1.1 (Mac OS X 0.0.0)]: Connected on socket KU6Mc4AbWnYj3acmAAAA with id 72799284
  Component
    ✔ default component renders as expected

Finished in 0.02 secs / 0.012 secs @ 21:04:50 GMT-0500 (CDT)

SUMMARY:
1 test completed
Done in 7.76s.

 

Writing another test

While we’re in here, let’s add a second test that tests our Button component directly. We’ll try render just that component, and pass in a different user name.
 

...
import Component from 'src/';
import Button from 'src/components/Button';

describe('Sample Component Tests', () => {
    ...

    it('button component handles dynamic prop', () => {
        render(<Button user={ { name: 'Anthony' } } />, node, () => {
            expect(node.innerHTML).toContain('Hello Anthony')
        })
    });
});

 

$ yarn test
yarn test v0.27.5
$ nwb test-react

START:
24 08 2017 09:37:46.005:INFO [karma]: Karma v1.7.0 server started at http://0.0.0.0:9876/
24 08 2017 09:37:46.008:INFO [launcher]: Launching browser PhantomJS with unlimited concurrency
24 08 2017 09:37:46.038:INFO [launcher]: Starting browser PhantomJS
24 08 2017 09:37:47.353:INFO [PhantomJS 2.1.1 (Mac OS X 0.0.0)]: Connected on socket pW02gpDmto4itmHVAAAA with id 16720158
WARN: 'Warning: Accessing factories like React.DOM.div has been deprecated and will be removed in v16.0+. Use the react-dom-factories package instead.  Version 1.0 provides a drop-in replacement. For more info, see https://fb.me/react-dom-factories'
  Component
    ✔ default component renders as expected
    ✔ button component handles dynamic prop

Finished in 0.023 secs / 0.015 secs @ 09:37:47 GMT-0500 (CDT)

SUMMARY:
2 tests completed
Done in 7.30s.

 

Building the Component

Our goal here is to build a React Component that we can then publish to the NPM directory and share it with other developers. The first thing we’ll need to do is compile and build our code to the lib directory.

$ npm run build -- --copy-files

> ds-react-sample-component@1.0.0 build ~/react-components/sample-component
> nwb build-react-component "--copy-files"

✔ Creating ES5 build
✔ Creating ES6 modules build
✔ Building demo

File sizes after gzip:

  demo/dist/demo.8ba2f9b3.js   48.9 KB
  demo/dist/demo.dc512879.css  240 B

 
You should now see a lib directory inside of your component’s parent directory:
 
Lib directory structure
 

Publishing the Component

Next we’ll need to push our Component out to the NPM directory. If you’ve never published code to NPM, you’ll need to start by creating a new account, and then logging in to your account locally using the adduser command:

$ npm adduser
Username: [MYUSERNAME]
Password: ********
Email: (this IS public) [MYEMAIL]@gmail.com
Logged in as [MYUSERNAME] on https://registry.npmjs.org/.

 
Next you’ll just run the npm publish command in your terminal:
 

$ npm publish
+ ds-react-sample-component@1.0.0

 

SUCCESS!

 
Now if you go to NPM and search for your component by the name specified in the package.json file, you should see it publicly available:
 
NPM React Sample Component