Building a Modern React Library Starter: A Comprehensive Guide

abhirup99

Abhirup Pal

Posted on November 9, 2024

Building a Modern React Library Starter: A Comprehensive Guide

Introduction

Creating a modern React library requires careful consideration of build tools, development experience, and output optimization. This guide will walk you through building a professional React library starter using TypeScript, SWC, and Rollup—a powerful combination that offers superior performance, reliability, and developer experience.

Why These Tools Matter

TypeScript: Type Safety and Developer Experience

  • Static Type Checking: Catch errors during development rather than runtime

  • Enhanced IDE Support: Better autocomplete, refactoring, and code navigation

  • Self-Documenting Code: Types serve as living documentation

  • Improved Maintenance: Makes large codebases more manageable

  • Growing Community: Extensive type definitions for popular libraries

SWC: Next-Generation Compilation

  • Rust-Powered Performance: Up to 20x faster than Babel
  • Drop-in Replacement: Compatible with existing Babel configurations
  • Low Memory Footprint: More efficient resource utilization
  • Native TypeScript Support: Direct compilation without intermediate steps
  • Active Development: Regular updates and improvements

Rollup: Optimized Library Bundling

  • Tree Shaking: Advanced dead code elimination
  • Multiple Output Formats: ESM, CommonJS, and UMD support
  • Smaller Bundle Size: No unnecessary runtime code
  • Plugin Ecosystem: Rich set of official and community plugins
  • Code Splitting: Efficient chunk management

Project Setup Guide

1. Initialize Project Structure

mkdir react-library
cd react-library
npm init -y

# Create essential directories
mkdir src
Enter fullscreen mode Exit fullscreen mode

2. Install Dependencies

# Core dependencies
npm install react react-dom --save-peer

# Development dependencies
npm install --save-dev typescript @types/react @types/react-dom \
  @swc/core @swc/helpers \
  rollup @rollup/plugin-swc @rollup/plugin-node-resolve \
  @rollup/plugin-commonjs rollup-plugin-peer-deps-external
Enter fullscreen mode Exit fullscreen mode

3. TypeScript Configuration

Create tsconfig.json:

{
  "compilerOptions": {
    "target": "ES2018",
    "module": "ESNext",
    "lib": ["DOM", "DOM.Iterable", "ESNext"],
    "declaration": true,
    "declarationDir": "dist/types",
    "emitDeclarationOnly": true,
    "jsx": "react-jsx",
    "strict": true,
    "moduleResolution": "node",
    "allowSyntheticDefaultImports": true,
    "esModuleInterop": true,
    "skipLibCheck": true,
    "forceConsistentCasingInFileNames": true,
    "resolveJsonModule": true,
    "isolatedModules": true,
    "noUnusedLocals": true,
    "noUnusedParameters": true,
    "noImplicitReturns": true,
    "noFallthroughCasesInSwitch": true
  },
  "include": ["src"],
  "exclude": ["node_modules", "dist"]
}
Enter fullscreen mode Exit fullscreen mode

4. Rollup Configuration

Create rollup.config.js:

import resolve from '@rollup/plugin-node-resolve';
import commonjs from '@rollup/plugin-commonjs';
import { swc, defineRollupSwcOption } from '@rollup/plugin-swc';
import peerDepsExternal from 'rollup-plugin-peer-deps-external';
import terser from '@rollup/plugin-terser';

const packageJson = require('./package.json');

const swcConfig = defineRollupSwcOption({
  jsc: {
    parser: {
      syntax: 'typescript',
      tsx: true,
    },
    transform: {
      react: {
        runtime: 'automatic',
        development: false,
        refresh: false,
      },
    },
    target: 'es2018',
  },
  minify: false,
});

export default [
  // ESM build
  {
    input: 'src/index.tsx',
    output: [
      {
        file: packageJson.module,
        format: 'esm',
        sourcemap: true,
      },
    ],
    plugins: [
      peerDepsExternal(),
      resolve({
        extensions: ['.ts', '.tsx', '.js', '.jsx'],
      }),
      commonjs(),
      swc(swcConfig),
      terser(),
    ],
    external: ['react', 'react-dom'],
  },
  // CommonJS build
  {
    input: 'src/index.tsx',
    output: [
      {
        file: packageJson.main,
        format: 'cjs',
        sourcemap: true,
        exports: 'auto',
      },
    ],
    plugins: [
      peerDepsExternal(),
      resolve({
        extensions: ['.ts', '.tsx', '.js', '.jsx'],
      }),
      commonjs(),
      swc(swcConfig),
      terser(),
    ],
    external: ['react', 'react-dom'],
  },
];
Enter fullscreen mode Exit fullscreen mode

5. Package.json Configuration

Update your package.json:

{
  "name": "your-library-name",
  "version": "1.0.0",
  "main": "dist/cjs/index.js",
  "module": "dist/esm/index.js",
  "types": "dist/types/index.d.ts",
  "files": [
    "dist"
  ],
  "sideEffects": false,
  "scripts": {
    "build": "rollup -c",
    "types": "tsc",
    "prepare": "npm run types && npm run build",
    "lint": "eslint ."
  },
  "peerDependencies": {
    "react": ">=17.0.0 <19.0.0",
    "react-dom": ">=17.0.0 <19.0.0"
  },
}
Enter fullscreen mode Exit fullscreen mode

Writing Library Code

Component Example

Create src/index.tsx:

import React from "react";

export interface HelloProps {
  name: string;
}

export default function Hello({ name }: HelloProps) {
  return <div>Hello {name}!</div>;
}
Enter fullscreen mode Exit fullscreen mode

Best Practices

1. Development Workflow

  • Use Git hooks (husky) for pre-commit linting and testing
  • Implement semantic versioning
  • Set up continuous integration/deployment

2. Documentation

  • Include detailed README.md
  • Provide usage examples
  • Document peer dependencies

3. Performance

  • Keep bundle size minimal
  • Implement tree-shaking friendly exports
  • Avoid runtime dependencies when possible

Publishing

  1. Update version in package.json
  2. Build the library: npm run build
  3. Test the build: npm pack
  4. Publish: npm publish

Add working example

Setup a vite app for providing example, and testing code changes in the repo itself. This can also be done with a storybook.

npm create vite@latest example -- --template react-ts
Enter fullscreen mode Exit fullscreen mode

add your package in the dependencies section of the example package.json

"react-library-starter": "file:../"
Enter fullscreen mode Exit fullscreen mode

Import your component and test it in the example project.

Your React library is now ready for publishing! 🎉

If you’d like to dive in with a ready-to-use setup, check out the complete starter template here: https://github.com/Abhirup-99/react-library-starter-template. This template includes everything we’ve covered and is designed to help you kickstart your React library development with minimal setup.

Happy coding!

💖 💪 🙅 🚩
abhirup99
Abhirup Pal

Posted on November 9, 2024

Join Our Newsletter. No Spam, Only the good stuff.

Sign up to receive the latest update from our blog.

Related