Files
stack/packages/mosaic/framework/skills/tsdown/references/recipe-react.md
T
fargo 1a822493ba format: apply repo prettier (3.8.1) to the folded skills tree
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.
2026-08-19 14:37:17 -05:00

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 React needed
  • 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

{
  "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

  1. Always externalize React - Don't bundle React/ReactDOM
  2. Use automatic JSX - Smaller bundles with React 17+
  3. Enable DTS generation - TypeScript support essential
  4. Use platform: 'neutral' - For maximum compatibility
  5. Add peer dependencies - Let users provide React
  6. Enable tree shaking - Reduce bundle size
  7. 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'];