Tech Takes

Creating a Robust React Component Library with Rollup, TypeScript, and Storybook

June 19, 2024

Introduction

Creating a component library can significantly enhance the development workflow by promoting reuse, consistency, and efficiency. By combining React, TypeScript, Rollup, and Storybook, we can build, package, and create a robust, type-safe, and well-documented library.

Component Library Setup

Here's an step-by-step guide for creating a React component library with React, Rollup, TypeScript, and Storybook:

Step 1: Initialize the Project

mkdir my-component-library

cd my-component-library

npm init -y

Step 2: Install Dependencies

Install the necessary dependencies:

npm install --save-dev rollup @rollup/plugin-terser @rollup/plugin-node-resolve @rollup/plugin-commonjs @rollup/plugin-typescript rollup-plugin-postcss rollup-plugin-peer-deps-external @rollup/plugin-json rollup-plugin-filesize @rollup/plugin-babel rollup-plugin-dts react react-dom typescript

Here’s a brief explanation of the dependencies:

  • rollup: A module bundler to bundle JavaScript and TypeScript code.
  • @rollup/plugin-terser: Minifies the bundle to reduce file size.
  • @rollup/plugin-node-resolve: Locates and bundles dependencies in node_modules.
  • @rollup/plugin-commonjs: Converts CommonJS modules to ES6.
  • @rollup/plugin-typescript: Compiles TypeScript files.
  • rollup-plugin-postcss: Processes CSS files.
  • rollup-plugin-peer-deps-external: Excludes peer dependencies from the bundle.
  • @rollup/plugin-json: Allows importing JSON files.
  • rollup-plugin-filesize: Displays the file size of the bundle.
  • @rollup/plugin-babel: Transpiles the code using Babel.
  • rollup-plugin-dts: Generates TypeScript declaration files.

Step 3: Creating Components

Set up the component structure:

mkdir src
mkdir src/components
touch src/components/ExampleComponent.tsx

Add a simple React component to ExampleComponent.tsx:

import React from 'react';
const ExampleComponent: React.FC = () => {
  return <div>Hello, Component Library!</div>;
};
export default ExampleComponent;

Step 4: Create an Entry Point

Create an entry point for your library in src/index.ts:

export { default as ExampleComponent } from './components/ExampleComponent';

Step 5: Rollup Configuration Setup

Base Configuration

Create a base configuration file rollup.base.config.js to handle common settings and plugins:

// rollup.base.config.js

import resolve from "@rollup/plugin-node-resolve";
import commonjs from "@rollup/plugin-commonjs";
import typescript from "@rollup/plugin-typescript";
import postcss from "rollup-plugin-postcss";
import peerDepsExternal from 'rollup-plugin-peer-deps-external';
import json from '@rollup/plugin-json';
import { babel } from '@rollup/plugin-babel';

export default {
  plugins: [
    peerDepsExternal(),
    resolve({
      browser: true,
      preferBuiltins: false,
    }),
    commonjs(),
    babel({
      babelHelpers: 'bundled',
      exclude: /node_modules/,
      presets: ["@babel/preset-react", "@babel/preset-typescript"],
    }),
    typescript({
      tsconfig: "./tsconfig.json",
      outputToFilesystem: true,
    }),
    postcss(),
    json(),
  ],
};

Here's a brief explanation of the plugins mentioned:

  • peerDepsExternal(): Excludes peer dependencies from the bundle.
  • resolve(): Locates and bundles dependencies in node_modules.
  • commonjs(): Converts CommonJS modules to ES6.
  • babel(): Transpiles the code using Babel.
  • typescript(): Compiles TypeScript files.
  • postcss(): Processes CSS files.
  • terser(): Minifies the bundle.
  • json(): Allows importing JSON files.

These plugins work together to provide a comprehensive setup for bundling a React component library with TypeScript support, handling various module formats, transpiling code with Babel, processing CSS with PostCSS, and excluding peer dependencies from the bundle.

Main Configuration

Create the main Rollup configuration file rollup.config.js that imports the base configuration and adds specific settings for your library:

// rollup.config.js
import { terser } from '@rollup/plugin-terser';
import baseConfig from './rollup.base.config.js';
import dts from 'rollup-plugin-dts';

export default [
  {
    input: 'src/index.ts', // Entry point for the library
    output: [
      {
        file: packageJson.main, // Output for CommonJS (e.g., main.js)
        sourcemap: true,
        exports: 'named',
      },
      {
        file: packageJson.module, // Output for ES6 modules 

        format: 'esm',
        sourcemap: true,
      },
    ],
    external: ['react', 'react-dom'],
    preserveModules: true,
    plugins: [
      ...baseConfig.plugins,
      terser(),
    ],
  },
  {
    input: 'src/index.ts', // Type Definitions
    output: {
      file: 'dist/index.d.ts',
      format: 'esm',
    },
    plugins: [dts()],
  },
];

  • Input: Specifies the entry point file for your library, typically src/index.ts or src/index.js.
  • Output: An array defining the output formats. In this case, it generates two bundles:
  • CommonJS bundle (e.g., main.js) for Node.js environments.
  • ES module bundle (e.g., module.js) for modern browsers and bundlers.
  • File: The output file path, often determined by the main and module fields in package.json.
  • Format: The output format, either 'cjs' for CommonJS or 'esm' for ES modules.
  • Sourcemap: Generates source maps for better debugging experience

Step 6: Integrating Storybook

  • Install Storybook by running npx sb init and selecting the appropriate project builder.
  • Create a story file (e.g., Button.stories.tsx) for each component, defining different scenarios and configurations.
  • Run npm run storybook to launch the Storybook environment and visualize your components.

Step 7: Publishing the Library

  • Update the library version in package.json following the Semantic Versioning (SemVer) convention.
  • Build the library for production with npm run rollup.
  • Publish the library to a package registry like npm or a private registry.

Why Rollup?

Rollup is a popular choice over other bundling tools like Webpack or Browserify for creating JavaScript libraries and components

  • Tree Shaking: Rollup's static analysis and tree-shaking capabilities allow it to eliminate unused code from the final bundle, resulting in smaller bundle sizes.
  • Focused on Libraries: While tools like Webpack are versatile and can handle applications and libraries, Rollup is primarily focused on bundling libraries and components. Its simplicity and optimization techniques make it well-suited for this specific use case.
  • Plugins: Rollup has a rich ecosystem of plugins that can extend its functionality to handle various types of files and optimizations.
  • Output Formats: Rollup can output multiple module formats, including CommonJS and ES modules, which are essential for compatibility with different environments.
  • Simplicity: Rollup's configuration is straightforward and easier to manage compared to other bundlers like Webpack.

Common Configuration Errors

While setting up Rollup, you might encounter some common errors:

  • Plugin Compatibility Issues: Ensure plugins and dependency versions are compatible to avoid errors or unexpected behavior during the build process.
  • Incorrect Plugin Options: Refer to plugin documentation for correct usage and required options. Providing incorrect options can result in errors or undesired output
  • Plugin Order: The order of plugins matters. For example, typescript should be before terser, and babel should come after resolve and commonjs.
  • Incorrect Paths: The main and module file paths in package.json do not match the actual output file paths generated by Rollup. This mismatch causes import failures as the import statements look for the wrong file paths. To avoid this, ensure the main and module fields accurately reflect the output file paths specified in the Rollup configuration.
  • Incorrect Module Format: Using umd format instead of cjs or es can cause issues with importing the library. Ensure the format matches the expected module type.
  • Missing External Dependencies: Failing to list external dependencies can result in bundling them with the library, increasing the bundle size unnecessarily.

Conclusion

By following the steps outlined in this article, you can build a robust, type-safe, and well-documented React component library that enhances your development workflow.

Author

Table of contents

RapidCanvas makes it easy for everyone to create an AI solution fast

The no-code AutoAI platform for business users to go from idea to live enterprise AI solution within days
Learn more