How to create a react component library with TypeScript, rollup.js and Storybook

hero-image

“Why would I want to set up a component library on my own?”. Well, we all have been to this point: Once our application grows, things tend to get complex and overwhelming. Despite the best intentions components start to have inconsistencies. Things get hard to maintain, and development speed decreases… wouldn’t it be nice to have a component friendly development environment that supports you to write consistent code and enables you to share the same components over and over in multiple projects?

This short guide will show you how to create your own bulletproof (aka decoupled) component library and tackle these challenges.

You will end up with …

  1. … less redundant/duplicate code.

  2. … consistent and robust components.

  3. … a speed up in development time.

  4. … a documentation/Styleguide.

  5. … a better collaboration between front-end and design teams.

That’s a lot of benefits. Let’s start!

Prerequisites

Before reading, you should have some fundamental knowledge of the following technologies:

  1. node.js and npm

  2. Typescript

  3. React

  4. Storybook

  5. rollup.js

At first initialize a new project:

npm init

Add Storybook

Once we created the project and initialized our repository we add Storybook. Storybook provides the possibility to browse and preview components and associated assets. It allows you to develop components in isolation.

npx -p @storybook/cli sb init --type react

Next we’ll add TypeScript support by adding a preset along with a loader for TypeScript files. ( — As of Storybook v6.0 the preset is no longer needed, I updated the Github repository below— )

npm install -D fork-ts-checker-webpack-plugin typescript

Once installed, add this preset to your storybook configuration.

# .storybook/main.js

module.exports = {
 stories: ["../stories/**/*.stories.js"],
 addons: [
  "@storybook/addon-actions",
  "@storybook/addon-links",
  "@storybook/preset-typescript"
 ],
  typescript: {
   check: false,
   checkOptions: {},
   reactDocgen: 'react-docgen-typescript',
   reactDocgenTypescriptOptions: {
     shouldExtractLiteralValuesFromEnum: true,
     propFilter: (prop) *=>* (*prop*.parent ?  !/node_modules/.test(*prop*.*parent*.fileName) : true),
}});

  config.resolve.extensions.push(".ts", ".tsx");
  *return* config;
 }
};

Finally we need to configure typescript. We want to achieve two things from TypeScript: First, our own codebase for TypeErrors.

Second, we want to export type declarations. You can check all configuration options over here.

{" "}

Before we can test our setup, we need to rename the autogenerated “stories” directory to “src” and the filetype from “.js” to “.tsx”.

By now, our project should be structured like this:

.
├── package-lock.json
├── package.json
├── src
│   ├── 0-Welcome.stories.tsx
│   └── 1-Button.stories.tsx
└── tsconfig.json

Now test this setup and run

npm run storybook

Bundle the library with rollup.js

Now that we have created a solid development environment for our components, it’s time to bundle them for production. Rollup is a excellent choice for bundling your library ( Use webpack for apps and rollup for libraries 🙂)

npm install @rollup/plugin-commonjs @rollup/plugin-node-resolve rollup-plugin-peer-deps-external rollup-plugin-typescript2 -D

Add build script and “main” + “module” to package.json, Add react + react-dom as peerDependencies

# package.json
{

(...)

  "main": "./build/index.js",
  "module": "./build/index.es.js",
  "peerDependencies": {
    "react": "16.13.1",
    "react-dom": "16.13.1"
  },
  "scripts": {
    "storybook": "start-storybook -p 6006",
    "build-storybook": "build-storybook",
    "build": "rollup -c"
  },

(...)

}

Eslint

When it comes to linting, there are two major options for TypeScript projects: TSlint and ESLint. We will use the latter, because it supports both JavaScript and TypeScript. Apart from that ESlint has the more-performant architecture. Which is one of several reasons why the TypeScript core team recommends it.

Using a good Linter is essential. It helps you to identify “code smells”. A Linter detects ugly code and even makes suggestions on how to replace it with better solutions. Finally, it’s up to you if you go with your own configuration or if you choose to take a pre-configured set of rules (e.g., Airbnb`s Code Style Guide).

npm install eslint eslint-plugin-react [@typescript](http://twitter.com/typescript)-eslint/eslint-plugin [@typescript](http://twitter.com/typescript)-eslint/parser -D

Prettier

Prettier is an opinionated code formatter. Having the same code format is crucial. With everybody in your team formatting the code identically, all changes in the files are guaranteed to be meaningful. No more “empty” commits containing only spaces, tabs or line-breaks. No arguing anymore that one style is better than another. It’s taking programmers ego out of the equation.

Most editors can be configured to run prettier on saving. Formatting your code becomes a side-effect of changing your files. It’s fun and saves both time and energy.

npm install prettier -D

Combining ESLint + Prettier

We want Prettier to be in charge of our code format. Therefore we need to disable any existing formatting rules in our ESLint configuration that might conflict.

npm install eslint-config-prettier eslint-plugin-prettier -D

After having everything set up, we will end up with the following ESLint configuration. Put it into your .eslintrc configuration file.

Jest

Jest is a JavaScript library for creating, running, and structuring tests. It’s one of the most popular test runners these days. You can install it along with its ESLint and TypeScript dependencies.

npm install @types/jest @types/node jest ts-jest eslint-plugin-jest -D

Next, create the following jest.config.js in your root directory. It tells Jest to look for React/Typescript files, including a “.test.” or “.spec.” substring in their extension. Jest expects them to be within the src directory.

React testing library

We want to test our components in a way that resembles how the user would use it. @kentcdodds react-testing-library allows us to just do that by providing lightweight utility functions on top of react-dom and react-dom/test-utils. You can learn more about it on his blog.

npm install @testing-library/react @testing-library/jest-dom @types/testing-library__react -D

Conclusion

There you have it. A convenient way to develop and share your react components. If you don’t have the time to follow along and set up each and every step manually, you can checkout or fork this project here: thepeaklab/react-component-library-starterContribute to thepeaklab/react-component-library-starter development by creating an account on GitHub.github.com