Your Web News in One Place

Help Webnuz

Referal links:

Sign up for GreenGeeks web hosting
June 20, 2022 02:20 pm GMT

How to create and publish a react component library (not the storybook way)

Hello everyone! Just some backstory before we start, I got selected for GSoC this year (2022) with Rocket.Chat organization. The project in which I was selected is to create an easy to embed React component of Rocket.Chat (like a mini-version of it) that can be plugged into any web application made in React.

Something like this,

import { RCComponent } from rc-react-component<RCComponent />

So when I was writing my proposal, I had researched a lot about the ways in which we can create a React component library.

As my project demanded that it should be a single component that should be tightly coupled up with the backend features provided by the RocketChat API, me and my mentor decided to go with a traditional approach of creating a React component library i.e, by not using Storybook.

I wanted to share this way, where you can get started with creating a component library instantly and naturally (without worrying about learning any other technology). For a detailed approach about why I chose some things over the other, I will be writing bi-weekly blogs about my progress in the EmbeddedChat project. But for now, let's create a simple counter component.

First of all create a project directory and initialize your npm project with,

npm init -y

Install react and react-dom as peer dependencies by,

npm i save-peer react react-dom

I went with rollup as my bundler of choice but you can go with any bundler of your preference. I am linking some articles that made up my mind for choosing rollup for creating component libraries:

I have also made a separate repository containing configuration files and example libraries created using both rollup and webpack. You can check it out too, if you want to go with webpack.

Now, lets install rollup and all the plugin dependencies

npm i save-dev rollup rollup-plugin-postcss @rollup/plugin-babel @rollup/plugin-commonjs @rollup/plugin-node-resolve rollup-plugin-peer-deps-external

After installation, lets create a rollup.config.js file which will contain our configuration for desired output files. I went with both cjs and esm modules.

// rollup.config.jsimport resolve from "@rollup/plugin-node-resolve";import commonjs from "@rollup/plugin-commonjs";import babel from "@rollup/plugin-babel";import postcss from "rollup-plugin-postcss";import external from "rollup-plugin-peer-deps-external";const packageJson = require("./package.json");export default [  {    input: "src/index.js",    output: [      { file: packageJson.main, format: "cjs", sourcemap: true },      { file: packageJson.module, format: "esm", sourcemap: true },    ],    plugins: [      resolve(),      commonjs({ include: ['node_modules/**'] }),      babel({        exclude: "node_modules/**",        presets: ["@babel/env", "@babel/preset-react"],        babelHelpers: 'bundled'      }),      postcss(),      external(),    ],  },];

As you can see we are using packageJson.main and packageJson.module so lets add them,

// package.json{..."main": "dist/cjs/index.js","module": "dist/esm/index.js",...}

Install babel and all the required dependencies to work with React.

npm i --save-dev @babel/core @babel/preset-env @babel/preset-react babel-jest

Create a babel.config.js file and add these,

// babel.config.jsmodule.exports = {  presets: [    [      "@babel/preset-env",      {        modules: false,        bugfixes: true,        targets: { browsers: "> 0.25%, ie 11, not op_mini all, not dead" },      },    ],    "@babel/preset-react",  ],};

For testing, I am going with jest and react-testing-library and these can be installed by,

npm i --save-dev jest @testing-library/react react-scripts identity-obj-proxy

Add the jest configuration file, create jest.config.js and add,

// jest.config.jsmodule.exports = {  testEnvironment: "jsdom",  moduleNameMapper: {    ".(css|less|scss)$": "identity-obj-proxy",  },};

We need react-scripts to run tests and to use it inside playground for running all the scripts (start, build, test and eject) this will ensure we get no conflicts. identity-obj-proxy is needed because when we will be running tests, jest cannot determine what we are importing from module CSS, so it will proxy it to an empty object of sorts.

We will be needing some more dependencies to run our project and use them in our scripts, lets install them too,

npm i --save-dev npm-run-all concurrently cross-env rimraf

Lets add some scripts to run our project now,

// package.json{"scripts": {    "prebuild": "rimraf dist",    "build": "rollup -c",    "watch": "rollup -c --watch",    "dev": "concurrently \" npm run watch \" \" npm run start --prefix playground \"",    "test": "run-s test:unit test:build",    "test:unit": "cross-env CI=1 react-scripts test --env=jsdom",    "test:watch": "react-scripts test --env=jsdom --coverage --collectCoverageFrom=src/components/**/*.js",    "test:build": "run-s build",    "prepublish": "npm run build"  },}

Lets create the component now,

Create src directory and inside this create index.js, index.test.js and index.module.css

// index.jsimport React, { useState } from "react";import styles from "./index.module.css";export const SimpleCounterComponent = () => {  const [counter, setCounter] = useState(0);  return (    <div>      <h1 className={styles.red}>Counter Component</h1>      <div>{counter}</div>      <button onClick={() => setCounter((prev) => prev + 1)}>increment</button>    </div>  );};
// index.test.jsimport React from "react";import { render } from "@testing-library/react";import { SimpleCounterComponent } from "./index";describe("SimpleCounterComponent Component", () => {  test("renders the SimpleCounterComponent component", () => {    render(<SimpleCounterComponent />);  });});
// index.module.css.red {  color: red;}

Now, when you run npm run build it will create a dist directory with our bundled output files (in both cjs and esm formats) but you definitely need to test your component before you ship, right?

Create a playground app by running npx create-react-app playground. Remember we downloaded react-scripts, change package.json of the playground app as follows,

// playground/package.json{    "dependencies": {    "@testing-library/jest-dom": "^5.16.4",    "@testing-library/react": "^13.3.0",    "@testing-library/user-event": "^13.5.0",    "react": "file:../node_modules/react",    "react-dom": "file:../node_modules/react-dom",    "react-scripts": "file:../node_modules/react-scripts",    "simple-counter-component": "file:../",    "web-vitals": "^2.1.4"  },    "scripts": {    "start": "node ../node_modules/react-scripts/bin/react-scripts.js start",    "build": "node ../node_modules/react-scripts/bin/react-scripts.js build",    "test": "node ../node_modules/react-scripts/bin/react-scripts.js test",    "eject": "node ../node_modules/react-scripts/bin/react-scripts.js eject"  },}

This will make use of the react-scripts downloaded in the root and also point to use react, react-dom thats installed in the root. This will save you from 3 days of headache if you are not familiar with how npm link works, and will throw an error that different react versions are used in your project and hooks cannot be used etc.

Now do an npm install in the playground, and you are ready to go.

Go back to the root directory and run npm run dev it will open up the playground application and you can do your changes in the component while watching the changes reflect real-time in the playground environment.

Now for publishing your component, make sure you use a name which has not been taken yet. After you come up with a name, you can use it in package.json's name attribute.

You can just do npm publish to publish your package, but it can show you an error if this is your first time. You need to create an account in https://www.npmjs.com/ and after that login using npm login in your terminal. After youve successfully logged in yourself, npm publish!

You can further improve your project by adding ESlint, prettier, terser-plugin (to minify) etc. which I am not including in this blog.

Last important thing, make sure you are shipping only the required module and not everything. This will heavily determine the size of your package. So if you want to just ship the dist directory, add this in your package.json.

// package.json "files": [    "dist"  ],

Checkout the repository here.

Hooray! Our package has been published. You can do npm i simple-counter-component to check it out. To manage versioning, you can use a great library called np.

Please let me know on the things that can be improved in the comment section below. Thank you.

If you want to connect:
Email : [email protected]
GitHub: https://github.com/sidmohanty11
LinkedIn: https://www.linkedin.com/in/sidmohanty11
Twitter: https://twitter.com/sidmohanty11


Original Link: https://dev.to/sidmohanty11/how-to-create-and-publish-a-react-component-library-not-the-storybook-way-3b07

Share this article:    Share on Facebook
View Full Article

Dev To

An online community for sharing and discovering great ideas, having debates, and making friends

More About this Source Visit Dev To