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
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
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"]
}
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'],
},
];
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"
},
}
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>;
}
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
- Update version in package.json
- Build the library:
npm run build
- Test the build:
npm pack
- 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
add your package in the dependencies section of the example package.json
"react-library-starter": "file:../"
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!
Top comments (0)