Distribute React component to NPM

Pontus Alexander
Meth Meth Method
Published in
8 min readAug 14, 2017

Lately I’ve invested a lot of time in researching how to effectively build React components that are highly reusable and publishable to NPM.

Before you can upload a React component to NPM, there are a couple of questions that needs to be answered.

  • What format should the package be written in.
  • What format should the published code be in.
  • How to think about styling (CSS).
  • How to handle resources like images.

Source code format

By source code format I’m referring to format of the source code for your package. This include ECMAScript version and if you’re using JSX, or a superset of Javascript like Coffee-script or TypeScript.

The answer is you should write the code in the style you prefer. When publishing your package you will have a build step, and there is few strong reasons to avoid transpiling.

In this post, we will bundle a React component that uses ES6 and JSX.

Published format

The published format is the state the code is in when installed by an end user. Common practice seems to be to use babel-preset-es2015. This means you will be able to use ES6 features like const, destructuring ( const {busy} = this.state;), class, and other syntactic sugar.

It might seem a bit counter intuitive to publish your code in a transpiled format. After all, this makes assumptions about where your code will run in the future that might not be sane. Lots of browsers are perfectly happy with const, destructuring and class. This is a good point. However, when you think about that the end user would need to know every possible superset of Javascript ever invented, and their build pipeline would need to support every superset that any of their dependencies has, it becomes obvious that this is the lesser evil.

Bundling styles

The question on what to do with styles was the biggest show stopper for me. As of now, there seems to be no standard way to get styles from your package into the parent project without sorcery.

My recommendation is to inline them using the style attribute and only include functional styles. By functional styles I mean style properties that affect functionality. These include display values, absolute positioning, and specific graphics that are required for the component to make sense. Always try to achieve your goal with semantic HTML elements first. There is a high likelihood that the grunt of the work your React component does is data processing and handling, and less that of styled presentation.

It is very important to be conservative here. When you set the style attribute you interfere with the cascading part of cascading style sheets, and you make it difficult for a user to customize. Therefore, include inline styles with caution. Colors, fonts and absolute dimensions are off limits as it prevents customization and defeats the purpose of publishing your component.

If you are uncertain, it is much better to not embed the style and bundle your package with documentation on how to customize it. By using classes in a smart way you give the power to your users to customize.

I want to stress again to be conservative. Your component looking great is the least of your users interest when they install your component. They want your component to solve a repetitive task, and they want to use it on their own terms. If you feel you need to bundle lots of CSS with your component, you may be going down the wrong path.

Bundling graphics

Few components will require you to bundle graphics. If you must, embed them in the code as data URIs. You want your component to come with batteries included — work out of the box and not have the user manually copy files after the install of you package is finished.

This bloats your componenent. Therefore I stress the “if you must” part here.

In our example we are bundling an SVG throbber.

Developing

I will suggest tools, but not go into depth on how to use all the tools. In order to follow this guide it is assumed that you are comfortable researching NPM, Yarn and React development.

Setup development environment

Your development enviroment is a directory that will contain the component you are developing and a React app that implements your component during development.

For your convenience, I have created a boilerplate repo with some prerequisites bundled called react-package-boilerplate.

The react-package-boiler plate comes installed with my preference for transpiling. This includes the following packages.

babel-cli
babel-core
babel-plugin-inline-import-data-uri
babel-plugin-transform-class-properties
babel-preset-es2015
babel-preset-react

It also comes with a babel config .babelrc

{
"presets": [
"es2015",
"react",
],
"plugins": [
"inline-import-data-uri",
"transform-react-jsx",
"transform-class-properties",
],
}

This allows you to build React components using ES6 classes and JSX and will import PNG and SVG files as data URIs. If you want other options for importing consult the babel-plugin-inline-import-data-uri documentation.

Clone react-package-boilerplate and setup a new React app using Create React App. If you don’t have Create React App installed you can install it with yarn global add create-react-app .

The react-package-boilerplate provides examples on inlining styles, embedding an SVG image as data URI, and logic for toggling visibility on a throbber.

mkdir distributable-react-component
cd distributable-react-component

git clone https://github.com/meth-meth-method/react-package-boilerplate.git my-component

create-react-app react-app

Now we have the prerequisites to start working. The first thing we want to do is install component dependencies and “link” our component using yarn. When you link a component you can use a local folder as if it was an installable NPM package which we have to do since we have not published our package yet.

Enter the my-component directory and run yarn followed by yarn link.

cd my-component
yarn link

When the linking is successful, you should see something like below.

We also want to start watching the component for changes and auto-rebuild. We do this so that the changes we make to the component we are developing is automatically reloaded in the React app.

yarn run build -- --watch

Now we want to enter the react-app, import my-component, and start developing. Since we are running a process already in my-component dir, you should do this in a new terminal.

cd react-app
yarn link my-component
yarn start

This should fake install my-component as a Node module and open the template app bundled with Create React App.

Find the file App.js from react-app, import my-component, and render it. In the example below I have removed everything but <MyComponent/> for brevity and set the property initiallyVisible for fun.

Your environment should now look similar to below.

And your browser should display the throbber component in its default state.

This is your basic development environment setup.

From here on, you will develop your application until fit for publishing.

Development and Documenting

This section will show how a user could customize your component. While you develop you want to make sure you do not restrict the user from applying their own style to your component, while still maintaining some sane default so that it is usable out of the box . You don’t want your component to be hidden by default for example.

Key for allowing customization is to document the class names your component uses and consider these part of your component’s API. Being part of the API means they are stable (do not change without notice), are documented, and clearly intended for use.

MyComponent from the boilerplate have three points of interaction useful for CSS. The main class .MyComponent, the <button> element, and the .throbber class.

Find the file App.css from react-app and remove all CSS that we do not use any more. Your App.css should now look like below.

The first thing we want to customize is the size of the throbber. Add CSS to App.css .

.App .MyComponent .throbber {
margin: 1em auto;
height: 20vw;
width: 20vw;
}

It should now look like below.

Next we will customize the button. Add CSS for button.

.App .MyComponent button {
background: #de4d5f;
border: none;
border-radius: 0.2em;
color: #fff;
font-size: 30px;
margin: 1em;
padding: 0.5em;
}

Lastly, we will add some custom fonts from Google Fonts. Find the file index.html from react-app and add a custom CSS from Google Fonts between<head> and </head> .

<link href="https://fonts.googleapis.com/css?family=Titan+One" rel="stylesheet">

Then add a font-family property to App.css .

* {
font-family: 'Titan One';
}

What we can see here, is because we were conservative on what styles we inline, we allow the user to override them via CSS in their project. If we would have inlined color, background-color, font-size, or font-family the user would not be able to customize colors or text without using !important. No code intended to live for longer than a hack day should use !important.

We have now shown that our component can be imported and customized by an end user. It is ready for publishing.

Publishing

Once you have everything else out of the way, publishing is easy. Before publishing, you should update the file README.md and make sure you change the following fields in the boilerplate’s package.json.

  • name
  • description
  • version
  • author

Once you are satisfied and want to publish your package you will want to familiarize yourself with NPM’s publishing guide and then go ahead and publish your first React component.

After publishing, it can be installed by running yarn add [your package].

What about Webpack?

I tried bundling modules with Webpack and it can certainly be done. However it is in the nature of Webpack to bake everything together into one file, and avoiding embedding code from a third party is an opt-out strategy which you will play catch up with as your component changes. My recommendation is to avoid bundling NPM modules with Webpack as of now.

I hope you found my thoughts on this to be insightful. Please let me know if you find out of any improvements. And as always, I might be wrong about everything.

--

--

Pontus Alexander
Meth Meth Method

I’m a software engineer, living in Stockholm. I write about random things that interest me.