In this article I tried to talk the steps of create a react component library.
Why do we need to build a react component library?
If you have several components that are shared between your projects or some js code that is copy-pasting and these things happen more than 2 or 3 times then you need to convert your shared code to a library.
So let's create a react component library.
First, we need to generate our component. We can create a React project and create a component. Our folder structure would be like this:
├── src
│ ├── components
| │ ├── Button
| | │ ├── Button.tsx
| | │ ├── Button.scss
| | │ └── index.ts
| │ ├── TextField
| | │ ├── TextField.tsx
| | │ ├── TextField.scss
| | │ └── index.ts
| │ └── index.ts
├── package.json
├── tsconfig.json
└── rollup.config.js
src/components/index.ts
export { default as Button } from "./Button";
export { default as TextField } from "./TextField";
After we create our component we need to config our rollup. We use rollup to bundle our library(also we could use webpack).
Let's config our rollup to bundle our library:
rollup.config.js
import externalDeps from 'rollup-plugin-peer-deps-external';
import typescript from '@rollup/plugin-typescript';
import sourcemaps from 'rollup-plugin-sourcemaps';
import resolve from '@rollup/plugin-node-resolve';
import commonJS from 'rollup-plugin-commonjs';
import replace from '@rollup/plugin-replace';
import styles from 'rollup-plugin-styles';
import babel from 'rollup-plugin-babel';
import json from '@rollup/plugin-json';
import pkg from './package.json';
const globals = {
react: 'React',
'react-dom': 'ReactDOM',
'react-query': 'ReactQuery',
};
const plugins = [
externalDeps(), //prevents packages listed in peerDependencies from being bundled with our component library
commonJS(), //convert common js modules to es6
resolve(), // Locate and bundle third-party dependencies in node_modules
typescript(), // transpiles our TypeScript code into JavaScript.
postcss() // transforms our Sass into CSS
];
export default {
input: `./src/components/index.ts`,
output: [
{
name: 'index',
file: `lib/index.cj.js`,
format: 'cjs',
sourcemap: true,
},
{
name: 'index' ,
file: `lib/index.es.js`,
format: 'esm',
sourcemap: true,
},
{
name: 'index',
file: `lib/index.umd.js`,
format: 'umd',
sourcemap: true,
globals,
},
],
plugins,
}));
esm vs common js vs umd
These types are js module formats.
Some tools like webpack and node use common js format and some tools like rollup and webpack2 use esm module. umd(Universal Module Definition) is the type of module that strive to work everywhere. Also, umd is a kind of fallback for other formats. If you want to include any of these files in the browser as standalone script tags without a build step like e.g. Webpack, you will want to use umd.
How to test our packages?
we have 3 options to test our package before publishing:
- npm link
- npm pack
- Storybook
npm link:
npm link add our package in node_module universal of your system and install your package globally. every time we change our files this package will be updated in node_modules folder.
npm pack:
This command will pack our package and we can install the package in our project. with every change that we make in our package, we need to run this command and install our library again.
Storybook:
In my opinion, the best way to test our package locally is Storybook.
In addition, to test our package, we can also have good documentation.
Final step:
Finally, we should publish our package.
with npm publish
we can publish our package in the npm registry but before that, we should create an account in npm.
also, we need to make some changes in our packge.json file.
package.json:
{
"name": "@react-components-library/react-sample-components-library",
"version": "0.0.20",
"main": "lib/index.js", // common js
"module": "lib/index.es.js", //esm
"browser": "lib/index.umd.js", //umd
"files": [
"/lib"
],
"type": "module",
"scripts": {
"test": "jest",
"start": "styleguidist server",
"build": "rm -rf ./lib && rollup -c",
"prepublishOnly": "rm -rf lib && npm run build",
"postbuild": "npm pack && tar -xvzf *.tgz && rm -rf package *.tgz",
"docs:build": "styleguidist build"
},
"peerDependencies": {
"react": "17.0.2",
"react-dom": "17.0.2"
},
...
}
There are some tips here:
- we should our react and react-dom in our peerDependencies to prevent rollup to add these packages in our bundle.
- when
npm publish
execute, first runprepublishOnly
script. so we can add our build steps to this script. -
files
indicates which files or folders should push to the npm registry.
Top comments (3)
You don’t “need” a component library, it can be rather useful and beneficial.
Here are some points I would like to mention:
You don’t use component libraries only for components that are shared between projects. We can also build component libraries for other developers to use in their own projects, which is what we call “open source”, one of the main reasons why we have npmjs, for example.
Team collaboration is another advantage of a component library, because you can share your component with your team mates. Working in projects is not always an egocentric and independent craft, it is a teamwork effort.
Pre-build components also have the advantage of being better-performant, which leads to faster load times, which at the end of the day benefits the user experience.
Building a component library has more benefits, these are some of the main points I believe are important when it comes to building an NPM library.
Whether exposed to the outside-world (as an node package) or not, is not the issue.
This article doesn't deal with the "need"/"reason" but the "how".
More developers don't know how to even start making a components "library" because they are so focused on the day-to-day tasks which are just tiny pieces of a big puzzle (most) never really understand (yet) or ever wish to understand.
I've met many front-end developers in my (almost 20 years) career and maybe 1% will even obtain the ability to really build a library, as they are clueless about the tooling and how it's all connected.
You have made great points!
The author mentioned “need”, hence why I said it. It is not a must, but it’s a great tool to have in one’s belt.
I think building component libraries should become a skill taught in courses, bootcamps and also part of the curriculum in software engineering degrees - which I’m not exactly sure if they already do, because I’m in CS, but if they haven’t included this topic, in my opinion, they should.
The thing with building libraries is the configuration, which I believe is the “trickiest” to learn how to setup, particularly in TypeScript, for those who use it. But, the outcomes are great!
Besides, building libraries and publishing on NPM is loads of fun, particularly when you go and see the downloads rising 🙃
I think that one other important thing to keep in mind when it comes to building component libraries is the fact that some of the existing libraries are outdated or don’t work well with certain versions of a framework, let’s say Vue 2 and 3, for example. It is also important to look for a “niche”, something that nobody explored yet or that is still very much untouched.
At the end of the day, it all comes down to the ambition of the developer and the needs for a particular project, as well as the demand for a particular library.