top

Making A Component Library For React

Some time ago I decided to make an article that covers topics like publishing to NPM , API architecture. Best tutorial for this would be a react component library development. A good example of React Component library as for me is react-color. It has neat documentation website with an easy step-by-step guide and lots of different variations of making a color-picker for your React application.                                                               https://casesandberg.github.io/react-color/ So I decided to go with making a rectangle-popup-menu like Google has:                                     This is from google.com website (an example of what I plan to make) Part 1. Preparing project (Setup) Let’s make up some requirements that every modern library should fit nowadays. Tree-shaking UMD pattern Build output is es5 Clear documentation Examples (demos) Unit testing Rollup & Webpack = Module bundling                                                                                     Rollup & Webpack For bundling library, I chose rollup (you can read in a more detailed article that explains why rollup is better for libraries in “Webpack and Rollup: the same but different” by Rich Harris). Rollup: https://rollupjs.org/guide/en Plus I used webpack (and webpack-dev-server) to serve examples folder. It handles css wrapping, font loading and es6 -> es5 transpilation (with the help of Babel). Webpack: https://webpack.js.org/ Jest = Unit testing Unit-testing tool by Facebook that perfectly fits our needs in comparing react component snapshots.     Link: https://facebook.github.io/jest/ Express = Serving examples Has a minor place in a project, but helps us configure proper examples serving properly (as webpack-dev-server is using it).                               The sample of code, where we use to express to serve static files for development mode Babel = write es6, provide es5 Nowadays ES6 is already widely supported by a majority of well-known browsers, but Babel is not just about working with es5, it’s a global standard for transpiling javascript subsets into browser-compatible implementation.  In this project, we use Babel mostly for using latest ES features like async/await and supporting JSX subset. Link: https://babeljs.io/   Part 2. Development Now, once we installed all required devDependencies we are able to move forward with the development process. The first step is to decide on the project folder structure. For this library, this is what I had at the end: assets/ — Skip this folder, this is just for images I had in API docs build/ — UMD and ES module build files + source maps. examples/ — This folder contains test .html examples that I use to test library in different cases. src/ — Contains library source code written in JSX and .babelrc file for in-folder babel configuration test/ — JEST tests Other files are needed to complete project configuration. I highly recommend you to use travis.yml for continuous integration (must-have for modern projects, especially such as a component library).   Important: Don’t forget to exclude react and react-dom from internal dependencies in rollup, otherwise, you’ll get compatibility errors on the client side and bad side effects, such as large bundle size and bad performance. // rollup.config.babel.js {  // ...  external: ['react', 'react-dom'],  globals: {    react: 'React',    'react-dom': 'ReactDOM'  } } Source files / Code In the index.js file, I linked every single file that exports classes (actually React components): // index.js export * from './PopupMenu'; export * from './PopupTable'; export * from './PopupText'; We won’t cover all the code written for this library as it’s more topic-specific rather than helpful, so let’s take for example only several parts of the code that explain our needs in project organization.                                                                           PopupMenu header part As we build components for UI we include style files, rollup allows us to make bundles with styles and images the same way as webpack does. In my case I chose sass syntax as it is a one I am familiar with. This means that ./PopupMenu.scssfile will be compiled from sass to css and then included as a javascript code that inserts inline styles into html <head> tag.                                                                    rollup-plugin-postcss module used in rollup config file Take into account that we enable "modules": true feature that enables CSS modules feature: import style from './PopupMenu.scss'; // Somewhere in JSX // ...  render() {    return (<div className={style.myClassName} />)  } // ... Any time we use JSX syntax in our ES6 modules we need to include react dependency otherwise, it will result in a build error. import React, {Component} from 'react'; In my case I even need to use React to provide context to child components this old way: (old because recently React introduced new Context API). I have Popup Table that takes PopupWidth of the parent PopupMenu                                                                                  React context in PopupMenu class I would like to also highlight classnames npm module that does a pretty good job in combining multiple classes from CSS modules:                                                                                           classnames module example Usage:   Unit testing First, you need to decide which unit-testing framework you want to choose. There are a few popular unit-testing frameworks I used and could suggest you test:   MochaJS JAVA Jest For this component library, I chose Jest. Because it is developed by Facebook (same as React) and it supports React components snapshot testing out of the box. Capture snapshots of React trees or other serializable values to simplify testing and to analyze how state changes over time. (From JEST website) That’s pretty simple, you render a react component you want to test, then call component.toJSON() which converts it to a rendered html tree. Example:   // Jest Snapshot v1, https://goo.gl/fbAQLP exports[`PopupMenu should render correctly 1`] = ` <div  className="PopupMenu_PopupMenu__8TfA4" >  <div    className="PopupMenu_button__20m_Y"    onMouseOut={[Function]}    onMouseOver={[Function]}  />  <div    className="PopupMenu_popover__3hd_Z"    onMouseOut={[Function]}    onMouseOver={[Function]}    style={      Object {        "height": "auto",        "left": "calc(-100px + 50%)",        "visibility": "hidden",        "width": "calc(200px - 10px)",      }    }  /> </div> `;   Once you did it for the first time it is saved into a *.test.js.snap file, which is basically a module that exports several rendered DOM tree strings to compare with each new render. If the DOM tree has changed, it will tell you that. If the tree was changed by positive changes (means that was expected), you have to run jest -u to save new snapshots. Conclusion Let’s highlight the most relevant tips from this article: Rollup is better than Webpack for component libraries Include postcss plugin and bundle css into the same js file Use Unit testing and continuous integration to show others that you care about stability and prevent unexpected errors. I would also recommend you divide the build into two steps, development and production (Includes minification and further optimizations). All the sources can be found on Github page. And the resulting demo is available as well.
Rated 4.0/5 based on 12 customer reviews
Normal Mode Dark Mode

Making A Component Library For React

Alexander Buzin
Blog
22nd Mar, 2018
Making A Component Library For React

Some time ago I decided to make an article that covers topics like publishing to NPM , API architecture. Best tutorial for this would be a react component library development.

A good example of React Component library as for me is react-color. It has neat documentation website with an easy step-by-step guide and lots of different variations of making a color-picker for your React application.

                                                              https://casesandberg.github.io/react-color/

So I decided to go with making a rectangle-popup-menu like Google has:

                                    This is from google.com website (an example of what I plan to make)


Part 1. Preparing project (Setup)

Let’s make up some requirements that every modern library should fit nowadays.

  • Tree-shaking
  • UMD pattern
  • Build output is es5
  • Clear documentation
  • Examples (demos)
  • Unit testing

Rollup & Webpack = Module bundling

Rollup & Webpack
                                                                                    Rollup & Webpack

For bundling library, I chose rollup (you can read in a more detailed article that explains why rollup is better for libraries in “Webpack and Rollup: the same but different” by Rich Harris).


Rollup: https://rollupjs.org/guide/en


Plus I used webpack (and webpack-dev-server) to serve examples folder. It handles css wrapping, font loading and es6 -> es5 transpilation (with the help of Babel).


Webpack: https://webpack.js.org/


Jest = Unit testing

Unit-testing tool by Facebook that perfectly fits our needs in comparing react component snapshots. 


   Link: https://facebook.github.io/jest/

Express = Serving examples

Has a minor place in a project, but helps us configure proper examples serving properly (as webpack-dev-server is using it).

                              The sample of code, where we use to express to serve static files for development mode

Babel = write es6, provide es5

Nowadays ES6 is already widely supported by a majority of well-known browsers, but Babel is not just about working with es5, it’s a global standard for transpiling javascript subsets into browser-compatible implementation. 

In this project, we use Babel mostly for using latest ES features like async/await and supporting JSX subset.

Link: https://babeljs.io/

 

Part 2. Development

Now, once we installed all required devDependencies we are able to move forward with the development process.

The first step is to decide on the project folder structure. For this library, this is what I had at the end:

 Development

  • assets/ — Skip this folder, this is just for images I had in API docs
  • build/ — UMD and ES module build files + source maps.

 Development

  • examples/ — This folder contains test .html examples that I use to test library in different cases.
  • src/ — Contains library source code written in JSX and .babelrc file for in-folder babel configuration
  • test/ — JEST tests

Other files are needed to complete project configuration. I highly recommend you to use travis.yml for continuous integration (must-have for modern projects, especially such as a component library).
 

Important: Don’t forget to exclude react and react-dom from internal dependencies in rollup, otherwise, you’ll get compatibility errors on
the client side and bad side effects, such as large bundle size and bad performance.

// rollup.config.babel.js
{
 // ...
 external: ['react', 'react-dom'],
 globals: {
   react: 'React',
   'react-dom': 'ReactDOM'
 }
}


Source files / Code

Source files / Code

In the index.js file, I linked every single file that exports classes (actually React components):

// index.js
export * from './PopupMenu';
export * from './PopupTable';
export * from './PopupText';

We won’t cover all the code written for this library as it’s more topic-specific rather than helpful, so let’s take for example only several parts of the code that explain our needs in project organization.

                                                                          PopupMenu header part

As we build components for UI we include style files, rollup allows us to make bundles with styles and images the same way as webpack does. In my case I chose sass syntax as it is a one I am familiar with. This means that ./PopupMenu.scssfile will be compiled from sass to css and then included as a javascript code that inserts inline styles into html <head> tag.

                                                                   rollup-plugin-postcss module used in rollup config file

Take into account that we enable "modules": true feature that enables CSS modules feature:

import style from './PopupMenu.scss';
// Somewhere in JSX
// ...
 render() {
   return (<div className={style.myClassName} />)
 }
// ...


Any time we use JSX syntax in our ES6 modules we need to include react dependency otherwise, it will result in a build error.

import React, {Component} from 'react';

In my case I even need to use React to provide context to child components this old way: (old because recently React introduced new Context API). I have Popup Table that takes PopupWidth of the parent PopupMenu

                                                                                 React context in PopupMenu class

I would like to also highlight classnames npm module that does a pretty good job in combining multiple classes from CSS modules:

classnames module
                                                                                          classnames module example

Usage:
 


Unit testing

First, you need to decide which unit-testing framework you want to choose. There are a few popular unit-testing frameworks I used and could suggest you test:
 

  • MochaJS
  • JAVA
  • Jest

For this component library, I chose Jest. Because it is developed by Facebook (same as React) and it supports React components snapshot testing out of the box.


Capture snapshots of React trees or other serializable values to simplify testing and to analyze how state changes over time. (From JEST website)


That’s pretty simple, you render a react component you want to test, then call component.toJSON() which converts it to a rendered html tree. Example:
 

// Jest Snapshot v1, https://goo.gl/fbAQLP
exports[`PopupMenu should render correctly 1`] = `
<div
 className="PopupMenu_PopupMenu__8TfA4"
>
 <div
   className="PopupMenu_button__20m_Y"
   onMouseOut={[Function]}
   onMouseOver={[Function]}
 />
 <div
   className="PopupMenu_popover__3hd_Z"
   onMouseOut={[Function]}
   onMouseOver={[Function]}
   style={
     Object {
       "height": "auto",
       "left": "calc(-100px + 50%)",
       "visibility": "hidden",
       "width": "calc(200px - 10px)",
     }
   }
 />
</div>
`;
 

Once you did it for the first time it is saved into a *.test.js.snap file, which is basically a module that exports several rendered DOM tree strings to compare with each new render. If the DOM tree has changed, it will tell you that. If the tree was changed by positive changes (means that was expected), you have to run jest -u to save new snapshots.

Conclusion

Let’s highlight the most relevant tips from this article:

  • Rollup is better than Webpack for component libraries

  • Include postcss plugin and bundle css into the same js file

  • Use Unit testing and continuous integration to show others that you care about stability and prevent unexpected errors.


I would also recommend you divide the build into two steps, development and production (Includes minification and further optimizations).

All the sources can be found on Github page. And the resulting demo is available as well.

Alexander

Alexander Buzin

Blog Author

Senior full-stack & VR/AR developer at AppReal-VR and Lead 3D developer at Vintage Web Production with 7+ years of experience in front-end development and 4+ years in Open source development

Leave a Reply

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

SUBSCRIBE OUR BLOG

Follow Us On

Share on

other Blogs

20% Discount