kyle1 / react-component-library-template

Instructions and template for creating a React component library

Geek Repo:Geek Repo

Github PK Tool:Github PK Tool

How to Create a React Component Library

Initialize the Package

mkdir my-component-library
cd my-component-library
npm init

You will be prompted for input about the package. You can answer with the default values and update the package settings later.

Install React

npm install react --save-dev

Install & Configure TypeScript

npm install typescript @types/react --save-dev

Generate a TypeScript config file using the following command:

npx tsc --init

Configure the TypeScript settings:

// tsconfig.json
{
  "compilerOptions": {
    // Default
    "esModuleInterop": true,
    "forceConsistentCasingInFileNames": true,
    "strict": true,
    "skipLibCheck": true,

    // Added/changed
    "target": "es5",
    "jsx": "react-jsx",
    "module": "ESNext",
    "declaration": true,
    "declarationDir": "types",
    "sourceMap": true,
    "outDir": "dist",
    "moduleResolution": "node",
    "allowSyntheticDefaultImports": true,
    "emitDeclarationOnly": true
  }
}

Create a Component

In the package directory, create a src directory with the structure shown below:

├── my-component-library
│   ├── node_modules
│   ├── src
│   │   ├── components
│   │   │   ├── Button
│   │   │   │   ├── Button.css
│   │   │   │   ├── Button.tsx
│   │   │   │   └── index.ts
│   │   │   └── index.ts
│   │   └── index.ts
│   ├── .gitignore
│   ├── package.json
│   ├── README.md
│   └── tsconfig.json
/* src/components/Button/Button.css */
.button {
  font-size: 100px;
}
// src/components/Button/Button.tsx
import "./Button.css";

interface ButtonProps {
  label: string;
}

export const Button = ({ label }: ButtonProps) => {
  return <button className="button">{label}</button>;
};
// src/components/Button/index.ts
export { Button } from "./Button";
// src/components/index.ts
export { Button } from "./Button";
// src/index.ts
export * from "./components";

Install & Configure Rollup

Install Rollup and plugins

npm install rollup @rollup/plugin-node-resolve @rollup/plugin-typescript @rollup/plugin-commonjs rollup-plugin-dts rollup-plugin-postcss rollup-plugin-peer-deps-external --save-dev
  • @rollup/plugin-node-resolve - For Rollup to locate and bundle third-party dependencies in node_modules. The dependencies meant here are the dependencies listed in your package.json file.
  • @rollup/plugin-typescript - To help integrate with TypeScript in an easier fashion. Covers things like transpiling TypeScript to JavaScript.
    • Note: both typescript and tslib are peer dependencies of this plugin that need to be installed separately.
  • @rollup/plugin-commonjs - For Rollup to convert CommonJS modules into ES6, so that they can be included in a Rollup bundle. It is typically used along with @rollup/plugin-node-resolve, to bundle the CommonJS dependencies.
  • rollup-plugin-dts - Rollup your .d.ts definition files
  • rollup-plugin-css - To integrate with PostCSS
  • rollup-plugin-peer-deps-external - Excludes peer dependencies from the bundle

@rollup/plugin-typescript has an additional dependency that needs to be installed:

npm install tslib --save-dev

Create Rollup configuration file rollup.config.mjs in the project root directory:

// rollup.config.mjs
import commonjs from "@rollup/plugin-commonjs";
import resolve from "@rollup/plugin-node-resolve";
import typescript from "@rollup/plugin-typescript";
import dts from "rollup-plugin-dts";
import peerDepsExternal from 'rollup-plugin-peer-deps-external';
import postcss from "rollup-plugin-postcss";

import packageJson from "./package.json" assert { type: "json" };

export default [
  {
    input: "src/index.ts",
    output: [
      {
        file: packageJson.main,
        format: "cjs",
        sourcemap: true,
      },
      {
        file: packageJson.module,
        format: "esm",
        sourcemap: true,
      },
    ],
    plugins: [
      // Preferably set as first plugin.
      peerDepsExternal(),
      resolve(),
      commonjs(),
      typescript({ tsconfig: "./tsconfig.json" }),
      postcss(),
    ],
  },
  {
    input: "dist/esm/types/index.d.ts",
    output: [{ file: "dist/index.d.ts", format: "esm" }],
    plugins: [dts()],
    external: [/\.css$/],
  },
];

Package Settings

// package.json
{
  "name": "my-component-library",
  "version": "1.0.0",
  "description": "My React component library",
  "author": "Name",
  "license": "MIT",
  "main": "dist/cjs/index.js",
  "module": "dist/esm/index.js",
  "files": ["dist"],
  "types": "dist/index.d.ts",
  "scripts": {
    "rollup": "rollup -c"
  },
  "devDependencies": {
    "@rollup/plugin-commonjs": "^24.1.0",
    "@rollup/plugin-node-resolve": "^15.0.2",
    "@rollup/plugin-typescript": "^11.1.0",
    "@types/react": "^18.2.6",
    "react": "^18.2.0",
    "rollup": "^3.21.5",
    "rollup-plugin-dts": "^5.3.0",
    "rollup-plugin-postcss": "^4.0.2",
    "tslib": "^2.5.0",
    "typescript": "^5.0.4"
  },
  "peerDependencies": {
    "react": "^18.2.0"
  }
}
  • "main": "dist/cjs/index.js" - Path of the CommonJS-style module
  • "module": "dist/esm/index.js - Path of the ECMAScript-style module
  • "files": ["dist"] - Array of file patterns that describes the entries to be included when your package is installed as a dependency.
  • "types": "dist/index.d.ts" - Path of the bundled declaration file.
  • "scripts.rollup": "rollup -c" - Script to create a bundle with Rollup using the config file
  • "peerDependencies" : { "react": "x.x.x" } - The apps using the library will have React installed

Create the Bundle

npm run rollup

Publish to GitHub

Create a .gitignore file:

# .gitignore
dist
node_modules

Create a GitHub repostiory and push the code.

Add the following to the package.json configuration:

// package.json
{
  "name": "GITHUB_USERNAME/REPO_NAME",
  "publish": {
    "registry": "https://npm.pkg.github.com/GITHUB_USERNAME"
  }
  ...
}

Create npm config file .npmrc in home directory (e.g. C:/Users/username/.npmrc)

registry=https://registry.npmjs.org/
@YOUR_GITHUB_USERNAME:registry=https://npm.pkg.github.com/
//npm.pkg.github.com/:_authToken=YOUR_AUTH_TOKEN

To get your auth token:

  1. Go https://github.com/settings/tokens.
  2. Click "Generate new token" button (classic mode)
  3. Check the "write:packages" scope
  4. Copy the token.

Publish the package to your GitHub by running the command:

npm publish

Go to your GitHub profile page and click the Packages tab to see the package you just published.

Using the Package Locally

You might want to keep your library private. You can import your local package into one of your projects by simply adding it as a dependency in the project:

npm i ./path-to/my-component-library

This will add your local package as a dependency in package.json:

// my-frontend-app/package.json
{
  ...
  "dependencies": {
    "my-component-library": "file:./path-to/my-component-library",
    ...
  }
}

You will now be able to import Button from "my-component-library".

If changes are made to the component library, recreate the package bundle by running the npm run rollup command in the library's root directory. The library changes will then take effect in the consumer app because a link was created to the local package when it was installed as a dependency.

Add Tailwind (Optional)

npm install tailwindcss postcss autoprefixer --save-dev
npx tailwindcss init -p

Add the paths to all of your template files in your tailwind.config.js file:

// tailwind.config.js
/** @type {import('tailwindcss').Config} */
export default {
  content: ["./index.html", "./src/**/*.{js,ts,jsx,tsx}"],
  theme: {
    extend: {},
  },
  plugins: [],
};

Insert Tailwind's base, components, and utilities styles into your CSS

/* src/styles/tailwind.css */
@tailwind base;
@tailwind components;
@tailwind utilities;

Import the CSS into the components entry point

// src/components/index.ts
import "../styles/tailwind.css";

export { Button } from "./Button";

You can now add Tailwind styles to your components that will be included in the rollup build.

Add Storybook

Install Storybook:

npx storybook@latest init

When asked if you would like to run the missing-babelrc migration on your project, answer "Y".

Answer "Y" to the three follow-up questions.

Install the following addons:

npm install @storybook/addon-a11y @storybook/addon-styling --save-dev

Then include the addons in your .storybook/main.ts file:

// .storybook/main.ts
import type { StorybookConfig } from "@storybook/react-webpack5";
const config: StorybookConfig = {
  stories: ["../src/**/*.stories.mdx", "../src/**/*.stories.@(js|jsx|ts|tsx)"],
  addons: [
    "@storybook/addon-a11y",
    "@storybook/addon-essentials",
    "@storybook/addon-interactions",
    "@storybook/addon-links",
    {
      // https://storybook.js.org/recipes/tailwindcss
      name: "@storybook/addon-styling",
      options: {
        // Check out https://github.com/storybookjs/addon-styling/blob/main/docs/api.md
        // For more details on this addon's options.
        postCss: true,
      },
    },
  ],
  framework: {
    name: "@storybook/react-webpack5",
    options: {},
  },
  docs: {
    autodocs: "tag",
  },
};
export default config;

Provide Tailwind to your stories in the preview.ts file. Use withThemeByClassName to add your themes to the Storybook toolbar

// .storybook/preview.ts
import type { Preview } from "@storybook/react";
import "../src/styles/tailwind.css";

const preview: Preview = {
  parameters: {
    actions: { argTypesRegex: "^on[A-Z].*" },
    controls: {
      matchers: {
        color: /(background|color)$/i,
        date: /Date$/,
      },
    },
  },
};

export default preview;

If additional styling changes are needed, create a Storybook stylesheet and import it into preview.ts:

/* .storybook/storybook.css */
html {
  height: 100% !important;
  background: #000000 !important;
  color: #ffffff !important;
}

html:not(.dark) > .sb-show-main {
  background: #ffffff !important;
  color: #000000 !important;
}

.dark > .sb-main-padded {
  padding: 0;
}

.dark > .sb-show-main > #storybook-root {
  padding: 1rem;
  background: #000000 !important;
  color: #ffffff;
}

.sb-show-main.sb-main-padded {
  height: 100% !important;
}

#storybook-root {
  height: 100%;
}

/* Docs are not configured for dark mode */
#storybook-docs {
  background: #ffffff;
  color: #000000;
}

Delete the src/stories folder containing example stories.

Create your own stories!

About

Instructions and template for creating a React component library


Languages

Language:TypeScript 51.2%Language:JavaScript 43.3%Language:CSS 5.5%