Build a React Component Library
I have always liked the idea of building code as lego-blocks — re-usable, modular, simple on their own but capable of great things when they come together.
In this 4-part series, we are going to focus on building a shared Auth Component Library that can be (privately) published and consumed by your entire team.
Thoughts on create-react-library?
I tried it, I spent a week trying to figure it out and although a great package to start trying this idea out, I felt like it was a truck compared to the sports car I wanted and it really slowed down development (I couldn’t use the shorthand for fragments for some reason!). Plus, it’s not being actively maintained anymore which was a hard pass for me.
Github
If you’d like to skip to the end, here’s the github-repo:
Objective
In this tutorial, we are just going to set-up the foundations of our component library with a HelloWorld component.
1. Setting up the project
In a directory of your choice, create a simple react app:
$ npx create-react-app auth-component-library
2. Create a HelloWorld Component
- Create a
src/components
folder and create aHelloWorld.js
file inside it.(Optional: delete thepublic
folder and all the other files inside thesrc
folder)
2. Create an index.js
file inside the src
folder and export the component we just created. index.js
file will be our key file throughout this process, exporting all the components we will create inside the components
folder.
5. The folder structure should now look like this:
..
-- src/
|-- components/
|-- HelloWorld.js
|-- index.js-- package.json
3. Configure Rollup.js & Babel to Build Our Library
We have the first component of our library good to go. Now, to build our library, we need to install Rollup.js, Babel and other packages we require to bundle our library.
- We will be installing the following packages:
$ cd auth-component-library$ npm i -D @babel/cli @babel/core @babel/preset-env @babel/preset-react rollup @rollup/plugin-babel rollup-plugin-delete rollup-plugin-peer-deps-external npm-run-all
2. Next, create a .babelrc
file in the root folder. It should look like this:
3. Next, create a rollup.config.js
file in the root folder. It should look like this:
This is what each configuration field stands for:
- input: The entry point to the component(s) we want to bundle. We directly point this to our
src/index.js
which we have used to export our components. - output: This specifies the directory where you want to save the bundled library. We are importing the output paths from package.json (More about this in the next step), which we will specify as the
./dist
folder. - plugins: This specifies all the plugins you wish to use and their respective configurations. For instance,
external
is asking rollup to excludepeerDependencies
as part of the bundle as they will be imported separately by the app calling this package. We will also configurepeerDependencies
in the next step.
The folder structure at the end of this step should look like this:
-- src/
|-- components/
|-- HelloWorld.js
|-- index.js-- .babelrc
-- rollup.config.js
-- package.json
4. Configure package.json
- Add
source, main & module
values inpackage.json
for ourrollup.config.js
{
"name": "auth-component-library",
"version": "0.1.0",
"private": true,
"main": "dist/index.cjs.js",
"module": "dist/index.esm.js",
"source": "src/index.js",
...
}
2. Add react, react-dom
to peerDependencies
and remove them from dependencies
.
{ "dependencies": {
"@testing-library/jest-dom": "^4.2.4",
"@testing-library/react": "^9.5.0",
"@testing-library/user-event": "^7.2.1",
"react-scripts": "3.4.3"
}, "devDependencies": {
"@babel/cli": "^7.10.5",
"@babel/core": "^7.11.4",
"@babel/preset-env": "^7.11.0",
"@babel/preset-react": "^7.10.4",
"@rollup/plugin-babel": "^5.2.0",
"rollup": "^2.26.4",
"rollup-plugin-delete": "^2.0.0",
"rollup-plugin-peer-deps-external": "^2.2.3"
}, "peerDependencies": {
"react": "^16.13.1",
"react-dom": "^16.13.1"
},
}
3. Add scripts
(to make our lives a bit easier)
Lastly, we need to add two scripts to our package.json
which will compile the components into a bundle using the configurations in rollup.config.js
. Don’t worry about the playground scripts, just add them, they’ll make more sense in the next step when we set up our “Testing Playground”.
{
...
"scripts": {
"build": "rollup -c",
"build-watch": "rollup -c -w",
"start-playground": "cd playground && npm run start",
"i-all": "npm i && cd playground && npm i",
"dev": "npm-run-all --parallel build-watch start-playground" },
...
}
4. The new package.json
should look like this:
5. Let’s build our library!
Now, run the following commands:
$ npm update && npm run build
You should have a ./dist
folder with two bundled files in it, index.cs.js
and index.esm.js
You have successfully created a component library! Now, we build our Testing Playground.
5. Add a Testing Playground to Our Project
We are now going to create a “playground” in our app so we can test our components as we develop them.
- For this, we are going to create another react app, this time inside the app we have already created.
$ cd auth-component-library
$ npx create-react-app playground
2. Add the auth component library you just created as a dependency in playground/package.json
. Also make sure to link react and react-dom to the already installed packages. Without this, it will give you “Invalid Hook Call” error when we start adding more complex components.
{
"name": "playground",
"version": "0.1.0",
"private": true,
"dependencies": {
"@testing-library/jest-dom": "^4.2.4",
"@testing-library/react": "^9.5.0",
"@testing-library/user-event": "^7.2.1",
"auth-component-library": "file:..",
"react": "file:../node_modules/react",
"react-dom": "file:../node_modules/react",
"react-scripts": "file:../node_modules/react-scripts"
},
...}
3. Modify playground/src/App.js
to call the <HelloWorld />
component
4. Run the playground app:
$ npm run i-all
$ npm run dev
This will build our library, watch for modifications, and run the Playground App at http://localhost:3000
. You should now see “Hello World” on your screen in giant letters. It’s a small but meaningful victory!
You can also modify the <HelloWorld />
component and your screen should update automatically.
Next Steps:
- In Part II, we publish our shared component library in a private Github Respository so it can be easily shared across the team.
- In Part III, we add complex Material UI components to our library, such as fully-functional
<SignIn />
component. - In Part IV, we add a mock JSON-API to our playground, to make sure our components will consume production Rest APIs properly.