How I set-up a React component library with Rollup

Jebus
Jebus
Oct 2, 2017 · 5 min read

This is a simple story, I needed to create a UI-Kit to be used on various React projects for the company where I work. I took a couple of days looking for a suitable configuration that would cover all the requirements I needed (it should be simple, easy to use, flexible, without too much configuration stuff, etc..). I tried several Toolkits, Boilerplates, etc. but none of them convinced me at all. So I decided to create my own simple setup with these features:

  • React as core
  • JS Syntax: ES6 with Babel + Plugins
  • Rollup as module bundle
  • CSS: PostCSS + CSS Module + classnames for binding the names

This is the process I followed:

The first thing I did was initialize the project,

$ mkdir react-ui-kit
$ cd react-ui-kit
react-ui-kit $ npm init -y

I created this folder structure:

// into react-ui-kit folderdist/                                           (the output folder)
node_modules/
src/
index.js (Entry point)
.babelrc (Babel config file)
|-- components/ (Components folder)
|-- Alert/ (My First component)
|-- Alert.js
|-- Alert.css
|-- OtherComponent/
|-- OtherComponent.js
|-- OtherComponent.css
package.json
rollup.config.js (Rollup config file)

Then I installed the first dependencies and devDependencies libraries:

react-ui-kit $ npm i -S react react-dom react-proptypesreact-ui-kit $ npm i -D babel-core babel-plugin-external-helper babel-preset-latest babel-preset-react babel-preset-stage-1react-ui-kit $ npm i -D rollup rollup-plugin-babel rollup-plugin-commonjs rollup-plugin-node-resolve

I checked if the module bundle worked:

react-ui-kit $ ./node_modules/rollup/bin/rollup src/index.js -f cjs -o dist/bundle.jssrc/index.js → dist/bundle.js...
(!) Generated an empty bundle
created dist/bundle.js in 19ms

Great, it seemed to be all ok, so I went to the next step:

Start with the setup

I created a file called rollup.config.js in the root directory and put down the first configurations for the module bundle. Also I edited the package.json and added the build task.

// rollup.config.jsexport default {
input: 'src/index.js',
output: {
file: 'dist/bundle.js',
format: 'cjs'
}
};

// package.json
...
"main": "dist/index.js",
"style": "dist/styles.css",
"files": [
"dist"
],
"scripts": {
"test": "echo \"Error: no test specified\" && exit 1",
"build": "rollup -c"
}
...

After that, I created the first component of the library:

// src/components/Alert/Alert.jsimport React from 'react';
import PropTypes from 'react-proptypes';
const AlertComponent = ({ message = 'this is an alert' }) => (
<div>
<span>{message}</span>
</div>
);
StatelessComponent.propTypes = {
message: PropTypes.string,
};
export default AlertComponent;// src/components/Alert/Alert.css.Alert {
width: 100%;
height: auto;
border: 1px solid midnightblue;
padding: 10px;
background-color: lightcoral;
}
// src/components/index.jsexport Alert from './components/Alert/Alert';

So far so good. The next step was to configure Babel with Rollup because I was writing my component with ES6 syntax.

Configure ES6 with Babel

// rollup.config.js// node-resolve will resolve all the node dependencies
import resolve from 'rollup-plugin-node-resolve';
import babel from 'rollup-plugin-babel';
export default {
input: 'src/index.js',
output: {
file: 'dist/bundle.js',
format: 'cjs'
},
// All the used libs needs to be here
external: [
'react',
'react-proptypes'
],
plugins: [
resolve(),
babel({
exclude: 'node_modules/**'
})
]

}

Also I created the .babelrc file in the root directory and put this necessary configuration (you can find more info here).

// .babelrc{
"presets": [
"stage-1",
"react",
[
"latest", {
"es2015": {
"modules": false
}
}
]
],
"plugins": ["external-helpers"]
}

I ran the build and checked if all looked fine one more time:

react-ui-kit $ npm run buildsrc/index.js → dist/bundle.js...
created dist/bundle.js in 211ms

The last thing I needed was to configure the styles for the components.

Why I chose PostCSS and CSS Modules ?

PostCSS is a tool for transforming styles with JS plugins. These plugins can lint your CSS, support variables and mixins, transpile future CSS syntax, inline images, and more.

CSS Module is a CSS file in which all class names and animation names are scoped locally by default.

In combination, both are great tools when we need to create UI components with their styles and local scope.

So, I installed the last dependencies:

react-ui-kit $ npm i -D rollup-plugin-postcss postcss-modules
react-ui-kit $ npm i -S classnames

I updated the rollup.config.js file one more time:

// rollup.config.jsimport resolve from 'rollup-plugin-node-resolve';
import babel from 'rollup-plugin-babel';
// Convert CJS modules to ES6, so they can be included in a bundle
import commonjs from 'rollup-plugin-commonjs';
import postcss from 'rollup-plugin-postcss';
import postcssModules from 'postcss-modules';
const cssExportMap = {};export default {
input: 'src/index.js',
output: {
file: 'dist/bundle.js',
format: 'cjs'
},
external: [
'react',
'react-proptypes'
],
plugins: [
resolve(),
postcss({
plugins: [
postcssModules({
getJSON (id, exportTokens) {
cssExportMap[id] = exportTokens;
}
})
],
getExportNamed: false,
getExport (id) {
return cssExportMap[id];
},
extract: 'dist/styles.css',
}),

commonjs(),
babel({
exclude: 'node_modules/**'
})
]
}

Note: here you will find more information about how to implement CSS Modules with PostCSS.

The final step was to bind the styles to the Alert component:

// src/components/Alert/Alert.jsimport React from 'react';
import PropTypes from 'react-proptypes';
import cn from 'classnames/bind';
import styles from './Alert.css';
const cx = cn.bind(styles);const AlertComponent = ({ message = 'this is an alert' }) => (
<div className={cx(styles.Alert)}>
<span>{message}</span>
</div>
);
StatelessComponent.propTypes = {
message: PropTypes.string,
};
export default AlertComponent;

And that’s all. I ran the build and checked the result:

react-ui-kit $ npm run buildsrc/index.js → dist/bundle.js...
created dist/bundle.js in 261ms
react-ui-kit $ tree dist
dist/
├── bundle.js
└── styles.css
0 directories, 2 files

The difficult thing was over. Now, the only thing I needed to do was to publish the library to the npm registry and include it in the other projects.

// Other React Projectimport 'react-ui-kit/dist/styles.css';
import { Alert } from 'react-ui-kit';
const AppComponent = () => (
<div>
<Alert message="It's works !!!" />
</div>
);
export default AppComponent;

Conclusion

Once I finished configuring everything, I realized that I had spent more time testing different tools and solutions than creating new ones. Sometimes when you think it will be the hardest path, it can be the fastest and simplest, if you just try it.

Useful links

Grandata Engineering

Engineers telling their experience on how they overcame difficulties with creativity

Jebus

Written by

Jebus

Frontend Developer at Grandata

Grandata Engineering

Engineers telling their experience on how they overcame difficulties with creativity

Welcome to a place where words matter. On Medium, smart voices and original ideas take center stage - with no ads in sight. Watch
Follow all the topics you care about, and we’ll deliver the best stories for you to your homepage and inbox. Explore
Get unlimited access to the best stories on Medium — and support writers while you’re at it. Just $5/month. Upgrade