963 markdown files reformatted with the repository's pinned prettier so pnpm format:check covers the folded tree like every other repo file. The formatter's embedded-language pass also normalized code fences (TS semicolons, closed HTML tags in examples, lowercased CSS hex colors, one renumbered list that skipped an index). Alphanumeric token deltas vs the fold commit were audited file-by-file; all are formatter-equivalent markup normalizations plus the four sanitized skills.
5.7 KiB
5.7 KiB
React Support
Build React component libraries with tsdown.
Overview
tsdown provides first-class support for React libraries. Rolldown natively supports JSX/TSX, so no additional plugins are required for basic React components.
Quick Start
Use Starter Template
# Basic React library
npx create-tsdown@latest -t react
# With React Compiler
npx create-tsdown@latest -t react-compiler
Basic Configuration
Minimal Setup
// tsdown.config.ts
export default defineConfig({
entry: ['./src/index.ts'],
format: ['esm', 'cjs'],
platform: 'neutral',
external: ['react', 'react-dom'],
dts: true,
});
Component Example
// src/MyButton.tsx
import React from 'react';
interface MyButtonProps {
type?: 'primary' | 'secondary';
onClick?: () => void;
}
export const MyButton: React.FC<MyButtonProps> = ({ type = 'primary', onClick }) => {
return (
<button className={`btn btn-${type}`} onClick={onClick}>
Click me
</button>
);
};
// src/index.ts
export { MyButton } from './MyButton';
JSX Transform
Automatic (Default)
Modern JSX transform (React 17+):
export default defineConfig({
entry: ['src/index.tsx'],
// Automatic JSX is default
});
Characteristics:
- No
import Reactneeded - Smaller bundle size
- React 17+ required
Classic
Legacy JSX transform:
export default defineConfig({
entry: ['src/index.tsx'],
inputOptions: {
transform: {
jsx: 'react', // Classic transform
},
},
});
Characteristics:
- Requires
import React from 'react' - Compatible with older React versions
React Compiler
React Compiler automatically optimizes React code at build time.
Install Dependencies
pnpm add -D @rollup/plugin-babel babel-plugin-react-compiler
Configure
import pluginBabel from '@rollup/plugin-babel';
export default defineConfig({
entry: ['src/index.tsx'],
format: ['esm', 'cjs'],
external: ['react', 'react-dom'],
plugins: [
pluginBabel({
babelHelpers: 'bundled',
parserOpts: {
sourceType: 'module',
plugins: ['jsx', 'typescript'],
},
plugins: ['babel-plugin-react-compiler'],
extensions: ['.js', '.jsx', '.ts', '.tsx'],
}),
],
dts: true,
});
Common Patterns
Component Library
export default defineConfig({
entry: ['src/index.ts'],
format: ['esm', 'cjs'],
platform: 'neutral',
external: [
'react',
'react-dom',
/^react\//, // react/jsx-runtime, etc.
],
dts: true,
clean: true,
});
Multiple Components
export default defineConfig({
entry: {
index: 'src/index.ts',
Button: 'src/Button.tsx',
Input: 'src/Input.tsx',
Modal: 'src/Modal.tsx',
},
format: ['esm', 'cjs'],
external: ['react', 'react-dom'],
dts: true,
});
Hooks Library
export default defineConfig({
entry: ['src/index.ts'],
format: ['esm', 'cjs'],
platform: 'neutral',
external: ['react'], // Only React needed
dts: true,
treeshake: true,
});
Monorepo React Packages
export default defineConfig({
workspace: 'packages/*',
entry: ['src/index.ts'],
format: ['esm', 'cjs'],
external: [
'react',
'react-dom',
/^@mycompany\//, // Other workspace packages
],
dts: true,
});
TypeScript Configuration
Recommended tsconfig.json
{
"compilerOptions": {
"target": "ES2020",
"module": "ESNext",
"lib": ["ES2020", "DOM", "DOM.Iterable"],
"jsx": "react-jsx", // or "react" for classic
"moduleResolution": "bundler",
"allowImportingTsExtensions": true,
"strict": true,
"isolatedDeclarations": true, // Fast DTS generation
"skipLibCheck": true
},
"include": ["src"]
}
Package.json Configuration
{
"name": "my-react-library",
"version": "1.0.0",
"type": "module",
"main": "./dist/index.cjs",
"module": "./dist/index.mjs",
"types": "./dist/index.d.ts",
"exports": {
".": {
"types": "./dist/index.d.ts",
"import": "./dist/index.mjs",
"require": "./dist/index.cjs"
}
},
"files": ["dist"],
"peerDependencies": {
"react": "^18.0.0",
"react-dom": "^18.0.0"
},
"devDependencies": {
"@types/react": "^18.0.0",
"@types/react-dom": "^18.0.0",
"react": "^18.0.0",
"react-dom": "^18.0.0",
"tsdown": "^0.9.0",
"typescript": "^5.0.0"
}
}
Advanced Patterns
With Fast Refresh (Development)
import react from '@vitejs/plugin-react';
export default defineConfig((options) => ({
entry: ['src/index.ts'],
format: ['esm'],
external: ['react', 'react-dom'],
plugins: options.watch
? [
// @ts-expect-error Vite plugin
react({ fastRefresh: true }),
]
: [],
}));
Tips
- Always externalize React - Don't bundle React/ReactDOM
- Use automatic JSX - Smaller bundles with React 17+
- Enable DTS generation - TypeScript support essential
- Use platform: 'neutral' - For maximum compatibility
- Add peer dependencies - Let users provide React
- Enable tree shaking - Reduce bundle size
- Use React Compiler - Better runtime performance
Troubleshooting
React Hook Errors
Ensure React is externalized:
external: ['react', 'react-dom', /^react\//];
Type Errors with JSX
Check tsconfig.json:
{
"compilerOptions": {
"jsx": "react-jsx" // or "react"
}
}
Duplicate React
Add to external patterns:
external: ['react', 'react-dom', 'react/jsx-runtime', 'react/jsx-dev-runtime'];
Related
- Plugins - Extend functionality
- Dependencies - External packages
- DTS - Type declarations
- Vue Recipe - Vue component libraries