Skip to main content

Command Palette

Search for a command to run...

Chronological guide: Building & Publishing a React Library

Updated
4 min read
Chronological guide: Building & Publishing a React Library

Phase 1: Project Setup

1.1 Initialize the Project

# Create project directory
mkdir my-react-library
cd my-react-library

# Initialize with pnpm
pnpm init

1.2 Install Dependencies

# Install React as peer dependencies (users will provide these)
pnpm add react react-dom --save-peer

# Install TypeScript and build tools
pnpm add -D typescript @types/react @types/react-dom tsup

# Install React types for development
pnpm add -D react react-dom

1.3 Create Basic File Structure

my-react-library/
├── src/
│   ├── index.ts
│   └── components/
│       └── HelloWorld.tsx
├── package.json
├── tsconfig.json
├── tsup.config.ts
└── README.md

Phase 2: Create the Component

2.1 Create HelloWorld Component

Create src/components/HelloWorld.tsx:

import React from "react";

interface HelloWorldProps {
  name?: string;
  className?: string;
}

export const HelloWorld: React.FC<HelloWorldProps> = ({
  name = "World",
  className = "",
}) => {
  return (
    <div className={`hello-world ${className}`}>
      <h1>Hello, {name}!</h1>
      <p>This is my first React library component.</p>
    </div>
  );
};

2.2 Create Main Export File

Create src/index.ts:

export { HelloWorld } from "./components/HelloWorld";
export type { HelloWorldProps } from "./components/HelloWorld";

Phase 3: Configuration Files

3.1 TypeScript Configuration

Create tsconfig.json:

{
  "compilerOptions": {
    "target": "ES2020",
    "lib": ["DOM", "DOM.Iterable", "ES6"],
    "allowJs": true,
    "skipLibCheck": true,
    "esModuleInterop": true,
    "allowSyntheticDefaultImports": true,
    "strict": true,
    "forceConsistentCasingInFileNames": true,
    "module": "ESNext",
    "moduleResolution": "node",
    "resolveJsonModule": true,
    "isolatedModules": true,
    "noEmit": true,
    "jsx": "react-jsx",
    "declaration": true,
    "outDir": "./dist"
  },
  "include": ["src/**/*"],
  "exclude": ["node_modules", "dist"]
}

3.2 Build Configuration

Create tsup.config.ts:

import { defineConfig } from "tsup";

export default defineConfig({
  entry: ["src/index.ts"],
  format: ["cjs", "esm"],
  dts: true,
  splitting: false,
  sourcemap: true,
  clean: true,
  external: ["react", "react-dom"],
});

3.3 Update package.json

{
  "name": "@yourscope/my-react-library",
  "version": "0.1.0",
  "description": "My first React library",
  "main": "./dist/index.cjs",
  "module": "./dist/index.js",
  "types": "./dist/index.d.ts",
  "exports": {
    ".": {
      "types": "./dist/index.d.ts",
      "import": "./dist/index.js",
      "require": "./dist/index.cjs",
      "default": "./dist/index.js"
    }
  },
  "files": ["dist"],
  "scripts": {
    "build": "tsup",
    "dev": "tsup --watch",
    "prepublishOnly": "pnpm build"
  },
  "keywords": ["react", "component", "library", "typescript"],
  "author": "Your Name",
  "license": "MIT",
  "repository": {
    "type": "git",
    "url": "https://github.com/yourusername/my-react-library"
  },
  "peerDependencies": {
    "react": ">=16.8.0",
    "react-dom": ">=16.8.0"
  },
  "devDependencies": {
    "@types/react": "^18.0.0",
    "@types/react-dom": "^18.0.0",
    "react": "^18.0.0",
    "react-dom": "^18.0.0",
    "tsup": "^8.0.0",
    "typescript": "^5.0.0"
  },
  "publishConfig": {
    "access": "public"
  }
}

Phase 4: Build and Test

4.1 Build the Library

# Build the library
pnpm build

# Check the output in dist/
ls -la dist/

You should see:

  • index.cjs (CommonJS)

  • index.js (ESM)

  • index.d.ts (TypeScript definitions)

  • Source maps

4.2 Test the Build

# Test if the package can be imported
node -e "console.log(require('./dist/index.cjs'))"

Phase 5: Create Documentation

5.1 Create README.md

Example readme

My React Library

A simple React component library.

Installation

npm install @yourscope/my-react-library
# or
pnpm add @yourscope/my-react-library

Usage

import { HelloWorld } from "@yourscope/my-react-library";

function App() {
  return (
    
); }

Components

HelloWorld

A simple greeting component.

Props

  • name?: string -> The name to greet (default: "World")
  • className?: string -> Additional CSS classes

License

MIT

Phase 6: Prepare for Publishing

6.1 Create .npmignore

src/
tsconfig.json
tsup.config.ts
*.log
node_modules/
.DS_Store

6.2 Verify Package Contents

# Check what will be published
pnpm pack --dry-run

# Or create a tarball to inspect
pnpm pack
tar -tzf *.tgz

Phase 7: Publishing

7.1 Set Up npm Account

# Login to npm
pnpm login

# Verify you're logged in
pnpm whoami

7.2 Publish First Version

# Make sure everything is built
pnpm build

# Publish to npm
pnpm publish

Phase 8: Version Updates

8.1 Making Changes

After making changes to your library:

# Update version (patch: 0.1.0 -> 0.1.1)
pnpm version patch

# Or minor version (0.1.0 -> 0.2.0)
pnpm version minor

# Or major version (0.1.0 -> 1.0.0)
pnpm version major

8.2 Publish Updates

# Build and publish
pnpm build
pnpm publish

Phase 9: Development Workflow

9.1 Development Scripts

Add to package.json scripts:

{
  "scripts": {
    "build": "tsup",
    "dev": "tsup --watch",
    "prepublishOnly": "pnpm build",
    "version": "pnpm build && git add dist/",
    "postversion": "git push && git push --tags"
  }
}

9.2 Testing Locally

To test your library in another project before publishing:

# In your library directory
pnpm link

# In your test project
pnpm link @yourscope/my-react-library

Quick Reference Commands

# Setup
pnpm init
pnpm add react react-dom --save-peer
pnpm add -D typescript @types/react @types/react-dom tsup

# Development
pnpm dev          # Watch mode
pnpm build        # Build library

# Publishing
pnpm version patch # Update version
pnpm publish      # Publish to npm

# Testing
pnpm link         # Link for local testing
pnpm pack --dry-run # Check package contents