feat: Complete fleet — 94 skills across 10+ domains

Pulled ALL skills from 15 source repositories:
- anthropics/skills: 16 (docs, design, MCP, testing)
- obra/superpowers: 14 (TDD, debugging, agents, planning)
- coreyhaines31/marketingskills: 25 (marketing, CRO, SEO, growth)
- better-auth/skills: 5 (auth patterns)
- vercel-labs/agent-skills: 5 (React, design, Vercel)
- antfu/skills: 16 (Vue, Vite, Vitest, pnpm, Turborepo)
- Plus 13 individual skills from various repos

Mosaic Stack is not limited to coding — the Orchestrator and
subagents serve coding, business, design, marketing, writing,
logistics, analysis, and more.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
Jason Woltje
2026-02-16 16:27:42 -06:00
parent 861b28b965
commit f5792c40be
1262 changed files with 212048 additions and 61 deletions

View File

@@ -0,0 +1,139 @@
# tsdown Skill References
This directory contains detailed reference documentation for the tsdown skill.
## Created Files (31 total)
### Core Guides (2)
-`guide-getting-started.md` - Installation, first bundle, CLI basics
-`guide-migrate-from-tsup.md` - Migration guide from tsup
### Configuration Options (20)
-`option-config-file.md` - Config file formats, loaders, workspace
-`option-entry.md` - Entry point configuration with globs
-`option-output-format.md` - Output formats (ESM, CJS, IIFE, UMD)
-`option-output-directory.md` - Output directory and extensions
-`option-dts.md` - TypeScript declaration generation
-`option-target.md` - Target environment (ES2020, ESNext, etc.)
-`option-platform.md` - Platform (node, browser, neutral)
-`option-dependencies.md` - External and inline dependencies
-`option-sourcemap.md` - Source map generation
-`option-minification.md` - Minification (`boolean | 'dce-only' | MinifyOptions`)
-`option-tree-shaking.md` - Tree shaking configuration
-`option-cleaning.md` - Output directory cleaning
-`option-watch-mode.md` - Watch mode configuration
-`option-shims.md` - ESM/CJS compatibility shims
-`option-package-exports.md` - Auto-generate package.json exports
-`option-css.md` - CSS handling (experimental, stub only)
-`option-unbundle.md` - Preserve directory structure
-`option-cjs-default.md` - CommonJS default export handling
-`option-log-level.md` - Logging configuration
-`option-lint.md` - Package validation (publint & attw)
### Advanced Topics (5)
-`advanced-plugins.md` - Rolldown, Rollup, Unplugin support
-`advanced-hooks.md` - Lifecycle hooks system
-`advanced-programmatic.md` - Node.js API usage
-`advanced-rolldown-options.md` - Pass options to Rolldown
-`advanced-ci.md` - CI environment detection and CI-aware options
### Framework Recipes (3)
-`recipe-react.md` - React library setup with JSX
-`recipe-vue.md` - Vue library setup with SFC
-`recipe-wasm.md` - WASM module support
### Reference (1)
-`reference-cli.md` - Complete CLI command reference
## Coverage Status
**Created:** 31 files (97% complete)
**Remaining:** 3 files (low priority, not referenced from SKILL.md)
### Remaining Files (Lower Priority)
These files can be added as needed:
1. **`guide-introduction.md`** - Covered in main SKILL.md
2. **`guide-faq.md`** - FAQ (stub mode, etc.)
3. **`advanced-benchmark.md`** - Performance data
## Current Skill Features
The tsdown skill now includes comprehensive coverage of:
### ✅ Core Functionality
- Getting started and installation
- Entry points and glob patterns
- Output formats (ESM, CJS, IIFE, UMD)
- TypeScript declarations
- Configuration file setup
- CLI reference
### ✅ Build Options
- Target environment configuration
- Platform selection
- Dependency management
- Source maps
- Minification
- Tree shaking
- Output cleaning
- Watch mode
### ✅ Advanced Features
- Plugins (Rolldown, Rollup, Unplugin)
- Lifecycle hooks
- ESM/CJS shims
- Package exports generation
- Package validation (publint, attw)
- Programmatic API (Node.js)
- Output directory customization
- CSS handling and modules
- Unbundle mode
- CI environment detection and CI-aware options
### ✅ Framework & Runtime Support
- React with JSX/TSX
- React Compiler integration
- Vue with SFC support
- Vue type generation (vue-tsc)
- WASM module bundling (rolldown-plugin-wasm)
### ✅ Migration
- Complete migration guide from tsup
- Compatibility notes
## Usage
The skill is now ready for use with comprehensive coverage of core features. Additional files can be added incrementally as needed.
## File Naming Convention
Files are prefixed by category:
- `guide-*` - Getting started guides and tutorials
- `option-*` - Configuration options
- `advanced-*` - Advanced topics (plugins, hooks, programmatic API)
- `recipe-*` - Framework-specific recipes
- `reference-*` - CLI and API reference
## Creating New Reference Files
When creating new reference files:
1. **Read source documentation** from `/docs` directory
2. **Simplify for AI consumption** - concise, actionable content
3. **Include code examples** - practical, copy-paste ready
4. **Add cross-references** - link to related options
5. **Follow naming convention** - use appropriate prefix
6. **Keep it focused** - one topic per file
## Updating Existing Files
When documentation changes:
1. Check git diff: `git diff <sha>..HEAD -- docs/`
2. Update affected reference files
3. Update SKILL.md if needed
4. Update GENERATION.md with new SHA
See `skills/GENERATION.md` for detailed update instructions.

View File

@@ -0,0 +1,89 @@
# CI Environment Support
Automatically detect CI environments and toggle features based on local vs CI builds.
## Overview
tsdown uses the [`is-in-ci`](https://www.npmjs.com/package/is-in-ci) package to detect CI environments. This covers GitHub Actions, GitLab CI, Jenkins, CircleCI, Travis CI, and more.
## CI-Aware Values
Several options accept CI-aware string values:
| Value | Behavior |
|-------|----------|
| `true` | Always enabled |
| `false` | Always disabled |
| `'ci-only'` | Enabled only in CI, disabled locally |
| `'local-only'` | Enabled only locally, disabled in CI |
## Supported Options
These options accept CI-aware values:
- `dts` - TypeScript declaration file generation
- `publint` - Package lint validation
- `attw` - "Are the types wrong" validation
- `report` - Bundle size reporting
- `exports` - Auto-generate `package.json` exports
- `unused` - Unused dependency check
- `devtools` - DevTools integration
- `failOnWarn` - Fail on warnings (defaults to `'ci-only'`)
## Usage
### String Form
```ts
export default defineConfig({
dts: 'local-only', // Skip DTS in CI for faster builds
publint: 'ci-only', // Only run publint in CI
failOnWarn: 'ci-only', // Fail on warnings in CI only (default)
})
```
### Object Form
When an option takes a configuration object, set `enabled` to a CI-aware value:
```ts
export default defineConfig({
publint: {
enabled: 'ci-only',
level: 'error',
},
attw: {
enabled: 'ci-only',
profile: 'node16',
},
})
```
### Config Function
The config function receives a `ci` boolean in its context:
```ts
export default defineConfig((_, { ci }) => ({
minify: ci,
sourcemap: !ci,
}))
```
## Typical CI Configuration
```ts
export default defineConfig({
entry: 'src/index.ts',
format: ['esm', 'cjs'],
dts: true,
failOnWarn: 'ci-only',
publint: 'ci-only',
attw: 'ci-only',
})
```
## Related Options
- [Package Validation](option-lint.md) - publint and attw configuration
- [Log Level](option-log-level.md) - `failOnWarn` option details

View File

@@ -0,0 +1,363 @@
# Lifecycle Hooks
Extend the build process with lifecycle hooks.
## Overview
Hooks provide a way to inject custom logic at specific stages of the build lifecycle. Inspired by [unbuild](https://github.com/unjs/unbuild).
**Recommendation:** Use [plugins](advanced-plugins.md) for most extensions. Use hooks for simple custom tasks or Rolldown plugin injection.
## Usage Patterns
### Object Syntax
```ts
export default defineConfig({
entry: ['src/index.ts'],
hooks: {
'build:prepare': async (context) => {
console.log('Build starting...')
},
'build:done': async (context) => {
console.log('Build complete!')
},
},
})
```
### Function Syntax
```ts
export default defineConfig({
entry: ['src/index.ts'],
hooks(hooks) {
hooks.hook('build:prepare', () => {
console.log('Preparing build...')
})
hooks.hook('build:before', (context) => {
console.log(`Building format: ${context.format}`)
})
},
})
```
## Available Hooks
### `build:prepare`
Called before the build process starts.
**When:** Once per build session
**Context:**
```ts
{
options: ResolvedConfig,
hooks: Hookable
}
```
**Use cases:**
- Setup tasks
- Validation
- Environment preparation
**Example:**
```ts
hooks: {
'build:prepare': async (context) => {
console.log('Starting build for:', context.options.entry)
await cleanOldFiles()
},
}
```
### `build:before`
Called before each Rolldown build.
**When:** Once per format (ESM, CJS, etc.)
**Context:**
```ts
{
options: ResolvedConfig,
buildOptions: BuildOptions,
hooks: Hookable
}
```
**Use cases:**
- Modify build options per format
- Inject plugins dynamically
- Format-specific setup
**Example:**
```ts
hooks: {
'build:before': async (context) => {
console.log(`Building ${context.buildOptions.format} format...`)
// Add format-specific plugin
if (context.buildOptions.format === 'iife') {
context.buildOptions.plugins.push(browserPlugin())
}
},
}
```
### `build:done`
Called after the build completes.
**When:** Once per build session
**Context:**
```ts
{
options: ResolvedConfig,
chunks: RolldownChunk[],
hooks: Hookable
}
```
**Use cases:**
- Post-processing
- Asset copying
- Notifications
- Deployment
**Example:**
```ts
hooks: {
'build:done': async (context) => {
console.log(`Built ${context.chunks.length} chunks`)
// Copy additional files
await copyAssets()
// Send notification
notifyBuildComplete()
},
}
```
## Common Patterns
### Build Notifications
```ts
export default defineConfig({
hooks: {
'build:prepare': () => {
console.log('🚀 Starting build...')
},
'build:done': (context) => {
const size = context.chunks.reduce((sum, c) => sum + c.code.length, 0)
console.log(`✅ Build complete! Total size: ${size} bytes`)
},
},
})
```
### Conditional Plugin Injection
```ts
export default defineConfig({
hooks(hooks) {
hooks.hook('build:before', (context) => {
// Add minification only for production
if (process.env.NODE_ENV === 'production') {
context.buildOptions.plugins.push(minifyPlugin())
}
})
},
})
```
### Custom File Copy
```ts
import { copyFile } from 'fs/promises'
export default defineConfig({
hooks: {
'build:done': async (context) => {
// Copy README to dist
await copyFile('README.md', `${context.options.outDir}/README.md`)
},
},
})
```
### Build Metrics
```ts
export default defineConfig({
hooks: {
'build:prepare': (context) => {
context.startTime = Date.now()
},
'build:done': (context) => {
const duration = Date.now() - context.startTime
console.log(`Build took ${duration}ms`)
// Log chunk sizes
context.chunks.forEach((chunk) => {
console.log(`${chunk.fileName}: ${chunk.code.length} bytes`)
})
},
},
})
```
### Format-Specific Logic
```ts
export default defineConfig({
format: ['esm', 'cjs', 'iife'],
hooks: {
'build:before': (context) => {
const format = context.buildOptions.format
if (format === 'iife') {
// Browser-specific setup
context.buildOptions.globalName = 'MyLib'
} else if (format === 'cjs') {
// Node-specific setup
context.buildOptions.platform = 'node'
}
},
},
})
```
### Deployment Hook
```ts
export default defineConfig({
hooks: {
'build:done': async (context) => {
if (process.env.DEPLOY === 'true') {
console.log('Deploying to CDN...')
await deployToCDN(context.options.outDir)
}
},
},
})
```
## Advanced Usage
### Multiple Hooks
```ts
export default defineConfig({
hooks(hooks) {
// Register multiple hooks
hooks.hook('build:prepare', setupEnvironment)
hooks.hook('build:prepare', validateConfig)
hooks.hook('build:before', injectPlugins)
hooks.hook('build:before', logFormat)
hooks.hook('build:done', generateManifest)
hooks.hook('build:done', notifyComplete)
},
})
```
### Async Hooks
```ts
export default defineConfig({
hooks: {
'build:prepare': async (context) => {
await fetchRemoteConfig()
await initializeDatabase()
},
'build:done': async (context) => {
await uploadToS3(context.chunks)
await invalidateCDN()
},
},
})
```
### Error Handling
```ts
export default defineConfig({
hooks: {
'build:done': async (context) => {
try {
await riskyOperation()
} catch (error) {
console.error('Hook failed:', error)
// Don't throw - allow build to complete
}
},
},
})
```
## Hookable API
tsdown uses [hookable](https://github.com/unjs/hookable) for hooks. Additional methods:
```ts
export default defineConfig({
hooks(hooks) {
// Register hook
hooks.hook('build:done', handler)
// Register hook once
hooks.hookOnce('build:prepare', handler)
// Remove hook
hooks.removeHook('build:done', handler)
// Clear all hooks for event
hooks.removeHooks('build:done')
// Call hooks manually
await hooks.callHook('build:done', context)
},
})
```
## Tips
1. **Use plugins** for most extensions
2. **Hooks for simple tasks** like notifications or file copying
3. **Async hooks supported** for I/O operations
4. **Don't throw errors** unless you want to fail the build
5. **Context is mutable** in `build:before` for advanced use cases
6. **Multiple hooks allowed** for the same event
## Troubleshooting
### Hook Not Called
- Verify hook name is correct
- Check hook is registered in config
- Ensure async hooks are awaited
### Build Fails in Hook
- Add try/catch for error handling
- Don't throw unless intentional
- Log errors for debugging
### Context Undefined
- Check which hook you're using
- Verify context properties available for that hook
## Related
- [Plugins](advanced-plugins.md) - Plugin system
- [Rolldown Options](advanced-rolldown-options.md) - Build options
- [Watch Mode](option-watch-mode.md) - Development workflow

View File

@@ -0,0 +1,381 @@
# Plugins
Extend tsdown with plugins from multiple ecosystems.
## Overview
tsdown, built on Rolldown, supports plugins from multiple ecosystems to extend and customize the bundling process.
## Supported Ecosystems
### 1. Rolldown Plugins
Native plugins designed for Rolldown:
```ts
import RolldownPlugin from 'rolldown-plugin-something'
export default defineConfig({
plugins: [RolldownPlugin()],
})
```
**Compatibility:** ✅ Full support
### 2. Unplugin
Universal plugins that work across bundlers:
```ts
import UnpluginPlugin from 'unplugin-something'
export default defineConfig({
plugins: [UnpluginPlugin.rolldown()],
})
```
**Compatibility:** ✅ Most unplugin-* plugins work
**Examples:**
- `unplugin-vue-components`
- `unplugin-auto-import`
- `unplugin-icons`
### 3. Rollup Plugins
Most Rollup plugins work with tsdown:
```ts
import RollupPlugin from '@rollup/plugin-something'
export default defineConfig({
plugins: [RollupPlugin()],
})
```
**Compatibility:** ✅ High compatibility
**Type Issues:** May cause TypeScript errors - use type casting:
```ts
import RollupPlugin from 'rollup-plugin-something'
export default defineConfig({
plugins: [
// @ts-expect-error Rollup plugin type mismatch
RollupPlugin(),
// Or cast to any
RollupPlugin() as any,
],
})
```
### 4. Vite Plugins
Some Vite plugins may work:
```ts
import VitePlugin from 'vite-plugin-something'
export default defineConfig({
plugins: [
// @ts-expect-error Vite plugin type mismatch
VitePlugin(),
],
})
```
**Compatibility:** ⚠️ Limited - only if not using Vite-specific APIs
**Note:** Improved support planned for future releases.
## Usage
### Basic Plugin Usage
```ts
import { defineConfig } from 'tsdown'
import SomePlugin from 'some-plugin'
export default defineConfig({
entry: ['src/index.ts'],
plugins: [SomePlugin()],
})
```
### Multiple Plugins
```ts
import PluginA from 'plugin-a'
import PluginB from 'plugin-b'
import PluginC from 'plugin-c'
export default defineConfig({
entry: ['src/index.ts'],
plugins: [
PluginA(),
PluginB({ option: true }),
PluginC(),
],
})
```
### Conditional Plugins
```ts
export default defineConfig((options) => ({
entry: ['src/index.ts'],
plugins: [
SomePlugin(),
options.watch && DevPlugin(),
!options.watch && ProdPlugin(),
].filter(Boolean),
}))
```
## Common Plugin Patterns
### JSON Import
```ts
import json from '@rollup/plugin-json'
export default defineConfig({
plugins: [json()],
})
```
### Node Resolve
```ts
import { nodeResolve } from '@rollup/plugin-node-resolve'
export default defineConfig({
plugins: [nodeResolve()],
})
```
### CommonJS
```ts
import commonjs from '@rollup/plugin-commonjs'
export default defineConfig({
plugins: [commonjs()],
})
```
### Replace
```ts
import replace from '@rollup/plugin-replace'
export default defineConfig({
plugins: [
replace({
'process.env.NODE_ENV': JSON.stringify('production'),
__VERSION__: JSON.stringify('1.0.0'),
}),
],
})
```
### Auto Import
```ts
import AutoImport from 'unplugin-auto-import/rolldown'
export default defineConfig({
plugins: [
AutoImport({
imports: ['vue', 'vue-router'],
dts: 'src/auto-imports.d.ts',
}),
],
})
```
### Vue Components
```ts
import Components from 'unplugin-vue-components/rolldown'
export default defineConfig({
plugins: [
Components({
dts: 'src/components.d.ts',
}),
],
})
```
## Framework-Specific Plugins
### React
```ts
import react from '@vitejs/plugin-react'
export default defineConfig({
entry: ['src/index.tsx'],
plugins: [
// @ts-expect-error Vite plugin
react(),
],
})
```
### Vue
```ts
import vue from '@vitejs/plugin-vue'
export default defineConfig({
entry: ['src/index.ts'],
plugins: [
// @ts-expect-error Vite plugin
vue(),
],
})
```
### Solid
```ts
import solid from 'vite-plugin-solid'
export default defineConfig({
entry: ['src/index.tsx'],
plugins: [
// @ts-expect-error Vite plugin
solid(),
],
})
```
### Svelte
```ts
import { svelte } from '@sveltejs/vite-plugin-svelte'
export default defineConfig({
entry: ['src/index.ts'],
plugins: [
// @ts-expect-error Vite plugin
svelte(),
],
})
```
## Writing Custom Plugins
Follow Rolldown's plugin development guide:
### Basic Plugin Structure
```ts
import type { Plugin } from 'rolldown'
function myPlugin(): Plugin {
return {
name: 'my-plugin',
// Transform hook
transform(code, id) {
if (id.endsWith('.custom')) {
return {
code: transformCode(code),
map: null,
}
}
},
// Other hooks...
}
}
```
### Using Custom Plugin
```ts
import { myPlugin } from './my-plugin'
export default defineConfig({
plugins: [myPlugin()],
})
```
## Plugin Configuration
### Plugin-Specific Options
Refer to each plugin's documentation for configuration options.
### Plugin Order
Plugins run in the order they're defined:
```ts
export default defineConfig({
plugins: [
PluginA(), // Runs first
PluginB(), // Runs second
PluginC(), // Runs last
],
})
```
## Troubleshooting
### Type Errors with Rollup/Vite Plugins
Use type casting:
```ts
plugins: [
// Option 1: @ts-expect-error
// @ts-expect-error Plugin type mismatch
SomePlugin(),
// Option 2: as any
SomePlugin() as any,
]
```
### Plugin Not Working
1. **Check compatibility** - Verify plugin supports your bundler
2. **Read documentation** - Follow plugin's setup instructions
3. **Check plugin order** - Some plugins depend on execution order
4. **Enable debug mode** - Use `--debug` flag
### Vite Plugin Fails
Vite plugins may rely on Vite-specific APIs:
1. **Find Rollup equivalent** - Look for Rollup version of plugin
2. **Use Unplugin version** - Check for `unplugin-*` alternative
3. **Wait for support** - Vite plugin support improving
## Resources
- [Rolldown Plugin Development](https://rolldown.rs/guide/plugin-development)
- [Unplugin Documentation](https://unplugin.unjs.io/)
- [Rollup Plugins](https://github.com/rollup/plugins)
- [Vite Plugins](https://vitejs.dev/plugins/)
## Tips
1. **Prefer Rolldown plugins** for best compatibility
2. **Use Unplugin** for cross-bundler support
3. **Cast types** for Rollup/Vite plugins
4. **Test thoroughly** when using cross-ecosystem plugins
5. **Check plugin docs** for specific configuration
6. **Write custom plugins** for unique needs
## Related
- [Hooks](advanced-hooks.md) - Lifecycle hooks
- [Rolldown Options](advanced-rolldown-options.md) - Advanced Rolldown config
- [React Recipe](recipe-react.md) - React setup with plugins
- [Vue Recipe](recipe-vue.md) - Vue setup with plugins

View File

@@ -0,0 +1,376 @@
# Programmatic Usage
Use tsdown from JavaScript/TypeScript code.
## Overview
tsdown can be imported and used programmatically in your Node.js scripts, custom build tools, or automation workflows.
## Basic Usage
### Simple Build
```ts
import { build } from 'tsdown'
await build({
entry: ['src/index.ts'],
format: ['esm', 'cjs'],
dts: true,
})
```
### With Options
```ts
import { build } from 'tsdown'
await build({
entry: ['src/index.ts'],
format: ['esm', 'cjs'],
outDir: 'dist',
dts: true,
minify: true,
sourcemap: true,
clean: true,
})
```
## API Reference
### build()
Main function to run a build.
```ts
import { build } from 'tsdown'
await build(options)
```
**Parameters:**
- `options` - Build configuration object (same as config file)
**Returns:**
- `Promise<void>` - Resolves when build completes
**Throws:**
- Build errors if compilation fails
## Configuration Object
All config file options are available:
```ts
import { build, defineConfig } from 'tsdown'
const config = defineConfig({
entry: ['src/index.ts'],
format: ['esm', 'cjs'],
dts: true,
minify: true,
sourcemap: true,
external: ['react', 'react-dom'],
plugins: [/* plugins */],
hooks: {
'build:done': async () => {
console.log('Build complete!')
},
},
})
await build(config)
```
See [Config Reference](option-config-file.md) for all options.
## Common Patterns
### Custom Build Script
```ts
// scripts/build.ts
import { build } from 'tsdown'
async function main() {
console.log('Building library...')
await build({
entry: ['src/index.ts'],
format: ['esm', 'cjs'],
dts: true,
clean: true,
})
console.log('Build complete!')
}
main().catch(console.error)
```
Run with:
```bash
tsx scripts/build.ts
```
### Multiple Builds
```ts
import { build } from 'tsdown'
// Build main library
await build({
entry: ['src/index.ts'],
format: ['esm', 'cjs'],
outDir: 'dist',
dts: true,
})
// Build CLI tool
await build({
entry: ['src/cli.ts'],
format: ['esm'],
outDir: 'dist/bin',
platform: 'node',
shims: true,
})
```
### Conditional Build
```ts
import { build } from 'tsdown'
const isDev = process.env.NODE_ENV === 'development'
await build({
entry: ['src/index.ts'],
format: ['esm', 'cjs'],
minify: !isDev,
sourcemap: isDev,
clean: !isDev,
})
```
### With Error Handling
```ts
import { build } from 'tsdown'
try {
await build({
entry: ['src/index.ts'],
format: ['esm', 'cjs'],
dts: true,
})
console.log('✅ Build successful')
} catch (error) {
console.error('❌ Build failed:', error)
process.exit(1)
}
```
### Automated Workflow
```ts
import { build } from 'tsdown'
import { execSync } from 'child_process'
async function release() {
// Clean
console.log('Cleaning...')
execSync('rm -rf dist')
// Build
console.log('Building...')
await build({
entry: ['src/index.ts'],
format: ['esm', 'cjs'],
dts: true,
minify: true,
})
// Test
console.log('Testing...')
execSync('npm test')
// Publish
console.log('Publishing...')
execSync('npm publish')
}
release().catch(console.error)
```
### Build with Post-Processing
```ts
import { build } from 'tsdown'
import { copyFileSync } from 'fs'
await build({
entry: ['src/index.ts'],
format: ['esm', 'cjs'],
dts: true,
hooks: {
'build:done': async () => {
// Copy additional files
copyFileSync('README.md', 'dist/README.md')
copyFileSync('LICENSE', 'dist/LICENSE')
console.log('Copied additional files')
},
},
})
```
## Watch Mode
Unfortunately, watch mode is not directly exposed in the programmatic API. Use the CLI for watch mode:
```ts
// Use CLI for watch mode
import { spawn } from 'child_process'
spawn('tsdown', ['--watch'], {
stdio: 'inherit',
shell: true,
})
```
## Integration Examples
### With Task Runner
```ts
// gulpfile.js
import { build } from 'tsdown'
import gulp from 'gulp'
gulp.task('build', async () => {
await build({
entry: ['src/index.ts'],
format: ['esm', 'cjs'],
dts: true,
})
})
gulp.task('watch', () => {
return gulp.watch('src/**/*.ts', gulp.series('build'))
})
```
### With Custom CLI
```ts
// scripts/cli.ts
import { build } from 'tsdown'
import { Command } from 'commander'
const program = new Command()
program
.command('build')
.option('--prod', 'Production build')
.action(async (options) => {
await build({
entry: ['src/index.ts'],
format: ['esm', 'cjs'],
minify: options.prod,
sourcemap: !options.prod,
})
})
program.parse()
```
### With CI/CD
```ts
// .github/scripts/build.ts
import { build } from 'tsdown'
const isCI = process.env.CI === 'true'
await build({
entry: ['src/index.ts'],
format: ['esm', 'cjs'],
dts: true,
minify: isCI,
clean: true,
})
// Upload to artifact storage
if (isCI) {
// Upload dist/ to S3, etc.
}
```
## TypeScript Support
```ts
// scripts/build.ts
import { build, type UserConfig } from 'tsdown'
const config: UserConfig = {
entry: ['src/index.ts'],
format: ['esm', 'cjs'],
dts: true,
}
await build(config)
```
## Tips
1. **Use TypeScript** for type safety
2. **Handle errors** properly
3. **Use hooks** for custom logic
4. **Log progress** for visibility
5. **Use CLI for watch** mode
6. **Exit on error** in scripts
## Troubleshooting
### Import Errors
Ensure tsdown is installed:
```bash
pnpm add -D tsdown
```
### Type Errors
Import types:
```ts
import type { UserConfig } from 'tsdown'
```
### Build Fails Silently
Add error handling:
```ts
try {
await build(config)
} catch (error) {
console.error(error)
process.exit(1)
}
```
### Options Not Working
Check spelling and types:
```ts
// ✅ Correct
{ format: ['esm', 'cjs'] }
// ❌ Wrong
{ formats: ['esm', 'cjs'] }
```
## Related
- [Config File](option-config-file.md) - Configuration options
- [Hooks](advanced-hooks.md) - Lifecycle hooks
- [CLI](reference-cli.md) - Command-line interface
- [Plugins](advanced-plugins.md) - Plugin system

View File

@@ -0,0 +1,117 @@
# Customizing Rolldown Options
Pass options directly to the underlying Rolldown bundler.
## Overview
tsdown uses [Rolldown](https://rolldown.rs) as its core bundling engine. You can override Rolldown's input and output options directly for fine-grained control.
**Warning:** You should be familiar with Rolldown's behavior before overriding options. Refer to the [Rolldown Config Options](https://rolldown.rs/options/input) documentation.
## Input Options
### Using an Object
```ts
export default defineConfig({
inputOptions: {
cwd: './custom-directory',
},
})
```
### Using a Function
Dynamically modify options based on the output format:
```ts
export default defineConfig({
inputOptions(inputOptions, format) {
inputOptions.cwd = './custom-directory'
return inputOptions
},
})
```
## Output Options
### Using an Object
```ts
export default defineConfig({
outputOptions: {
legalComments: 'inline',
},
})
```
### Using a Function
```ts
export default defineConfig({
outputOptions(outputOptions, format) {
if (format === 'esm') {
outputOptions.legalComments = 'inline'
}
return outputOptions
},
})
```
## Common Use Cases
### Preserve Legal Comments
```ts
export default defineConfig({
entry: ['src/index.ts'],
outputOptions: {
legalComments: 'inline',
},
})
```
### Custom Working Directory
```ts
export default defineConfig({
entry: ['src/index.ts'],
inputOptions: {
cwd: './packages/my-lib',
},
})
```
### Format-Specific Options
```ts
export default defineConfig({
entry: ['src/index.ts'],
format: ['esm', 'cjs'],
outputOptions(outputOptions, format) {
if (format === 'esm') {
outputOptions.legalComments = 'inline'
}
return outputOptions
},
})
```
## When to Use
- When tsdown doesn't expose a specific Rolldown option
- For format-specific Rolldown customizations
- For advanced bundling scenarios
## Tips
1. **Read Rolldown docs** before overriding options
2. **Use functions** for format-specific customization
3. **Test thoroughly** when overriding defaults
4. **Prefer tsdown options** when available (e.g., use `minify` instead of setting it via `outputOptions`)
## Related
- [Plugins](advanced-plugins.md) - Plugin system
- [Hooks](advanced-hooks.md) - Lifecycle hooks
- [Config File](option-config-file.md) - Configuration options

View File

@@ -0,0 +1,178 @@
# Getting Started
Quick guide to installing and using tsdown for the first time.
## Installation
Install tsdown as a development dependency:
```bash
pnpm add -D tsdown
# Optionally install TypeScript if not using isolatedDeclarations
pnpm add -D typescript
```
**Requirements:**
- Node.js 20.19 or higher
- Experimental support for Deno and Bun
## Quick Start Templates
Use `create-tsdown` CLI for instant setup:
```bash
pnpm create tsdown@latest
```
Provides templates for:
- Pure TypeScript libraries
- React component libraries
- Vue component libraries
- Ready-to-use configurations
## First Bundle
### 1. Create Source Files
```ts
// src/index.ts
import { hello } from './hello.ts'
hello()
// src/hello.ts
export function hello() {
console.log('Hello tsdown!')
}
```
### 2. Create Config File
```ts
// tsdown.config.ts
import { defineConfig } from 'tsdown'
export default defineConfig({
entry: ['./src/index.ts'],
})
```
### 3. Run Build
```bash
./node_modules/.bin/tsdown
```
Output: `dist/index.mjs`
### 4. Test Output
```bash
node dist/index.mjs
# Output: Hello tsdown!
```
## Add to npm Scripts
```json
{
"scripts": {
"build": "tsdown"
}
}
```
Run with:
```bash
pnpm build
```
## CLI Commands
```bash
# Check version
tsdown --version
# View help
tsdown --help
# Build with watch mode
tsdown --watch
# Build with specific format
tsdown --format esm,cjs
# Generate type declarations
tsdown --dts
```
## Basic Configurations
### TypeScript Library (ESM + CJS)
```ts
export default defineConfig({
entry: ['src/index.ts'],
format: ['esm', 'cjs'],
dts: true,
clean: true,
})
```
### Browser Library (IIFE)
```ts
export default defineConfig({
entry: ['src/index.ts'],
format: ['iife'],
globalName: 'MyLib',
platform: 'browser',
minify: true,
})
```
### Multiple Entry Points
```ts
export default defineConfig({
entry: {
index: 'src/index.ts',
utils: 'src/utils.ts',
cli: 'src/cli.ts',
},
format: ['esm', 'cjs'],
dts: true,
})
```
## Using Plugins
Add Rolldown, Rollup, or Unplugin plugins:
```ts
import SomePlugin from 'some-plugin'
export default defineConfig({
entry: ['src/index.ts'],
plugins: [SomePlugin()],
})
```
## Watch Mode
Enable automatic rebuilds on file changes:
```bash
tsdown --watch
# or
tsdown -w
```
## Next Steps
- Configure [entry points](option-entry.md) with glob patterns
- Set up [multiple output formats](option-output-format.md)
- Enable [type declaration generation](option-dts.md)
- Explore [plugins](advanced-plugins.md) for extended functionality
- Read [migration guide](guide-migrate-from-tsup.md) if coming from tsup

View File

@@ -0,0 +1,189 @@
# Migrate from tsup
Migration guide for switching from tsup to tsdown.
## Overview
tsdown is built on Rolldown (Rust-based) vs tsup's esbuild, providing faster and more powerful bundling while maintaining compatibility.
## Automatic Migration
### Single Package
```bash
npx tsdown-migrate
```
### Monorepo
```bash
# Using glob patterns
npx tsdown-migrate packages/*
# Multiple directories
npx tsdown-migrate packages/foo packages/bar
```
### Migration Options
- `[...dirs]` - Directories to migrate (supports globs)
- `--dry-run` or `-d` - Preview changes without modifying files
**Important:** Commit your changes before running migration.
## Key Differences
### Default Values
| Option | tsup | tsdown |
|--------|------|--------|
| `format` | `['cjs']` | `['esm']` |
| `clean` | `false` | `true` |
| `dts` | `false` | Auto-enabled if `types`/`typings` in package.json |
| `target` | Manual | Auto-read from `engines.node` in package.json |
### New Features in tsdown
#### Node Protocol Control
```ts
export default defineConfig({
nodeProtocol: true, // Add node: prefix (fs → node:fs)
nodeProtocol: 'strip', // Remove node: prefix (node:fs → fs)
nodeProtocol: false, // Keep as-is (default)
})
```
#### Better Workspace Support
```ts
export default defineConfig({
workspace: 'packages/*', // Build all packages
})
```
## Migration Checklist
1. **Backup your code** - Commit all changes
2. **Run migration tool** - `npx tsdown-migrate`
3. **Review changes** - Check modified config files
4. **Update scripts** - Change `tsup` to `tsdown` in package.json
5. **Test build** - Run `pnpm build` to verify
6. **Adjust config** - Fine-tune based on your needs
## Common Migration Patterns
### Basic Library
**Before (tsup):**
```ts
export default defineConfig({
entry: ['src/index.ts'],
format: ['cjs', 'esm'],
dts: true,
})
```
**After (tsdown):**
```ts
export default defineConfig({
entry: ['src/index.ts'],
format: ['esm', 'cjs'], // ESM now default
dts: true,
clean: true, // Now enabled by default
})
```
### With Custom Target
**Before (tsup):**
```ts
export default defineConfig({
entry: ['src/index.ts'],
target: 'es2020',
})
```
**After (tsdown):**
```ts
export default defineConfig({
entry: ['src/index.ts'],
// target auto-reads from package.json engines.node
// Or override explicitly:
target: 'es2020',
})
```
### CLI Scripts
**Before (package.json):**
```json
{
"scripts": {
"build": "tsup",
"dev": "tsup --watch"
}
}
```
**After (package.json):**
```json
{
"scripts": {
"build": "tsdown",
"dev": "tsdown --watch"
}
}
```
## Feature Compatibility
### Supported tsup Features
Most tsup features are supported:
- ✅ Multiple entry points
- ✅ Multiple formats (ESM, CJS, IIFE, UMD)
- ✅ TypeScript declarations
- ✅ Source maps
- ✅ Minification
- ✅ Watch mode
- ✅ External dependencies
- ✅ Tree shaking
- ✅ Shims
- ✅ Plugins (Rollup compatible)
### Missing Features
Some tsup features are not yet available. Check [GitHub issues](https://github.com/rolldown/tsdown/issues) for status and request features.
## Troubleshooting
### Build Fails After Migration
1. **Check Node.js version** - Requires Node.js 20.19+
2. **Install TypeScript** - Required for DTS generation
3. **Review config changes** - Ensure format and options are correct
4. **Check dependencies** - Verify all dependencies are installed
### Different Output
- **Format order** - tsdown defaults to ESM first
- **Clean behavior** - tsdown cleans outDir by default
- **Target** - tsdown auto-detects from package.json
### Performance Issues
tsdown should be faster than tsup. If not:
1. Enable `isolatedDeclarations` for faster DTS generation
2. Check for large dependencies being bundled
3. Use `skipNodeModulesBundle` if needed
## Getting Help
- [GitHub Issues](https://github.com/rolldown/tsdown/issues) - Report bugs or request features
- [Documentation](https://tsdown.dev) - Full documentation
- [Migration Tool](https://github.com/rolldown/tsdown/tree/main/packages/tsdown-migrate) - Source code
## Acknowledgements
tsdown is heavily inspired by tsup and incorporates parts of its codebase. Thanks to [@egoist](https://github.com/egoist) and the tsup community.

View File

@@ -0,0 +1,98 @@
# CJS Default Export
Control how default exports are handled in CommonJS output.
## Overview
The `cjsDefault` option improves compatibility when generating CommonJS modules. When enabled (default), modules with only a single default export use `module.exports = ...` instead of `exports.default = ...`.
## Type
```ts
cjsDefault?: boolean // default: true
```
## Basic Usage
### Enabled (Default)
```ts
export default defineConfig({
entry: ['src/index.ts'],
format: ['cjs'],
cjsDefault: true, // default behavior
})
```
### Disabled
```ts
export default defineConfig({
entry: ['src/index.ts'],
format: ['cjs'],
cjsDefault: false,
})
```
## How It Works
### With `cjsDefault: true` (Default)
When your module has **only a single default export**, tsdown transforms:
**Source:**
```ts
// src/index.ts
export default function greet() {
console.log('Hello, world!')
}
```
**Generated CJS:**
```js
// dist/index.cjs
function greet() {
console.log('Hello, world!')
}
module.exports = greet
```
**Generated Declaration:**
```ts
// dist/index.d.cts
declare function greet(): void
export = greet
```
This allows consumers to use `const greet = require('your-module')` directly.
### With `cjsDefault: false`
The default export stays as `exports.default`:
```js
// dist/index.cjs
function greet() {
console.log('Hello, world!')
}
exports.default = greet
```
Consumers need `require('your-module').default`.
## When to Disable
- When your module has both default and named exports
- When you need consistent `exports.default` behavior
- When consumers always use ESM imports
## Tips
1. **Leave enabled** for most libraries (default `true`)
2. **Disable** if you have both default and named exports and need consistent behavior
3. **Test CJS consumers** to verify compatibility
## Related Options
- [Output Format](option-output-format.md) - Module formats
- [Shims](option-shims.md) - ESM/CJS compatibility

View File

@@ -0,0 +1,275 @@
# Output Directory Cleaning
Control how the output directory is cleaned before builds.
## Overview
By default, tsdown **cleans the output directory** before each build to remove stale files from previous builds.
## Basic Usage
### CLI
```bash
# Clean enabled (default)
tsdown
# Disable cleaning
tsdown --no-clean
```
### Config File
```ts
export default defineConfig({
entry: ['src/index.ts'],
clean: true, // Default
})
```
## Behavior
### With Cleaning (Default)
Before each build:
1. All files in `outDir` are removed
2. Fresh build starts with empty directory
3. Only current build outputs remain
**Benefits:**
- No stale files
- Predictable output
- Clean slate each build
### Without Cleaning
Build outputs are added to existing files:
```ts
export default defineConfig({
clean: false,
})
```
**Use when:**
- Multiple builds to same directory
- Incremental builds
- Preserving other files
- Watch mode (faster rebuilds)
## Common Patterns
### Production Build
```ts
export default defineConfig({
entry: ['src/index.ts'],
format: ['esm', 'cjs'],
clean: true, // Ensure clean output
minify: true,
})
```
### Development Mode
```ts
export default defineConfig((options) => ({
entry: ['src/index.ts'],
clean: !options.watch, // Don't clean in watch mode
sourcemap: options.watch,
}))
```
### Multiple Builds
```ts
export default defineConfig([
{
entry: ['src/index.ts'],
outDir: 'dist',
clean: true, // Clean once
},
{
entry: ['src/cli.ts'],
outDir: 'dist',
clean: false, // Don't clean, add to same dir
},
])
```
### Monorepo Package
```ts
export default defineConfig({
workspace: 'packages/*',
entry: ['src/index.ts'],
clean: true, // Clean each package's dist
})
```
### Preserve Static Files
```ts
export default defineConfig({
entry: ['src/index.ts'],
clean: false, // Keep manually added files
outDir: 'dist',
})
// Manually copy files first
// Then run tsdown --no-clean
```
## Clean Patterns
### Selective Cleaning
```ts
import { rmSync } from 'fs'
export default defineConfig({
clean: false, // Disable auto clean
hooks: {
'build:prepare': () => {
// Custom cleaning logic
rmSync('dist/*.js', { force: true })
// Keep other files
},
},
})
```
### Clean Specific Directories
```ts
export default defineConfig({
clean: false,
hooks: {
'build:prepare': async () => {
const { rm } = await import('fs/promises')
// Only clean specific subdirectories
await rm('dist/esm', { recursive: true, force: true })
await rm('dist/cjs', { recursive: true, force: true })
// Keep dist/types
},
},
})
```
## Watch Mode Behavior
In watch mode, cleaning behavior is important:
### Clean on First Build Only
```ts
export default defineConfig((options) => ({
entry: ['src/index.ts'],
watch: options.watch,
clean: !options.watch, // Only clean initial build
}))
```
**Result:**
- First build: Clean
- Subsequent rebuilds: Incremental
### Always Clean
```ts
export default defineConfig({
watch: true,
clean: true, // Clean every rebuild
})
```
**Trade-off:** Slower rebuilds, but always fresh output.
## Tips
1. **Leave enabled** for production builds
2. **Disable in watch mode** for faster rebuilds
3. **Use multiple configs** carefully with cleaning
4. **Custom clean logic** via hooks if needed
5. **Be cautious** - cleaning removes ALL files in outDir
6. **Test cleaning** - ensure no important files are lost
## Troubleshooting
### Important Files Deleted
- Don't put non-build files in outDir
- Use separate directory for static files
- Disable cleaning and manage manually
### Stale Files in Output
- Enable cleaning: `clean: true`
- Or manually remove before build
### Slow Rebuilds in Watch
- Disable cleaning in watch mode
- Use incremental builds
## CLI Examples
```bash
# Default (clean enabled)
tsdown
# Disable cleaning
tsdown --no-clean
# Watch mode without cleaning
tsdown --watch --no-clean
# Multiple formats with cleaning
tsdown --format esm,cjs --clean
```
## Examples
### Safe Production Build
```bash
# Clean before build
rm -rf dist
tsdown --clean
```
### Incremental Development
```ts
export default defineConfig({
entry: ['src/index.ts'],
watch: true,
clean: false, // Faster rebuilds
sourcemap: true,
})
```
### Multi-Stage Build
```ts
// Stage 1: Clean and build main
export default defineConfig([
{
entry: ['src/index.ts'],
outDir: 'dist',
clean: true,
},
{
entry: ['src/utils.ts'],
outDir: 'dist',
clean: false, // Add to same directory
},
])
```
## Related Options
- [Output Directory](option-output-directory.md) - Configure outDir
- [Watch Mode](option-watch-mode.md) - Development workflow
- [Hooks](advanced-hooks.md) - Custom clean logic
- [Entry](option-entry.md) - Entry points

View File

@@ -0,0 +1,281 @@
# Configuration File
Centralize and manage build settings with a configuration file.
## Overview
tsdown searches for config files automatically in the current directory and parent directories.
## Supported File Names
tsdown looks for these files (in order):
- `tsdown.config.ts`
- `tsdown.config.mts`
- `tsdown.config.cts`
- `tsdown.config.js`
- `tsdown.config.mjs`
- `tsdown.config.cjs`
- `tsdown.config.json`
- `tsdown.config`
- `package.json` (in `tsdown` field)
## Basic Configuration
### TypeScript Config
```ts
// tsdown.config.ts
import { defineConfig } from 'tsdown'
export default defineConfig({
entry: ['src/index.ts'],
format: ['esm', 'cjs'],
dts: true,
clean: true,
})
```
### JavaScript Config
```js
// tsdown.config.js
export default {
entry: ['src/index.ts'],
format: ['esm', 'cjs'],
dts: true,
}
```
### JSON Config
```json
// tsdown.config.json
{
"entry": ["src/index.ts"],
"format": ["esm", "cjs"],
"dts": true
}
```
### Package.json Config
```json
// package.json
{
"name": "my-library",
"tsdown": {
"entry": ["src/index.ts"],
"format": ["esm", "cjs"],
"dts": true
}
}
```
## Multiple Configurations
Build multiple outputs with different settings:
```ts
export default defineConfig([
{
entry: 'src/index.ts',
format: ['esm', 'cjs'],
platform: 'node',
dts: true,
},
{
entry: 'src/browser.ts',
format: ['iife'],
platform: 'browser',
globalName: 'MyLib',
minify: true,
},
])
```
Each configuration runs as a separate build.
## Dynamic Configuration
Use a function for conditional config:
```ts
export default defineConfig((options) => {
const isDev = options.watch
return {
entry: ['src/index.ts'],
format: ['esm', 'cjs'],
minify: !isDev,
sourcemap: isDev,
clean: !isDev,
}
})
```
Available options:
- `watch` - Whether watch mode is enabled
- Other CLI flags passed to config
## Config Loaders
Control how TypeScript config files are loaded:
### Auto Loader (Default)
Uses native TypeScript support if available, otherwise falls back to `unrun`:
```bash
tsdown # Uses auto loader
```
### Native Loader
Uses runtime's native TypeScript support (Node.js 23+, Bun, Deno):
```bash
tsdown --config-loader native
```
### Unrun Loader
Uses [unrun](https://gugustinette.github.io/unrun/) library for loading:
```bash
tsdown --config-loader unrun
```
**Tip:** Use `unrun` loader if you need to load TypeScript configs without file extensions in Node.js.
## Custom Config Path
Specify a custom config file location:
```bash
tsdown --config ./configs/build.config.ts
# or
tsdown -c custom-config.ts
```
## Disable Config File
Ignore config files and use CLI options only:
```bash
tsdown --no-config src/index.ts --format esm
```
## Extend Vite/Vitest Config (Experimental)
Reuse existing Vite or Vitest configurations:
```bash
# Extend vite.config.*
tsdown --from-vite
# Extend vitest.config.*
tsdown --from-vite vitest
```
**Note:** Only specific options like `resolve` and `plugins` are reused. Test thoroughly as this feature is experimental.
## Workspace / Monorepo
Build multiple packages with a single config:
```ts
export default defineConfig({
workspace: 'packages/*',
entry: ['src/index.ts'],
format: ['esm', 'cjs'],
dts: true,
})
```
Each package directory matching the glob pattern will be built with the same configuration.
## Common Patterns
### Library with Multiple Builds
```ts
export default defineConfig([
// Node.js build
{
entry: ['src/index.ts'],
format: ['esm', 'cjs'],
platform: 'node',
dts: true,
},
// Browser build
{
entry: ['src/browser.ts'],
format: ['iife'],
platform: 'browser',
globalName: 'MyLib',
},
])
```
### Development vs Production
```ts
export default defineConfig((options) => ({
entry: ['src/index.ts'],
format: ['esm', 'cjs'],
minify: !options.watch,
sourcemap: options.watch ? true : false,
clean: !options.watch,
}))
```
### Monorepo Root Config
```ts
// Root tsdown.config.ts
export default defineConfig({
workspace: 'packages/*',
entry: ['src/index.ts'],
format: ['esm', 'cjs'],
dts: true,
clean: true,
// Shared config for all packages
})
```
### Per-Package Override
```ts
// packages/special/tsdown.config.ts
export default defineConfig({
entry: ['src/index.ts'],
format: ['esm'], // Override: only ESM
platform: 'browser', // Override: browser only
})
```
## Config Precedence
When multiple configs exist:
1. CLI options (highest priority)
2. Config file specified with `--config`
3. Auto-discovered config files
4. Package.json `tsdown` field
5. Default values
## Tips
1. **Use TypeScript config** for type checking and autocomplete
2. **Use defineConfig** helper for better DX
3. **Export arrays** for multiple build configurations
4. **Use functions** for dynamic/conditional configs
5. **Keep configs simple** - prefer convention over configuration
6. **Use workspace** for monorepo builds
7. **Test experimental features** thoroughly before production use
## Related Options
- [Entry](option-entry.md) - Configure entry points
- [Output Format](option-output-format.md) - Output formats
- [Watch Mode](option-watch-mode.md) - Watch mode configuration

View File

@@ -0,0 +1,7 @@
# CSS Support
**Status: Experimental — still in active development.**
CSS handling in tsdown is not yet stable. The API and capabilities may change significantly in future releases.
Avoid relying on CSS-related options in production builds until the feature is marked as stable.

View File

@@ -0,0 +1,309 @@
# Dependencies
Control how dependencies are bundled or externalized.
## Overview
tsdown intelligently handles dependencies to keep your library lightweight while ensuring all necessary code is included.
## Default Behavior
### Auto-Externalized
These are **NOT bundled** by default:
- **`dependencies`** - Installed automatically with your package
- **`peerDependencies`** - User must install manually
### Conditionally Bundled
These are **bundled ONLY if imported**:
- **`devDependencies`** - Only if actually used in source code
- **Phantom dependencies** - In node_modules but not in package.json
## Configuration Options
### `external`
Mark dependencies as external (not bundled):
```ts
export default defineConfig({
entry: ['src/index.ts'],
external: [
'react', // Single package
'react-dom',
/^@myorg\//, // Regex pattern (all @myorg/* packages)
/^lodash/, // All lodash packages
],
})
```
### `noExternal`
Force dependencies to be bundled:
```ts
export default defineConfig({
entry: ['src/index.ts'],
noExternal: [
'some-package', // Bundle this even if in dependencies
'vendor-lib',
],
})
```
### `skipNodeModulesBundle`
Skip resolving and bundling ALL node_modules:
```ts
export default defineConfig({
entry: ['src/index.ts'],
skipNodeModulesBundle: true,
})
```
**Result:** No dependencies from node_modules are parsed or bundled.
## Common Patterns
### React Component Library
```ts
export default defineConfig({
entry: ['src/index.tsx'],
format: ['esm', 'cjs'],
external: [
'react',
'react-dom',
/^react\//, // react/jsx-runtime, etc.
],
dts: true,
})
```
### Utility Library with Shared Deps
```ts
export default defineConfig({
entry: ['src/index.ts'],
format: ['esm', 'cjs'],
// Bundle lodash utilities
noExternal: ['lodash-es'],
dts: true,
})
```
### Monorepo Package
```ts
export default defineConfig({
entry: ['src/index.ts'],
format: ['esm', 'cjs'],
external: [
/^@mycompany\//, // Don't bundle other workspace packages
],
dts: true,
})
```
### CLI Tool (Bundle Everything)
```ts
export default defineConfig({
entry: ['src/cli.ts'],
format: ['esm'],
platform: 'node',
// Bundle all dependencies for standalone CLI
noExternal: [/.*/],
shims: true,
})
```
### Library with Specific Externals
```ts
export default defineConfig({
entry: ['src/index.ts'],
format: ['esm', 'cjs'],
external: [
'vue',
'@vue/runtime-core',
'@vue/reactivity',
],
dts: true,
})
```
## Declaration Files
Dependency handling for `.d.ts` files follows the same rules as JavaScript.
### Complex Type Resolution
Use TypeScript resolver for complex third-party types:
```ts
export default defineConfig({
entry: ['src/index.ts'],
dts: {
resolver: 'tsc', // Use TypeScript resolver instead of Oxc
},
})
```
**When to use `tsc` resolver:**
- Types in `@types/*` packages with non-standard naming (e.g., `@types/babel__generator`)
- Complex type dependencies
- Issues with default Oxc resolver
**Trade-off:** `tsc` is slower but more compatible.
## CLI Usage
### External
```bash
tsdown --external react --external react-dom
tsdown --external '/^@myorg\/.*/'
```
### No External
```bash
tsdown --no-external some-package
```
## Examples by Use Case
### Framework Component
```ts
// Don't bundle framework
export default defineConfig({
external: ['vue', 'react', 'solid-js', 'svelte'],
})
```
### Standalone App
```ts
// Bundle everything
export default defineConfig({
noExternal: [/.*/],
skipNodeModulesBundle: false,
})
```
### Shared Library
```ts
// Bundle only specific utils
export default defineConfig({
external: [/.*/], // External by default
noExternal: ['tiny-utils'], // Except this one
})
```
### Monorepo Package
```ts
// External workspace packages, bundle utilities
export default defineConfig({
external: [
/^@workspace\//, // Other workspace packages
'react',
'react-dom',
],
noExternal: [
'lodash-es', // Bundle utility libraries
],
})
```
## Troubleshooting
### Dependency Bundled Unexpectedly
Check if it's in `devDependencies` and imported. Move to `dependencies`:
```json
{
"dependencies": {
"should-be-external": "^1.0.0"
}
}
```
Or explicitly externalize:
```ts
export default defineConfig({
external: ['should-be-external'],
})
```
### Missing Dependency at Runtime
Ensure it's in `dependencies` or `peerDependencies`:
```json
{
"dependencies": {
"needed-package": "^1.0.0"
}
}
```
Or bundle it:
```ts
export default defineConfig({
noExternal: ['needed-package'],
})
```
### Type Resolution Errors
Use TypeScript resolver for complex types:
```ts
export default defineConfig({
dts: {
resolver: 'tsc',
},
})
```
## Summary
**Default behavior:**
- `dependencies` & `peerDependencies` → External
- `devDependencies` & phantom deps → Bundled if imported
**Override:**
- `external` → Force external
- `noExternal` → Force bundled
- `skipNodeModulesBundle` → Skip all node_modules
**Declaration files:**
- Same bundling logic as JavaScript
- Use `resolver: 'tsc'` for complex types
## Tips
1. **Keep dependencies external** for libraries
2. **Bundle everything** for standalone CLIs
3. **Use regex patterns** for namespaced packages
4. **Check bundle size** to verify external/bundled split
5. **Test with fresh install** to catch missing dependencies
6. **Use tsc resolver** only when needed (slower)
## Related Options
- [External](option-dependencies.md) - This page
- [Platform](option-platform.md) - Runtime environment
- [Output Format](option-output-format.md) - Module formats
- [DTS](option-dts.md) - Type declarations

View File

@@ -0,0 +1,251 @@
# TypeScript Declaration Files
Generate `.d.ts` type declaration files for your library.
## Overview
tsdown uses [rolldown-plugin-dts](https://github.com/sxzz/rolldown-plugin-dts) to generate and bundle TypeScript declaration files.
**Requirements:**
- TypeScript must be installed in your project
## Enabling DTS Generation
### Auto-Enabled
DTS generation is **automatically enabled** if `package.json` contains:
- `types` field, or
- `typings` field
### Manual Enable
#### CLI
```bash
tsdown --dts
```
#### Config File
```ts
export default defineConfig({
dts: true,
})
```
## Performance
### With `isolatedDeclarations` (Recommended)
**Extremely fast** - uses oxc-transform for generation.
```json
// tsconfig.json
{
"compilerOptions": {
"isolatedDeclarations": true
}
}
```
### Without `isolatedDeclarations`
Falls back to TypeScript compiler. Reliable but slower.
## Declaration Maps
Map `.d.ts` files back to original `.ts` sources (useful for monorepos).
### Enable in tsconfig.json
```json
{
"compilerOptions": {
"declarationMap": true
}
}
```
### Enable in tsdown Config
```ts
export default defineConfig({
dts: {
sourcemap: true,
},
})
```
## Advanced Options
### Custom Compiler Options
Override TypeScript compiler options:
```ts
export default defineConfig({
dts: {
compilerOptions: {
removeComments: false,
},
},
})
```
## Build Process
- **ESM format**: `.js` and `.d.ts` files generated in same build
- **CJS format**: Separate build process for `.d.ts` files
## Common Patterns
### Basic Library
```ts
export default defineConfig({
entry: ['src/index.ts'],
format: ['esm', 'cjs'],
dts: true,
})
```
Output:
- `dist/index.mjs`
- `dist/index.cjs`
- `dist/index.d.ts`
### Multiple Entry Points
```ts
export default defineConfig({
entry: {
index: 'src/index.ts',
utils: 'src/utils.ts',
},
format: ['esm', 'cjs'],
dts: true,
})
```
Output:
- `dist/index.mjs`, `dist/index.cjs`, `dist/index.d.ts`
- `dist/utils.mjs`, `dist/utils.cjs`, `dist/utils.d.ts`
### With Monorepo Support
```ts
export default defineConfig({
entry: ['src/index.ts'],
format: ['esm', 'cjs'],
dts: {
sourcemap: true, // Enable declaration maps
},
})
```
### Fast Build (Isolated Declarations)
```json
// tsconfig.json
{
"compilerOptions": {
"isolatedDeclarations": true,
"declaration": true,
"declarationMap": true
}
}
```
```ts
// tsdown.config.ts
export default defineConfig({
entry: ['src/index.ts'],
format: ['esm', 'cjs'],
dts: true, // Will use fast oxc-transform
})
```
## Troubleshooting
### Missing Types
Ensure TypeScript is installed:
```bash
pnpm add -D typescript
```
### Slow Generation
Enable `isolatedDeclarations` in `tsconfig.json` for faster builds.
### Declaration Errors
Check that all exports have explicit types (required for `isolatedDeclarations`).
### Report Issues
For DTS-specific issues, report to [rolldown-plugin-dts](https://github.com/sxzz/rolldown-plugin-dts/issues).
### Vue Support
Enable Vue component type generation (requires `vue-tsc`):
```ts
export default defineConfig({
dts: {
vue: true,
},
})
```
### Oxc Transform
Control Oxc usage for declaration generation:
```ts
export default defineConfig({
dts: {
oxc: true, // Use oxc-transform (fast, requires isolatedDeclarations)
},
})
```
### Custom TSConfig
Specify a different tsconfig for DTS generation:
```ts
export default defineConfig({
dts: {
tsconfig: './tsconfig.build.json',
},
})
```
## Available DTS Options
| Option | Type | Description |
|--------|------|-------------|
| `sourcemap` | `boolean` | Generate declaration source maps |
| `compilerOptions` | `object` | Override TypeScript compiler options |
| `vue` | `boolean` | Enable Vue type generation (requires vue-tsc) |
| `oxc` | `boolean` | Use oxc-transform for fast generation |
| `tsconfig` | `string` | Path to tsconfig file |
| `resolver` | `'oxc' \| 'tsc'` | Module resolver: `'oxc'` (default, fast) or `'tsc'` (more compatible) |
| `cjsDefault` | `boolean` | CJS default export handling |
| `sideEffects` | `boolean` | Preserve side effects in declarations |
## Tips
1. **Always enable DTS** for TypeScript libraries
2. **Use isolatedDeclarations** for fast builds
3. **Enable declaration maps** in monorepos
4. **Ensure explicit types** for all exports
5. **Install TypeScript** as dev dependency
## Related Options
- [Entry](option-entry.md) - Configure entry points
- [Output Format](option-output-format.md) - Multiple output formats
- [Target](option-target.md) - JavaScript version

View File

@@ -0,0 +1,211 @@
# Entry Points
Configure which files to bundle as entry points.
## Overview
Entry points are the starting files for the bundling process. Each entry point generates a separate bundle.
## Usage Patterns
### CLI
```bash
# Single entry
tsdown src/index.ts
# Multiple entries
tsdown src/index.ts src/cli.ts
# Glob patterns
tsdown 'src/*.ts'
```
### Config File
#### Single Entry
```ts
export default defineConfig({
entry: 'src/index.ts',
})
```
#### Multiple Entries (Array)
```ts
export default defineConfig({
entry: ['src/entry1.ts', 'src/entry2.ts'],
})
```
#### Named Entries (Object)
```ts
export default defineConfig({
entry: {
main: 'src/index.ts',
utils: 'src/utils.ts',
cli: 'src/cli.ts',
},
})
```
Output files will match the keys:
- `dist/main.mjs`
- `dist/utils.mjs`
- `dist/cli.mjs`
## Glob Patterns
Match multiple files dynamically using glob patterns:
### All TypeScript Files
```ts
export default defineConfig({
entry: 'src/**/*.ts',
})
```
### Exclude Test Files
```ts
export default defineConfig({
entry: ['src/*.ts', '!src/*.test.ts'],
})
```
### Object Entries with Glob Patterns
Use glob wildcards (`*`) in both keys and values. The `*` in the key acts as a placeholder replaced with the matched file name (without extension):
```ts
export default defineConfig({
entry: {
// Maps src/foo.ts → dist/lib/foo.js, src/bar.ts → dist/lib/bar.js
'lib/*': 'src/*.ts',
},
})
```
#### Negation Patterns in Object Entries
Values can be an array with negation patterns (`!`):
```ts
export default defineConfig({
entry: {
'hooks/*': ['src/hooks/*.ts', '!src/hooks/index.ts'],
},
})
```
Multiple positive and negation patterns:
```ts
export default defineConfig({
entry: {
'utils/*': [
'src/utils/*.ts',
'src/utils/*.tsx',
'!src/utils/index.ts',
'!src/utils/internal.ts',
],
},
})
```
**Warning:** Multiple positive patterns in an array value must share the same base directory.
### Mixed Entries
Mix strings, glob patterns, and object entries in an array:
```ts
export default defineConfig({
entry: [
'src/*',
'!src/foo.ts',
{ main: 'index.ts' },
{ 'lib/*': ['src/*.ts', '!src/bar.ts'] },
],
})
```
Object entries take precedence when output names conflict.
### Windows Compatibility
Use forward slashes `/` instead of backslashes `\` on Windows:
```ts
// ✅ Correct
entry: 'src/utils/*.ts'
// ❌ Wrong on Windows
entry: 'src\\utils\\*.ts'
```
## Common Patterns
### Library with Main Export
```ts
export default defineConfig({
entry: 'src/index.ts',
format: ['esm', 'cjs'],
dts: true,
})
```
### Library with Multiple Exports
```ts
export default defineConfig({
entry: {
index: 'src/index.ts',
client: 'src/client.ts',
server: 'src/server.ts',
},
format: ['esm', 'cjs'],
dts: true,
})
```
### CLI Tool
```ts
export default defineConfig({
entry: {
cli: 'src/cli.ts',
},
format: ['esm'],
platform: 'node',
})
```
### Preserve Directory Structure
Use with `unbundle: true` to keep file structure:
```ts
export default defineConfig({
entry: ['src/**/*.ts', '!**/*.test.ts'],
unbundle: true,
format: ['esm'],
dts: true,
})
```
This will output files matching the source structure:
- `src/index.ts``dist/index.mjs`
- `src/utils/helper.ts``dist/utils/helper.mjs`
## Tips
1. **Use glob patterns** for multiple related files
2. **Use object syntax** for custom output names
3. **Exclude test files** with negation patterns `!**/*.test.ts`
4. **Combine with unbundle** to preserve directory structure
5. **Use named entries** for better control over output filenames

View File

@@ -0,0 +1,127 @@
# Package Validation (publint & attw)
Validate your package configuration and type declarations before publishing.
## Overview
tsdown integrates with [publint](https://publint.dev/) and [Are the types wrong?](https://arethetypeswrong.github.io/) (attw) to catch common packaging issues. Both are optional dependencies.
## Installation
```bash
# publint only
npm install -D publint
# attw only
npm install -D @arethetypeswrong/core
# both
npm install -D publint @arethetypeswrong/core
```
## publint
Checks that `package.json` fields (`exports`, `main`, `module`, `types`) match your actual output files.
### Enable
```ts
export default defineConfig({
publint: true,
})
```
### Configuration
```ts
export default defineConfig({
publint: {
level: 'error', // 'warning' | 'error' | 'suggestion'
},
})
```
### CLI
```bash
tsdown --publint
```
## attw (Are the types wrong?)
Verifies TypeScript declarations are correct across different module resolution strategies (`node10`, `node16`, `bundler`).
### Enable
```ts
export default defineConfig({
attw: true,
})
```
### Configuration
```ts
export default defineConfig({
attw: {
profile: 'node16', // 'strict' | 'node16' | 'esm-only'
level: 'error', // 'warn' | 'error'
ignoreRules: ['false-cjs', 'cjs-resolves-to-esm'],
},
})
```
### Profiles
| Profile | Description |
|---------|-------------|
| `strict` | Requires all resolutions to pass (default) |
| `node16` | Ignores `node10` resolution failures |
| `esm-only` | Ignores `node10` and `node16-cjs` resolution failures |
### Ignore Rules
Suppress specific problem types with `ignoreRules`:
| Rule | Description |
|------|-------------|
| `no-resolution` | Module could not be resolved |
| `untyped-resolution` | Resolution succeeded but has no types |
| `false-cjs` | Types indicate CJS but implementation is ESM |
| `false-esm` | Types indicate ESM but implementation is CJS |
| `cjs-resolves-to-esm` | CJS resolution points to an ESM module |
| `fallback-condition` | A fallback/wildcard condition was used |
| `cjs-only-exports-default` | CJS module only exports a default |
| `named-exports` | Named exports mismatch between types and implementation |
| `false-export-default` | Types declare a default export that doesn't exist |
| `missing-export-equals` | Types are missing `export =` for CJS |
| `unexpected-module-syntax` | File uses unexpected module syntax |
| `internal-resolution-error` | Internal resolution error in type checking |
### CLI
```bash
tsdown --attw
```
## CI Integration
Both tools support CI-aware options:
```ts
export default defineConfig({
publint: 'ci-only',
attw: {
enabled: 'ci-only',
profile: 'node16',
level: 'error',
},
})
```
Both tools require a `package.json` in your project directory.
## Related Options
- [CI Environment](advanced-ci.md) - CI-aware option details
- [Package Exports](option-package-exports.md) - Auto-generate exports field

View File

@@ -0,0 +1,91 @@
# Log Level
Control the verbosity of build output.
## Overview
The `logLevel` option controls how much information tsdown displays during the build process.
## Type
```ts
logLevel?: 'silent' | 'error' | 'warn' | 'info'
```
**Default:** `'info'`
## Basic Usage
### CLI
```bash
# Suppress all output
tsdown --log-level silent
# Only show errors
tsdown --log-level error
# Show warnings and errors
tsdown --log-level warn
# Show all info (default)
tsdown --log-level info
```
### Config File
```ts
export default defineConfig({
entry: ['src/index.ts'],
logLevel: 'error',
})
```
## Available Levels
| Level | Shows | Use Case |
|-------|-------|----------|
| `silent` | Nothing | CI/CD pipelines, scripting |
| `error` | Errors only | Minimal output |
| `warn` | Warnings + errors | Standard CI/CD |
| `info` | All messages | Development (default) |
## Common Patterns
### CI/CD Pipeline
```ts
export default defineConfig({
entry: ['src/index.ts'],
logLevel: 'error', // Only show errors in CI
})
```
### Scripting
```ts
export default defineConfig({
entry: ['src/index.ts'],
logLevel: 'silent', // No output for automation
})
```
## Fail on Warnings
The `failOnWarn` option controls whether warnings cause the build to exit with a non-zero code. Defaults to `'ci-only'` — warnings fail the build in CI but not locally.
```ts
export default defineConfig({
failOnWarn: 'ci-only', // Default: fail on warnings only in CI
// failOnWarn: true, // Always fail on warnings
// failOnWarn: false, // Never fail on warnings
})
```
See [CI Environment](advanced-ci.md) for more about CI-aware options.
## Related Options
- [CI Environment](advanced-ci.md) - CI-aware option details
- [CLI Reference](reference-cli.md) - All CLI options
- [Config File](option-config-file.md) - Configuration setup

View File

@@ -0,0 +1,177 @@
# Minification
Compress code to reduce bundle size.
## Overview
Minification removes unnecessary characters (whitespace, comments) and optimizes code for production, reducing bundle size and improving load times.
**Note:** Uses [Oxc minifier](https://oxc.rs/docs/contribute/minifier) internally. The minifier is currently in alpha.
## Type
```ts
minify?: boolean | 'dce-only' | MinifyOptions
```
- `true` — Enable full minification (whitespace removal, mangling, compression)
- `false` — Disable minification (default)
- `'dce-only'` — Only perform dead code elimination without full minification
- `MinifyOptions` — Pass detailed options to the Oxc minifier
## Basic Usage
### CLI
```bash
# Enable minification
tsdown --minify
# Disable minification
tsdown --no-minify
```
**Note:** The CLI `--minify` flag is a boolean toggle. For `'dce-only'` mode or advanced options, use the config file.
### Config File
```ts
export default defineConfig({
entry: ['src/index.ts'],
minify: true,
})
```
### DCE-Only Mode
Remove dead code without full minification (keeps readable output):
```ts
export default defineConfig({
entry: ['src/index.ts'],
minify: 'dce-only',
})
```
## Example Output
### Without Minification
```js
// dist/index.mjs
const x = 1
function hello(x$1) {
console.log('Hello World')
console.log(x$1)
}
hello(x)
```
### With Minification
```js
// dist/index.mjs
const e=1;function t(e){console.log(`Hello World`),console.log(e)}t(e);
```
## Common Patterns
### Production Build
```ts
export default defineConfig({
entry: ['src/index.ts'],
format: ['esm', 'cjs'],
minify: true,
clean: true,
})
```
### Conditional Minification
```ts
export default defineConfig((options) => ({
entry: ['src/index.ts'],
format: ['esm'],
minify: !options.watch, // Only minify in production
}))
```
### Browser Library
```ts
export default defineConfig({
entry: ['src/index.ts'],
format: ['iife'],
platform: 'browser',
globalName: 'MyLib',
minify: true,
})
```
### Multiple Builds
```ts
export default defineConfig([
// Development build
{
entry: ['src/index.ts'],
format: ['esm'],
minify: false,
outDir: 'dist/dev',
},
// Production build
{
entry: ['src/index.ts'],
format: ['esm'],
minify: true,
outDir: 'dist/prod',
},
])
```
## CLI Examples
```bash
# Production build with minification
tsdown --minify --clean
# Multiple formats with minification
tsdown --format esm --format cjs --minify
# Conditional minification (only when not watching)
tsdown --minify # Or omit --watch
```
## Tips
1. **Use `minify: true`** for production builds
2. **Use `'dce-only'`** to remove dead code while keeping output readable
3. **Skip minification** during development for faster rebuilds
4. **Combine with tree shaking** for best results
5. **Test minified output** thoroughly (Oxc minifier is in alpha)
## Troubleshooting
### Minified Code Has Bugs
Oxc minifier is in alpha and may have issues:
1. **Use DCE-only mode**: `minify: 'dce-only'`
2. **Report bug** to [Oxc project](https://github.com/oxc-project/oxc/issues)
3. **Disable minification**: `minify: false`
### Unexpected Output
- **Test unminified** first to isolate issue
- **Check source maps** for debugging
- **Verify target compatibility**
## Related Options
- [Tree Shaking](option-tree-shaking.md) - Remove unused code
- [Target](option-target.md) - Syntax transformations
- [Output Format](option-output-format.md) - Module formats
- [Sourcemap](option-sourcemap.md) - Debug information

View File

@@ -0,0 +1,270 @@
# Output Directory
Configure the output directory for bundled files.
## Overview
By default, tsdown outputs bundled files to the `dist` directory. You can customize this location using the `outDir` option.
## Basic Usage
### CLI
```bash
# Default output to dist/
tsdown
# Custom output directory
tsdown --out-dir build
tsdown -d lib
```
### Config File
```ts
export default defineConfig({
entry: ['src/index.ts'],
outDir: 'build',
})
```
## Common Patterns
### Standard Library
```ts
export default defineConfig({
entry: ['src/index.ts'],
format: ['esm', 'cjs'],
outDir: 'dist', // Default
dts: true,
})
```
**Output:**
```
dist/
├── index.mjs
├── index.cjs
└── index.d.ts
```
### Separate Directories by Format
```ts
export default defineConfig([
{
entry: ['src/index.ts'],
format: ['esm'],
outDir: 'dist/esm',
},
{
entry: ['src/index.ts'],
format: ['cjs'],
outDir: 'dist/cjs',
},
])
```
**Output:**
```
dist/
├── esm/
│ └── index.js
└── cjs/
└── index.js
```
### Monorepo Package
```ts
export default defineConfig({
entry: ['src/index.ts'],
outDir: 'lib', // Custom directory
clean: true,
})
```
### Build to Root
```ts
export default defineConfig({
entry: ['src/index.ts'],
outDir: '.', // Output to project root (not recommended)
clean: false, // Don't clean root!
})
```
**Warning:** Be careful when outputting to root to avoid deleting important files.
## Output Extensions
### Custom Extensions
Use `outExtensions` to control file extensions:
```ts
export default defineConfig({
entry: ['src/index.ts'],
format: ['esm', 'cjs'],
outDir: 'dist',
outExtensions({ format }) {
return {
js: format === 'esm' ? '.mjs' : '.cjs',
}
},
})
```
### Default Extensions
| Format | Default Extension | With `type: "module"` |
|--------|-------------------|----------------------|
| `esm` | `.mjs` | `.js` |
| `cjs` | `.cjs` | `.js` |
| `iife` | `.global.js` | `.global.js` |
| `umd` | `.umd.js` | `.umd.js` |
### ESM with .js Extension
```ts
export default defineConfig({
entry: ['src/index.ts'],
format: ['esm'],
outExtensions: () => ({ js: '.js' }),
})
```
Requires `"type": "module"` in package.json.
## File Naming
### Entry Names
Control output filenames based on entry names:
```ts
export default defineConfig({
entry: {
index: 'src/index.ts',
utils: 'src/utils.ts',
},
outDir: 'dist',
})
```
**Output:**
```
dist/
├── index.mjs
└── utils.mjs
```
### Glob Entry
```ts
export default defineConfig({
entry: ['src/**/*.ts', '!**/*.test.ts'],
outDir: 'dist',
unbundle: true, // Preserve structure
})
```
**Output:**
```
dist/
├── index.mjs
├── utils/
│ └── helper.mjs
└── components/
└── button.mjs
```
## Multiple Builds
### Same Output Directory
```ts
export default defineConfig([
{
entry: ['src/index.ts'],
outDir: 'dist',
clean: true, // Clean first
},
{
entry: ['src/cli.ts'],
outDir: 'dist',
clean: false, // Don't clean again
},
])
```
### Different Output Directories
```ts
export default defineConfig([
{
entry: ['src/index.ts'],
format: ['esm', 'cjs'],
outDir: 'dist/lib',
},
{
entry: ['src/cli.ts'],
format: ['esm'],
outDir: 'dist/bin',
},
])
```
## CLI Examples
```bash
# Default
tsdown
# Custom directory
tsdown --out-dir build
tsdown -d lib
# Nested directory
tsdown --out-dir dist/lib
# With other options
tsdown --out-dir build --format esm,cjs --dts
```
## Tips
1. **Use default `dist`** for standard projects
2. **Be careful with root** - avoid `outDir: '.'`
3. **Clean before build** - use `clean: true`
4. **Consistent naming** - match your project conventions
5. **Separate by format** if needed for clarity
6. **Check .gitignore** - ensure output dir is ignored
## Troubleshooting
### Files Not in Expected Location
- Check `outDir` config
- Verify build completed successfully
- Look for typos in path
### Files Deleted Unexpectedly
- Check if `clean: true`
- Ensure outDir doesn't overlap with source
- Don't use root as outDir
### Permission Errors
- Check write permissions
- Ensure directory isn't locked
- Try different location
## Related Options
- [Cleaning](option-cleaning.md) - Clean output directory
- [Entry](option-entry.md) - Entry points
- [Output Format](option-output-format.md) - Module formats
- [Unbundle](option-unbundle.md) - Preserve structure

View File

@@ -0,0 +1,179 @@
# Output Format
Configure the module format(s) for generated bundles.
## Overview
tsdown can generate bundles in multiple formats. Default is ESM.
## Available Formats
| Format | Description | Use Case |
|--------|-------------|----------|
| `esm` | ECMAScript Module (default) | Modern Node.js, browsers, Deno |
| `cjs` | CommonJS | Legacy Node.js, require() |
| `iife` | Immediately Invoked Function Expression | Browser `<script>` tags |
| `umd` | Universal Module Definition | AMD, CommonJS, and globals |
## Usage
### CLI
```bash
# Single format
tsdown --format esm
# Multiple formats
tsdown --format esm --format cjs
# Or comma-separated
tsdown --format esm,cjs
```
### Config File
#### Single Format
```ts
export default defineConfig({
entry: ['src/index.ts'],
format: 'esm',
})
```
#### Multiple Formats
```ts
export default defineConfig({
entry: ['src/index.ts'],
format: ['esm', 'cjs'],
})
```
## Per-Format Configuration
Override options for specific formats:
```ts
export default defineConfig({
entry: ['src/index.ts'],
format: {
esm: {
target: ['es2015'],
},
cjs: {
target: ['node20'],
},
},
})
```
This allows different targets, platforms, or other settings per format.
## Common Patterns
### Modern Library (ESM + CJS)
```ts
export default defineConfig({
entry: ['src/index.ts'],
format: ['esm', 'cjs'],
dts: true,
})
```
Output:
- `dist/index.mjs` (ESM)
- `dist/index.cjs` (CJS)
- `dist/index.d.ts` (Types)
### Browser Library (IIFE)
```ts
export default defineConfig({
entry: ['src/index.ts'],
format: ['iife'],
globalName: 'MyLib',
platform: 'browser',
minify: true,
})
```
Output: `dist/index.global.js` (IIFE with global `MyLib`)
### Universal Library (UMD)
```ts
export default defineConfig({
entry: ['src/index.ts'],
format: ['umd'],
globalName: 'MyLib',
platform: 'neutral',
})
```
Works with AMD, CommonJS, and browser globals.
### Node.js Package (CJS + ESM)
```ts
export default defineConfig({
entry: ['src/index.ts'],
format: ['esm', 'cjs'],
platform: 'node',
dts: true,
shims: true, // Add __dirname, __filename for CJS compat
})
```
### Framework Component Library
```ts
export default defineConfig({
entry: ['src/index.tsx'],
format: ['esm', 'cjs'],
external: ['react', 'react-dom'], // Don't bundle dependencies
dts: true,
})
```
## Format-Specific Outputs
### File Extensions
| Format | Extension |
|--------|-----------|
| ESM | `.mjs` or `.js` (with `"type": "module"`) |
| CJS | `.cjs` or `.js` (without `"type": "module"`) |
| IIFE | `.global.js` |
| UMD | `.umd.js` |
### Customize Extensions
Use `outExtensions` to override:
```ts
export default defineConfig({
entry: ['src/index.ts'],
format: ['esm', 'cjs'],
outExtensions: ({ format }) => ({
js: format === 'esm' ? '.js' : '.cjs',
}),
})
```
## Tips
1. **Use ESM + CJS** for maximum compatibility
2. **Use IIFE** for browser-only libraries
3. **Use UMD** for universal compatibility (less common now)
4. **Externalize dependencies** to avoid bundling framework code
5. **Add shims** for CJS compatibility when using Node.js APIs
6. **Set globalName** for IIFE/UMD formats
## Related Options
- [Target](option-target.md) - Set JavaScript version
- [Platform](option-platform.md) - Set platform (node, browser, neutral)
- [Shims](option-shims.md) - Add ESM/CJS compatibility
- [Output Directory](option-output-directory.md) - Customize output paths

View File

@@ -0,0 +1,320 @@
# Auto-Generate Package Exports
Automatically generate package.json exports field from build output.
## Overview
tsdown can automatically infer and generate the `exports`, `main`, `module`, and `types` fields in your `package.json` based on your build outputs.
**Status:** Experimental - review before publishing.
## Basic Usage
### CLI
```bash
tsdown --exports
```
### Config File
```ts
export default defineConfig({
entry: ['src/index.ts'],
format: ['esm', 'cjs'],
dts: true,
exports: true,
})
```
## What Gets Generated
### Single Entry
**Config:**
```ts
export default defineConfig({
entry: ['src/index.ts'],
format: ['esm', 'cjs'],
dts: true,
exports: true,
})
```
**Generated in package.json:**
```json
{
"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"
}
}
}
```
### Multiple Entries
**Config:**
```ts
export default defineConfig({
entry: {
index: 'src/index.ts',
utils: 'src/utils.ts',
},
format: ['esm', 'cjs'],
dts: true,
exports: true,
})
```
**Generated in package.json:**
```json
{
"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"
},
"./utils": {
"types": "./dist/utils.d.ts",
"import": "./dist/utils.mjs",
"require": "./dist/utils.cjs"
}
}
}
```
## Export All Files
Include all output files, not just entry points:
```ts
export default defineConfig({
entry: ['src/index.ts'],
format: ['esm', 'cjs'],
exports: {
all: true,
},
})
```
**Result:** All `.mjs`, `.cjs`, and `.d.ts` files will be added to exports.
## Dev-Time Source Linking
### Dev Exports
Link to source files during development:
```ts
export default defineConfig({
entry: ['src/index.ts'],
format: ['esm', 'cjs'],
exports: {
devExports: true,
},
})
```
**Generated:**
```json
{
"exports": {
".": "./src/index.ts" // Points to source
},
"publishConfig": {
"exports": {
".": {
"import": "./dist/index.mjs",
"require": "./dist/index.cjs"
}
}
}
}
```
**Note:** Supported by pnpm/yarn, not npm.
### Conditional Dev Exports
Use specific condition for dev exports:
```ts
export default defineConfig({
exports: {
devExports: 'development',
},
})
```
**Generated:**
```json
{
"exports": {
".": {
"development": "./src/index.ts",
"import": "./dist/index.mjs",
"require": "./dist/index.cjs"
}
}
}
```
**Use with TypeScript customConditions:**
```json
// tsconfig.json
{
"compilerOptions": {
"customConditions": ["development"]
}
}
```
## Custom Exports
Add custom export mappings:
```ts
export default defineConfig({
entry: ['src/index.ts'],
exports: {
customExports(pkg, context) {
// Add custom export
pkg['./foo'] = './dist/foo.js'
// Add package.json export
pkg['./package.json'] = './package.json'
return pkg
},
},
})
```
## Common Patterns
### Complete Library Setup
```ts
export default defineConfig({
entry: ['src/index.ts'],
format: ['esm', 'cjs'],
dts: true,
exports: true,
clean: true,
})
```
### Multiple Exports with Dev Mode
```ts
export default defineConfig({
entry: {
index: 'src/index.ts',
client: 'src/client.ts',
server: 'src/server.ts',
},
format: ['esm', 'cjs'],
dts: true,
exports: {
all: false, // Only entries
devExports: 'development',
},
})
```
### Monorepo Package
```ts
export default defineConfig({
workspace: 'packages/*',
entry: ['src/index.ts'],
format: ['esm', 'cjs'],
dts: true,
exports: true, // Generate for each package
})
```
## Validation
### Enable Publint
Validate generated exports:
```bash
tsdown --exports --publint
```
Or in config:
```ts
export default defineConfig({
exports: true,
publint: true, // Validate exports
})
```
## Tips
1. **Review before publishing** - Check generated fields
2. **Use with publint** - Validate exports field
3. **Enable for libraries** - Especially with multiple exports
4. **Use devExports** - Better DX during development
5. **Test exports** - Verify imports work correctly
## Troubleshooting
### Exports Not Generated
- Ensure `exports: true` is set
- Check build completed successfully
- Verify output files exist
### Wrong Export Paths
- Check `outDir` configuration
- Verify entry names match expectations
- Review `format` settings
### Dev Exports Not Working
- Only supported by pnpm/yarn
- Check package manager
- Use `publishConfig` for publishing
### Types Not Exported
- Enable `dts: true`
- Ensure TypeScript is installed
- Check `.d.ts` files are generated
## CLI Examples
```bash
# Generate exports
tsdown --exports
# With publint validation
tsdown --exports --publint
# Export all files
tsdown --exports
# With dev exports
tsdown --exports
```
## Related Options
- [Entry](option-entry.md) - Configure entry points
- [Output Format](option-output-format.md) - Module formats
- [DTS](option-dts.md) - Type declarations

View File

@@ -0,0 +1,254 @@
# Platform
Target runtime environment for bundled code.
## Overview
Platform determines the runtime environment and affects module resolution, built-in handling, and optimizations.
## Available Platforms
| Platform | Runtime | Built-ins | Use Case |
|----------|---------|-----------|----------|
| `node` | Node.js (default) | Resolved automatically | Server-side, CLIs, tooling |
| `browser` | Web browsers | Warning if used | Front-end applications |
| `neutral` | Platform-agnostic | No assumptions | Universal libraries |
## Usage
### CLI
```bash
tsdown --platform node # Default
tsdown --platform browser
tsdown --platform neutral
```
### Config File
```ts
export default defineConfig({
entry: ['src/index.ts'],
platform: 'browser',
})
```
## Platform Details
### Node Platform
**Default platform** for server-side and tooling.
```ts
export default defineConfig({
entry: ['src/index.ts'],
platform: 'node',
})
```
**Characteristics:**
- Node.js built-ins (fs, path, etc.) resolved automatically
- Optimized for Node.js runtime
- Compatible with Deno and Bun
- Default mainFields: `['main', 'module']`
### Browser Platform
For web applications running in browsers.
```ts
export default defineConfig({
entry: ['src/index.ts'],
platform: 'browser',
format: ['esm'],
})
```
**Characteristics:**
- Warnings if Node.js built-ins are used
- May require polyfills for Node APIs
- Optimized for browser environments
- Default mainFields: `['browser', 'module', 'main']`
### Neutral Platform
Platform-agnostic for universal libraries.
```ts
export default defineConfig({
entry: ['src/index.ts'],
platform: 'neutral',
format: ['esm'],
})
```
**Characteristics:**
- No runtime assumptions
- No automatic built-in resolution
- Relies on `exports` field only
- Default mainFields: `[]`
- Full control over runtime behavior
## CJS Format Limitation
**CJS format always uses `node` platform** and cannot be changed.
```ts
export default defineConfig({
entry: ['src/index.ts'],
format: ['cjs'],
platform: 'browser', // Ignored for CJS
})
```
See [rolldown PR #4693](https://github.com/rolldown/rolldown/pull/4693#issuecomment-2912229545) for details.
## Module Resolution
### Main Fields
Different platforms check different `package.json` fields:
| Platform | mainFields | Priority |
|----------|------------|----------|
| `node` | `['main', 'module']` | main → module |
| `browser` | `['browser', 'module', 'main']` | browser → module → main |
| `neutral` | `[]` | Only `exports` field |
### Neutral Platform Resolution
When using `neutral`, packages without `exports` field may fail to resolve:
```
Help: The "main" field here was ignored. Main fields must be configured
explicitly when using the "neutral" platform.
```
**Solution:** Configure mainFields explicitly:
```ts
export default defineConfig({
platform: 'neutral',
inputOptions: {
resolve: {
mainFields: ['module', 'main'],
},
},
})
```
## Common Patterns
### Node.js CLI Tool
```ts
export default defineConfig({
entry: ['src/cli.ts'],
format: ['esm'],
platform: 'node',
shims: true,
})
```
### Browser Library (IIFE)
```ts
export default defineConfig({
entry: ['src/index.ts'],
format: ['iife'],
platform: 'browser',
globalName: 'MyLib',
minify: true,
})
```
### Universal Library
```ts
export default defineConfig({
entry: ['src/index.ts'],
format: ['esm'],
platform: 'neutral',
inputOptions: {
resolve: {
mainFields: ['module', 'main'],
},
},
})
```
### React Component Library
```ts
export default defineConfig({
entry: ['src/index.tsx'],
format: ['esm', 'cjs'],
platform: 'browser',
external: ['react', 'react-dom'],
})
```
### Node.js + Browser Builds
```ts
export default defineConfig([
{
entry: ['src/index.ts'],
format: ['esm', 'cjs'],
platform: 'node',
},
{
entry: ['src/browser.ts'],
format: ['esm'],
platform: 'browser',
},
])
```
## Troubleshooting
### Node Built-in Warnings (Browser)
When using Node.js APIs in browser builds:
```
Warning: Module "fs" has been externalized for browser compatibility
```
**Solutions:**
1. Use platform: 'node' if not browser-only
2. Add polyfills for Node APIs
3. Avoid Node.js built-ins in browser code
4. Use platform: 'neutral' with careful dependency management
### Module Resolution Issues (Neutral)
When packages don't resolve with `neutral`:
```ts
export default defineConfig({
platform: 'neutral',
inputOptions: {
resolve: {
mainFields: ['module', 'browser', 'main'],
conditions: ['import', 'require'],
},
},
})
```
## Tips
1. **Use `node`** for server-side and CLIs (default)
2. **Use `browser`** for front-end applications
3. **Use `neutral`** for universal libraries
4. **Configure mainFields** when using neutral platform
5. **CJS is always node** - use ESM for other platforms
6. **Test in target environment** to verify compatibility
## Related Options
- [Output Format](option-output-format.md) - Module formats
- [Target](option-target.md) - JavaScript version
- [Shims](option-shims.md) - ESM/CJS compatibility
- [Dependencies](option-dependencies.md) - External packages

View File

@@ -0,0 +1,297 @@
# Shims
Add compatibility between ESM and CommonJS module systems.
## Overview
Shims provide small pieces of code that bridge the gap between CommonJS (CJS) and ECMAScript Modules (ESM), enabling cross-module-system compatibility.
## What Shims Provide
### ESM Output (when enabled)
With `shims: true`, adds CommonJS variables to ESM:
- `__dirname` - Current directory path
- `__filename` - Current file path
### ESM Output (automatic)
Always added when using `require` in ESM on Node.js:
- `require` function via `createRequire(import.meta.url)`
### CJS Output (automatic)
Always added to CommonJS output:
- `import.meta.url`
- `import.meta.dirname`
- `import.meta.filename`
## Usage
### CLI
```bash
tsdown --shims
```
### Config File
```ts
export default defineConfig({
entry: ['src/index.ts'],
format: ['esm'],
shims: true,
})
```
## Generated Code
### ESM with Shims
**Source:**
```ts
console.log(__dirname)
console.log(__filename)
```
**Output (shims: true):**
```js
import { fileURLToPath } from 'node:url'
import { dirname } from 'node:path'
const __filename = fileURLToPath(import.meta.url)
const __dirname = dirname(__filename)
console.log(__dirname)
console.log(__filename)
```
### ESM with require
**Source:**
```ts
const mod = require('some-module')
```
**Output (automatic on Node.js):**
```js
import { createRequire } from 'node:module'
const require = createRequire(import.meta.url)
const mod = require('some-module')
```
### CJS with import.meta
**Source:**
```ts
console.log(import.meta.url)
console.log(import.meta.dirname)
```
**Output (automatic):**
```js
const import_meta = {
url: require('url').pathToFileURL(__filename).toString(),
dirname: __dirname,
filename: __filename
}
console.log(import_meta.url)
console.log(import_meta.dirname)
```
## Common Patterns
### Node.js CLI Tool
```ts
export default defineConfig({
entry: ['src/cli.ts'],
format: ['esm'],
platform: 'node',
shims: true, // Add __dirname, __filename
})
```
### Dual Format Library
```ts
export default defineConfig({
entry: ['src/index.ts'],
format: ['esm', 'cjs'],
platform: 'node',
shims: true, // ESM gets __dirname/__filename
// CJS gets import.meta.* (automatic)
})
```
### Server-Side Code
```ts
export default defineConfig({
entry: ['src/server.ts'],
format: ['esm'],
platform: 'node',
shims: true,
external: [/.*/], // External all deps
})
```
### File System Operations
```ts
// Source code
import { readFileSync } from 'fs'
import { join } from 'path'
// Read file relative to current module
const content = readFileSync(join(__dirname, 'data.json'), 'utf-8')
```
```ts
// tsdown config
export default defineConfig({
entry: ['src/index.ts'],
format: ['esm'],
shims: true, // Enables __dirname
})
```
## When to Use Shims
### Use `shims: true` when:
- ✅ Building Node.js tools/CLIs
- ✅ Code uses `__dirname` or `__filename`
- ✅ Need file system operations relative to module
- ✅ Migrating from CommonJS to ESM
- ✅ Need cross-format compatibility
### Don't need shims when:
- ❌ Browser-only code
- ❌ No file system operations
- ❌ Using only `import.meta.url`
- ❌ Pure ESM without CJS variables
## Performance Impact
### Runtime Overhead
Shims add minimal runtime overhead:
```js
// Added to output when shims enabled
import { fileURLToPath } from 'node:url'
import { dirname } from 'node:path'
const __filename = fileURLToPath(import.meta.url)
const __dirname = dirname(__filename)
```
### Tree Shaking
If `__dirname` or `__filename` are not used, they're automatically removed during bundling (no overhead).
## Platform Considerations
### Node.js Platform
```ts
export default defineConfig({
platform: 'node',
format: ['esm'],
shims: true, // Recommended for Node.js
})
```
- `require` shim added automatically
- `__dirname` and `__filename` available with `shims: true`
### Browser Platform
```ts
export default defineConfig({
platform: 'browser',
format: ['esm'],
shims: false, // Not needed for browser
})
```
- Shims not needed (no Node.js variables)
- Will cause warnings if Node.js APIs used
### Neutral Platform
```ts
export default defineConfig({
platform: 'neutral',
format: ['esm'],
shims: false, // Avoid platform-specific code
})
```
- Avoid shims for maximum portability
## CLI Examples
```bash
# Enable shims
tsdown --shims
# ESM with shims for Node.js
tsdown --format esm --platform node --shims
# Dual format with shims
tsdown --format esm --format cjs --shims
```
## Troubleshooting
### `__dirname is not defined`
Enable shims:
```ts
export default defineConfig({
shims: true,
})
```
### `require is not defined` in ESM
Automatic on Node.js platform. If not working:
```ts
export default defineConfig({
platform: 'node', // Ensure Node.js platform
})
```
### Import.meta not working in CJS
Automatic - no configuration needed. If still failing, check output format:
```ts
export default defineConfig({
format: ['cjs'], // Shims added automatically
})
```
## Tips
1. **Enable for Node.js tools** - Use `shims: true` for CLIs and servers
2. **Skip for browsers** - Not needed for browser code
3. **No overhead if unused** - Automatically tree-shaken
4. **Automatic require shim** - No config needed for `require` in ESM
5. **CJS shims automatic** - `import.meta.*` always available in CJS
## Related Options
- [Platform](option-platform.md) - Runtime environment
- [Output Format](option-output-format.md) - Module formats
- [Target](option-target.md) - Syntax transformations

View File

@@ -0,0 +1,301 @@
# Source Maps
Generate source maps for debugging bundled code.
## Overview
Source maps map minified/bundled code back to original source files, making debugging significantly easier by showing original line numbers and variable names.
## Basic Usage
### CLI
```bash
tsdown --sourcemap
# Or inline
tsdown --sourcemap inline
```
### Config File
```ts
export default defineConfig({
entry: ['src/index.ts'],
sourcemap: true,
})
```
## Source Map Types
### External (default)
Generates separate `.map` files:
```ts
export default defineConfig({
sourcemap: true, // or 'external'
})
```
**Output:**
- `dist/index.mjs`
- `dist/index.mjs.map`
**Pros:**
- Smaller bundle size
- Can be excluded from production
- Faster parsing
### Inline
Embeds source maps in the bundle:
```ts
export default defineConfig({
sourcemap: 'inline',
})
```
**Output:**
- `dist/index.mjs` (includes source map as data URL)
**Pros:**
- Single file deployment
- Guaranteed to be available
**Cons:**
- Larger bundle size
- Exposed in production
### Hidden
Generates map files without reference comment:
```ts
export default defineConfig({
sourcemap: 'hidden',
})
```
**Output:**
- `dist/index.mjs` (no `//# sourceMappingURL` comment)
- `dist/index.mjs.map`
**Use when:**
- You want maps for error reporting tools
- But don't want them exposed to users
## Auto-Enable Scenarios
### Declaration Maps
If `declarationMap` is enabled in `tsconfig.json`, source maps are automatically enabled:
```json
// tsconfig.json
{
"compilerOptions": {
"declarationMap": true
}
}
```
This also generates `.d.ts.map` files for TypeScript declarations.
## Common Patterns
### Development Build
```ts
export default defineConfig((options) => ({
entry: ['src/index.ts'],
sourcemap: options.watch, // Only in dev
minify: !options.watch,
}))
```
### Production with External Maps
```ts
export default defineConfig({
entry: ['src/index.ts'],
format: ['esm', 'cjs'],
sourcemap: true, // External maps
minify: true,
})
```
Deploy maps to separate error reporting service.
### Always Inline (Development Tool)
```ts
export default defineConfig({
entry: ['src/index.ts'],
format: ['esm'],
sourcemap: 'inline',
})
```
### Per-Format Source Maps
```ts
export default defineConfig({
entry: ['src/index.ts'],
format: {
esm: {
sourcemap: true,
},
iife: {
sourcemap: 'inline', // Inline for browser
},
},
})
```
### TypeScript Library with Declaration Maps
```ts
export default defineConfig({
entry: ['src/index.ts'],
format: ['esm', 'cjs'],
sourcemap: true,
dts: {
sourcemap: true, // Enable declaration maps
},
})
```
**Output:**
- `dist/index.mjs` + `dist/index.mjs.map`
- `dist/index.cjs` + `dist/index.cjs.map`
- `dist/index.d.ts` + `dist/index.d.ts.map`
## Benefits
### For Development
- **Faster debugging** - See original code in debugger
- **Better error messages** - Stack traces show original lines
- **Easier breakpoints** - Set breakpoints on source code
### For Production
- **Error reporting** - Send accurate error locations to services
- **Monitoring** - Track errors back to source
- **Support** - Help users report issues accurately
## Performance Impact
| Type | Bundle Size | Parse Speed | Debugging |
|------|-------------|-------------|-----------|
| None | Smallest | Fastest | Hard |
| External | Small | Fast | Easy |
| Inline | Largest | Slower | Easy |
| Hidden | Small | Fast | Tools only |
## CLI Examples
```bash
# Enable source maps
tsdown --sourcemap
# Inline source maps
tsdown --sourcemap inline
# Hidden source maps
tsdown --sourcemap hidden
# Development with source maps
tsdown --watch --sourcemap
# Production with external maps
tsdown --minify --sourcemap
# No source maps
tsdown --no-sourcemap
```
## Use Cases
### Local Development
```ts
export default defineConfig({
sourcemap: true,
minify: false,
})
```
### Production Build
```ts
export default defineConfig({
sourcemap: 'external', // Upload to error service
minify: true,
})
```
### Browser Library
```ts
export default defineConfig({
format: ['iife'],
platform: 'browser',
sourcemap: 'inline', // Self-contained
globalName: 'MyLib',
})
```
### Node.js CLI Tool
```ts
export default defineConfig({
format: ['esm'],
platform: 'node',
sourcemap: true,
shims: true,
})
```
## Troubleshooting
### Source Maps Not Working
1. **Check output** - Verify `.map` files are generated
2. **Check reference** - Look for `//# sourceMappingURL=` comment
3. **Check paths** - Ensure relative paths are correct
4. **Check tool** - Verify debugger/browser supports source maps
### Large Bundle Size
Use external source maps instead of inline:
```ts
export default defineConfig({
sourcemap: true, // Not 'inline'
})
```
### Source Not Found
- Ensure source files are accessible relative to map
- Check `sourceRoot` in generated map
- Verify paths in `sources` array
## Tips
1. **Use external maps** for production (smaller bundles)
2. **Use inline maps** for single-file tools
3. **Enable in development** for better DX
4. **Upload to error services** for production debugging
5. **Use hidden maps** when you want them for tools only
6. **Enable declaration maps** for TypeScript libraries
## Related Options
- [Minification](option-minification.md) - Code compression
- [DTS](option-dts.md) - TypeScript declarations
- [Watch Mode](option-watch-mode.md) - Development workflow
- [Target](option-target.md) - Syntax transformations

View File

@@ -0,0 +1,208 @@
# Target Environment
Configure JavaScript syntax transformations for target environments.
## Overview
The `target` option controls which JavaScript features are downleveled (transformed to older syntax) for compatibility.
**Important:** Only affects syntax transformations, not runtime polyfills.
## Default Behavior
tsdown auto-reads from `package.json`:
```json
// package.json
{
"engines": {
"node": ">=18.0.0"
}
}
```
Automatically sets `target` to `node18.0.0`.
If no `engines.node` field exists, behaves as if `target: false` (no transformations).
## Disabling Transformations
Set to `false` to preserve modern syntax:
```ts
export default defineConfig({
target: false,
})
```
**Result:**
- No JavaScript downleveling
- Modern features preserved (optional chaining `?.`, nullish coalescing `??`, etc.)
**Use when:**
- Targeting modern environments
- Handling transformations elsewhere
- Building libraries for further processing
## Setting Target
### CLI
```bash
# Single target
tsdown --target es2020
tsdown --target node20
# Multiple targets
tsdown --target chrome100 --target node20.18
# Disable
tsdown --no-target
```
### Config File
```ts
export default defineConfig({
entry: ['src/index.ts'],
target: 'es2020',
})
```
### Multiple Targets
```ts
export default defineConfig({
entry: ['src/index.ts'],
target: ['chrome100', 'safari15', 'node18'],
})
```
## Supported Targets
### ECMAScript Versions
- `es2015`, `es2016`, `es2017`, `es2018`, `es2019`, `es2020`, `es2021`, `es2022`, `es2023`, `esnext`
### Browser Versions
- `chrome100`, `safari18`, `firefox110`, `edge100`, etc.
### Node.js Versions
- `node16`, `node18`, `node20`, `node20.18`, etc.
## Examples
### Modern Browsers
```ts
export default defineConfig({
entry: ['src/index.ts'],
format: ['esm'],
target: ['chrome100', 'safari15', 'firefox100'],
})
```
### Node.js Library
```ts
export default defineConfig({
entry: ['src/index.ts'],
format: ['esm', 'cjs'],
target: 'node18',
})
```
### Legacy Support
```ts
export default defineConfig({
entry: ['src/index.ts'],
format: ['esm'],
target: 'es2015', // Maximum compatibility
})
```
### Per-Format Targets
```ts
export default defineConfig({
entry: ['src/index.ts'],
format: {
esm: {
target: 'es2020',
},
cjs: {
target: 'node16',
},
},
})
```
## Decorators
### Legacy Decorators (Stage 2)
Enable in `tsconfig.json`:
```json
{
"compilerOptions": {
"experimentalDecorators": true
}
}
```
### Stage 3 Decorators
**Not currently supported** by tsdown/Rolldown/Oxc.
See [oxc issue #9170](https://github.com/oxc-project/oxc/issues/9170).
## Common Patterns
### Universal Library
```ts
export default defineConfig({
entry: ['src/index.ts'],
format: ['esm', 'cjs'],
target: 'es2020', // Wide compatibility
})
```
### Modern-Only Library
```ts
export default defineConfig({
entry: ['src/index.ts'],
format: ['esm'],
target: false, // No transformations
})
```
### Browser Component
```ts
export default defineConfig({
entry: ['src/index.tsx'],
format: ['esm'],
target: ['chrome100', 'safari15', 'firefox100'],
platform: 'browser',
})
```
## Tips
1. **Let tsdown auto-detect** from package.json when possible
2. **Use `false`** for modern-only builds
3. **Specify multiple targets** for broader compatibility
4. **Use legacy decorators** with `experimentalDecorators`
6. **Test output** in target environments
## Related Options
- [Platform](option-platform.md) - Runtime environment
- [Output Format](option-output-format.md) - Module formats
- [Minification](option-minification.md) - Code optimization

View File

@@ -0,0 +1,335 @@
# Tree Shaking
Remove unused code from bundles.
## Overview
Tree shaking eliminates dead code (unused exports) from your final bundle, reducing size and improving performance.
**Default:** Enabled
## Basic Usage
### CLI
```bash
# Tree shaking enabled (default)
tsdown
# Disable tree shaking
tsdown --no-treeshake
```
### Config File
```ts
export default defineConfig({
entry: ['src/index.ts'],
treeshake: true, // Default
})
```
## How It Works
### With Tree Shaking
**Source:**
```ts
// src/util.ts
export function unused() {
console.log("I'm unused")
}
export function hello(x: number) {
console.log('Hello World', x)
}
// src/index.ts
import { hello } from './util'
hello(1)
```
**Output:**
```js
// dist/index.mjs
function hello(x) {
console.log('Hello World', x)
}
hello(1)
```
`unused()` function is removed because it's never imported.
### Without Tree Shaking
**Output:**
```js
// dist/index.mjs
function unused() {
console.log("I'm unused")
}
function hello(x) {
console.log('Hello World', x)
}
hello(1)
```
All code is included, even if unused.
## Advanced Configuration
### Enable (Default)
```ts
export default defineConfig({
treeshake: true,
})
```
Uses Rolldown's default tree shaking.
### Custom Options
```ts
export default defineConfig({
treeshake: {
moduleSideEffects: false,
propertyReadSideEffects: false,
unknownGlobalSideEffects: false,
},
})
```
See [Rolldown docs](https://rolldown.rs/reference/config-options#treeshake) for all options.
### Disable
```ts
export default defineConfig({
treeshake: false,
})
```
## Side Effects
### Package.json sideEffects
Declare side effects in your package:
```json
{
"sideEffects": false
}
```
Or specify files with side effects:
```json
{
"sideEffects": ["*.css", "src/polyfills.ts"]
}
```
### Module Side Effects
```ts
export default defineConfig({
treeshake: {
moduleSideEffects: (id) => {
// Preserve side effects for polyfills
return id.includes('polyfill')
},
},
})
```
## Common Patterns
### Production Build
```ts
export default defineConfig({
entry: ['src/index.ts'],
format: ['esm', 'cjs'],
treeshake: true,
minify: true,
})
```
### Development Build
```ts
export default defineConfig((options) => ({
entry: ['src/index.ts'],
treeshake: !options.watch, // Disable in dev
}))
```
### Library with Side Effects
```ts
export default defineConfig({
entry: ['src/index.ts'],
treeshake: {
moduleSideEffects: (id) => {
return (
id.includes('.css') ||
id.includes('polyfill') ||
id.includes('side-effect')
)
},
},
})
```
### Utilities Library
```ts
export default defineConfig({
entry: ['src/index.ts'],
format: ['esm'],
treeshake: true,
dts: true,
})
```
Users can import only what they need:
```ts
import { onlyWhatINeed } from 'my-utils'
```
## Benefits
### Smaller Bundles
- Only includes imported code
- Removes unused functions, classes, variables
- Reduces download size
### Better Performance
- Less code to parse
- Faster execution
- Improved loading times
### Cleaner Output
- No dead code in production
- Easier to debug
- Better maintainability
## When to Disable
### Debugging
During development to see all code:
```ts
export default defineConfig((options) => ({
treeshake: !options.watch,
}))
```
### Side Effect Code
Code with global side effects:
```ts
// This has side effects
window.myGlobal = {}
export function setup() {
// ...
}
```
Disable tree shaking or mark side effects:
```json
{
"sideEffects": true
}
```
### Testing
Include all code for coverage:
```ts
export default defineConfig({
treeshake: false,
})
```
## Tips
1. **Leave enabled** for production builds
2. **Mark side effects** in package.json
3. **Use with minification** for best results
4. **Test tree shaking** - verify unused code is removed
5. **Disable for debugging** if needed
6. **Pure functions** are easier to tree shake
## Troubleshooting
### Code Still Included
- Check for side effects
- Verify imports are ES modules
- Ensure code is actually unused
- Check `sideEffects` in package.json
### Missing Code at Runtime
- Code has side effects but marked as none
- Set `sideEffects: true` or list specific files
### Unexpected Behavior
- Module has side effects not declared
- Try disabling tree shaking to isolate issue
## Examples
### Pure Utility Functions
```ts
// utils.ts - perfect for tree shaking
export function add(a, b) {
return a + b
}
export function multiply(a, b) {
return a * b
}
// Only 'add' imported = only 'add' bundled
import { add } from './utils'
```
### With Side Effects
```ts
// polyfill.ts - has side effects
if (!Array.prototype.at) {
Array.prototype.at = function(index) {
// polyfill implementation
}
}
export {} // Need to export something
```
```json
{
"sideEffects": ["src/polyfill.ts"]
}
```
## Related Options
- [Minification](option-minification.md) - Code compression
- [Target](option-target.md) - Syntax transformations
- [Dependencies](option-dependencies.md) - External packages
- [Output Format](option-output-format.md) - Module formats

View File

@@ -0,0 +1,309 @@
# Unbundle Mode
Preserve source directory structure in output.
## Overview
Unbundle mode (also called "bundleless" or "transpile-only") outputs files that mirror your source structure, rather than bundling everything into single files. Each source file is compiled individually with a one-to-one mapping.
## Basic Usage
### CLI
```bash
tsdown --unbundle
```
### Config File
```ts
export default defineConfig({
entry: ['src/**/*.ts', '!**/*.test.ts'],
unbundle: true,
})
```
## How It Works
### Source Structure
```
src/
├── index.ts
├── utils/
│ ├── helper.ts
│ └── format.ts
└── components/
└── button.ts
```
### With Unbundle
**Config:**
```ts
export default defineConfig({
entry: ['src/index.ts'],
unbundle: true,
})
```
**Output:**
```
dist/
├── index.mjs
├── utils/
│ ├── helper.mjs
│ └── format.mjs
└── components/
└── button.mjs
```
All imported files are output individually, preserving structure.
### Without Unbundle (Default)
**Output:**
```
dist/
└── index.mjs (all code bundled together)
```
## When to Use
### Use Unbundle When:
✅ Building monorepo packages with shared utilities
✅ Users need to import individual modules
✅ Want clear source-to-output mapping
✅ Library with many independent utilities
✅ Debugging requires tracing specific files
✅ Incremental builds for faster development
### Use Standard Bundling When:
❌ Single entry point application
❌ Want to optimize bundle size
❌ Need aggressive tree shaking
❌ Creating IIFE/UMD bundles
❌ Deploying to browsers directly
## Common Patterns
### Utility Library
```ts
export default defineConfig({
entry: ['src/**/*.ts', '!**/*.test.ts'],
format: ['esm', 'cjs'],
unbundle: true,
dts: true,
})
```
**Benefits:**
- Users import only what they need
- Tree shaking still works at user's build
- Clear module boundaries
**Usage:**
```ts
// Users can import specific utilities
import { helper } from 'my-lib/utils/helper'
import { Button } from 'my-lib/components/button'
```
### Monorepo Shared Package
```ts
export default defineConfig({
entry: ['src/index.ts'],
format: ['esm'],
unbundle: true,
outDir: 'dist',
})
```
### TypeScript Compilation Only
```ts
export default defineConfig({
entry: ['src/**/*.ts'],
format: ['esm'],
unbundle: true,
minify: false,
treeshake: false,
dts: true,
})
```
Pure TypeScript to JavaScript transformation.
### Development Mode
```ts
export default defineConfig((options) => ({
entry: ['src/**/*.ts'],
unbundle: options.watch, // Unbundle in dev only
minify: !options.watch,
}))
```
Fast rebuilds during development, optimized for production.
## With Entry Patterns
### Include/Exclude
```ts
export default defineConfig({
entry: [
'src/**/*.ts',
'!**/*.test.ts',
'!**/*.spec.ts',
'!**/fixtures/**',
],
unbundle: true,
})
```
### Multiple Entry Points
```ts
export default defineConfig({
entry: {
index: 'src/index.ts',
cli: 'src/cli.ts',
},
unbundle: true,
})
```
Both entry files and all imports preserved.
## Output Control
### Custom Extension
```ts
export default defineConfig({
entry: ['src/**/*.ts'],
unbundle: true,
outExtensions: () => ({ js: '.js' }),
})
```
### Preserve Directory
```ts
export default defineConfig({
entry: ['src/**/*.ts'],
unbundle: true,
outDir: 'lib',
})
```
**Output:**
```
lib/
├── index.js
├── utils/
│ └── helper.js
└── components/
└── button.js
```
## Package.json Setup
```json
{
"name": "my-library",
"type": "module",
"main": "./dist/index.js",
"types": "./dist/index.d.ts",
"exports": {
".": "./dist/index.js",
"./utils/*": "./dist/utils/*.js",
"./components/*": "./dist/components/*.js"
},
"files": ["dist"]
}
```
Or use `exports: true` to auto-generate.
## Comparison
| Feature | Bundled | Unbundled |
|---------|---------|-----------|
| Output files | Few | Many |
| File size | Smaller | Larger |
| Build speed | Slower | Faster |
| Tree shaking | Build time | User's build |
| Source mapping | Complex | Simple |
| Module imports | Entry only | Any module |
| Dev rebuilds | Slower | Faster |
## Performance
### Build Speed
Unbundle is typically faster:
- No bundling overhead
- Parallel file processing
- Incremental builds possible
### Bundle Size
Unbundle produces larger output:
- Each file has its own overhead
- No cross-module optimizations
- User's bundler handles final optimization
## Tips
1. **Use with glob patterns** for multiple files
2. **Enable in development** for faster rebuilds
3. **Let users bundle** for production optimization
4. **Preserve structure** for utilities/components
5. **Combine with DTS** for type definitions
6. **Use with monorepos** for shared code
## Troubleshooting
### Too Many Files
- Adjust entry patterns
- Exclude unnecessary files
- Use specific entry points
### Missing Files
- Check entry patterns
- Verify files are imported
- Look for excluded patterns
### Import Paths Wrong
- Check relative paths
- Verify output structure
- Update package.json exports
## CLI Examples
```bash
# Enable unbundle
tsdown --unbundle
# With specific entry
tsdown src/**/*.ts --unbundle
# With other options
tsdown --unbundle --format esm --dts
```
## Related Options
- [Entry](option-entry.md) - Entry patterns
- [Output Directory](option-output-directory.md) - Output location
- [Output Format](option-output-format.md) - Module formats
- [DTS](option-dts.md) - Type declarations

View File

@@ -0,0 +1,261 @@
# Watch Mode
Automatically rebuild when files change.
## Overview
Watch mode monitors your source files and rebuilds automatically on changes, streamlining the development workflow.
## Basic Usage
### CLI
```bash
# Watch all project files
tsdown --watch
# Or use short flag
tsdown -w
# Watch specific directory
tsdown --watch ./src
# Watch specific file
tsdown --watch ./src/index.ts
```
### Config File
```ts
export default defineConfig({
entry: ['src/index.ts'],
watch: true,
})
```
## Watch Options
### Ignore Paths
Ignore specific paths in watch mode:
```bash
tsdown --watch --ignore-watch test --ignore-watch '**/*.test.ts'
```
```ts
export default defineConfig({
entry: ['src/index.ts'],
watch: {
exclude: ['test/**', '**/*.test.ts'],
},
})
```
### On Success Command
Run command after successful build:
```bash
tsdown --watch --on-success "echo Build complete!"
tsdown --watch --on-success "node dist/index.mjs"
```
```ts
export default defineConfig({
entry: ['src/index.ts'],
watch: true,
onSuccess: 'node dist/index.mjs',
})
```
## Watch Behavior
### Default Watch Targets
By default, tsdown watches:
- All entry files
- All imported files
- Config file (triggers restart)
### File Change Handling
- **Source files** - Incremental rebuild
- **Config file** - Full restart with cache clear
- **Dependencies** - Rebuild if imported
### Keyboard Shortcuts
During watch mode:
- `r` - Manual rebuild
- `q` - Quit watch mode
## Common Patterns
### Development Mode
```ts
export default defineConfig((options) => ({
entry: ['src/index.ts'],
format: ['esm'],
watch: options.watch,
sourcemap: options.watch,
minify: !options.watch,
}))
```
### With Post-Build Script
```ts
export default defineConfig({
entry: ['src/index.ts'],
watch: true,
onSuccess: 'npm run test',
})
```
### Multiple Entry Points
```ts
export default defineConfig({
entry: {
main: 'src/index.ts',
cli: 'src/cli.ts',
},
watch: true,
clean: false, // Don't clean on each rebuild
})
```
### Test Runner Integration
```bash
# Watch and run tests on change
tsdown --watch --on-success "vitest run"
# Watch and start dev server
tsdown --watch --on-success "node dist/server.mjs"
```
### Monorepo Package
```ts
export default defineConfig({
workspace: 'packages/*',
entry: ['src/index.ts'],
watch: true,
watch: {
exclude: ['**/test/**', '**/*.spec.ts'],
},
})
```
## Advanced Configuration
### Custom Watch Options
```ts
export default defineConfig({
entry: ['src/index.ts'],
watch: {
include: ['src/**'],
exclude: ['**/*.test.ts', '**/fixtures/**'],
skipWrite: false,
},
})
```
### Conditional Watch
```ts
export default defineConfig((options) => {
const isDev = options.watch
return {
entry: ['src/index.ts'],
format: ['esm'],
dts: !isDev, // Skip DTS in watch mode
sourcemap: isDev,
clean: !isDev,
}
})
```
## CLI Examples
```bash
# Basic watch
tsdown -w
# Watch with source maps
tsdown -w --sourcemap
# Watch without cleaning
tsdown -w --no-clean
# Watch and run on success
tsdown -w --on-success "npm test"
# Watch specific format
tsdown -w --format esm
# Watch with minification
tsdown -w --minify
# Watch and ignore test files
tsdown -w --ignore-watch '**/*.test.ts'
```
## Tips
1. **Use watch mode** for active development
2. **Skip DTS generation** in watch for faster rebuilds
3. **Disable clean** to avoid unnecessary file operations
4. **Use onSuccess** for post-build tasks
5. **Ignore test files** to avoid unnecessary rebuilds
6. **Use keyboard shortcuts** for manual control
## Troubleshooting
### Watch Not Detecting Changes
- Check file is in entry or imported chain
- Verify path is not in `exclude` patterns
- Ensure file system supports watching
### Too Many Rebuilds
Add ignore patterns:
```ts
export default defineConfig({
watch: {
exclude: [
'**/node_modules/**',
'**/.git/**',
'**/dist/**',
'**/*.test.ts',
],
},
})
```
### Slow Rebuilds
- Skip DTS in watch mode: `dts: !options.watch`
- Disable minification: `minify: false`
- Use smaller entry set during development
### Config Changes Not Applied
Config file changes trigger full restart automatically.
### Why Not Stub Mode?
tsdown does not support stub mode. Watch mode is the recommended alternative for rapid development, providing instant rebuilds without the drawbacks of stub mode.
## Related Options
- [On Success](reference-cli.md#on-success-command) - Post-build commands
- [Sourcemap](option-sourcemap.md) - Debug information
- [Clean](option-cleaning.md) - Output directory cleaning

View File

@@ -0,0 +1,320 @@
# 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
```bash
# Basic React library
npx create-tsdown@latest -t react
# With React Compiler
npx create-tsdown@latest -t react-compiler
```
## Basic Configuration
### Minimal Setup
```ts
// tsdown.config.ts
export default defineConfig({
entry: ['./src/index.ts'],
format: ['esm', 'cjs'],
platform: 'neutral',
external: ['react', 'react-dom'],
dts: true,
})
```
### Component Example
```tsx
// 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>
)
}
```
```ts
// src/index.ts
export { MyButton } from './MyButton'
```
## JSX Transform
### Automatic (Default)
Modern JSX transform (React 17+):
```ts
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:
```ts
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
```bash
pnpm add -D @rollup/plugin-babel babel-plugin-react-compiler
```
### Configure
```ts
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
```ts
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
```ts
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
```ts
export default defineConfig({
entry: ['src/index.ts'],
format: ['esm', 'cjs'],
platform: 'neutral',
external: ['react'], // Only React needed
dts: true,
treeshake: true,
})
```
### Monorepo React Packages
```ts
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
```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
```json
{
"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)
```ts
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:
```ts
external: ['react', 'react-dom', /^react\//]
```
### Type Errors with JSX
Check `tsconfig.json`:
```json
{
"compilerOptions": {
"jsx": "react-jsx" // or "react"
}
}
```
### Duplicate React
Add to external patterns:
```ts
external: [
'react',
'react-dom',
'react/jsx-runtime',
'react/jsx-dev-runtime',
]
```
## Related
- [Plugins](advanced-plugins.md) - Extend functionality
- [Dependencies](option-dependencies.md) - External packages
- [DTS](option-dts.md) - Type declarations
- [Vue Recipe](recipe-vue.md) - Vue component libraries

View File

@@ -0,0 +1,371 @@
# Vue Support
Build Vue component libraries with tsdown.
## Overview
tsdown provides first-class support for Vue libraries through integration with `unplugin-vue` and `rolldown-plugin-dts` for type generation.
## Quick Start
### Use Starter Template
```bash
npx create-tsdown@latest -t vue
```
## Basic Configuration
### Install Dependencies
```bash
pnpm add -D unplugin-vue vue-tsc
```
### Minimal Setup
```ts
// tsdown.config.ts
import { defineConfig } from 'tsdown'
import Vue from 'unplugin-vue/rolldown'
export default defineConfig({
entry: ['./src/index.ts'],
format: ['esm', 'cjs'],
platform: 'neutral',
external: ['vue'],
plugins: [
Vue({ isProduction: true }),
],
dts: {
vue: true, // Enable Vue type generation
},
})
```
## How It Works
### unplugin-vue
Compiles `.vue` single-file components:
- Transforms template to render functions
- Handles scoped styles
- Processes script setup
### vue-tsc
Generates TypeScript declarations:
- Type-checks Vue components
- Creates `.d.ts` files
- Preserves component props types
- Exports component types
## Component Example
### Single File Component
```vue
<!-- src/Button.vue -->
<script setup lang="ts">
interface Props {
type?: 'primary' | 'secondary'
disabled?: boolean
}
defineProps<Props>()
defineEmits<{
click: []
}>()
</script>
<template>
<button
:class="['btn', `btn-${type}`]"
:disabled="disabled"
@click="$emit('click')"
>
<slot />
</button>
</template>
<style scoped>
.btn {
padding: 8px 16px;
border-radius: 4px;
}
.btn-primary {
background: blue;
color: white;
}
</style>
```
### Export Components
```ts
// src/index.ts
export { default as Button } from './Button.vue'
export { default as Input } from './Input.vue'
export { default as Modal } from './Modal.vue'
// Re-export types
export type { ButtonProps } from './Button.vue'
```
## Common Patterns
### Component Library
```ts
export default defineConfig({
entry: ['src/index.ts'],
format: ['esm', 'cjs'],
platform: 'neutral',
external: ['vue'],
plugins: [
Vue({
isProduction: true,
style: {
trim: true,
},
}),
],
dts: {
vue: true,
},
clean: true,
})
```
### Multiple Components
```ts
export default defineConfig({
entry: {
index: 'src/index.ts',
Button: 'src/Button.vue',
Input: 'src/Input.vue',
Modal: 'src/Modal.vue',
},
format: ['esm', 'cjs'],
external: ['vue'],
plugins: [Vue({ isProduction: true })],
dts: { vue: true },
})
```
### With Composition Utilities
```ts
// src/composables/useCounter.ts
import { ref } from 'vue'
export function useCounter(initial = 0) {
const count = ref(initial)
const increment = () => count.value++
const decrement = () => count.value--
return { count, increment, decrement }
}
```
```ts
export default defineConfig({
entry: ['src/index.ts'],
format: ['esm', 'cjs'],
external: ['vue'],
plugins: [Vue({ isProduction: true })],
dts: { vue: true },
})
```
### TypeScript Configuration
```json
// tsconfig.json
{
"compilerOptions": {
"target": "ES2020",
"module": "ESNext",
"lib": ["ES2020", "DOM", "DOM.Iterable"],
"jsx": "preserve",
"moduleResolution": "bundler",
"allowImportingTsExtensions": true,
"strict": true,
"isolatedDeclarations": true,
"skipLibCheck": true
},
"include": ["src"],
"exclude": ["node_modules", "dist"]
}
```
### Package.json Configuration
```json
{
"name": "my-vue-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": {
"vue": "^3.0.0"
},
"devDependencies": {
"tsdown": "^0.9.0",
"typescript": "^5.0.0",
"unplugin-vue": "^5.0.0",
"vue": "^3.4.0",
"vue-tsc": "^2.0.0"
}
}
```
## Advanced Patterns
### With Vite Plugins
Some Vite Vue plugins may work:
```ts
import Vue from 'unplugin-vue/rolldown'
import Components from 'unplugin-vue-components/rolldown'
export default defineConfig({
entry: ['src/index.ts'],
external: ['vue'],
plugins: [
Vue({ isProduction: true }),
Components({
dts: 'src/components.d.ts',
}),
],
dts: { vue: true },
})
```
### JSX Support
```ts
export default defineConfig({
entry: ['src/index.ts'],
format: ['esm', 'cjs'],
external: ['vue'],
plugins: [
Vue({
isProduction: true,
script: {
propsDestructure: true,
},
}),
],
inputOptions: {
transform: {
jsx: 'automatic',
jsxImportSource: 'vue',
},
},
dts: { vue: true },
})
```
### Monorepo Vue Packages
```ts
export default defineConfig({
workspace: 'packages/*',
entry: ['src/index.ts'],
format: ['esm', 'cjs'],
external: ['vue', /^@mycompany\//],
plugins: [Vue({ isProduction: true })],
dts: { vue: true },
})
```
## Plugin Options
### unplugin-vue Options
```ts
Vue({
isProduction: true,
script: {
defineModel: true,
propsDestructure: true,
},
style: {
trim: true,
},
template: {
compilerOptions: {
isCustomElement: (tag) => tag.startsWith('custom-'),
},
},
})
```
## Tips
1. **Always externalize Vue** - Don't bundle Vue itself
2. **Enable vue: true in dts** - For proper type generation
3. **Use platform: 'neutral'** - Maximum compatibility
4. **Install vue-tsc** - Required for type generation
5. **Set isProduction: true** - Optimize for production
6. **Add peer dependency** - Vue as peer dependency
## Troubleshooting
### Type Generation Fails
Ensure vue-tsc is installed:
```bash
pnpm add -D vue-tsc
```
Enable in config:
```ts
dts: { vue: true }
```
### Component Types Missing
Check TypeScript config:
```json
{
"compilerOptions": {
"jsx": "preserve",
"moduleResolution": "bundler"
}
}
```
### Vue Not Externalized
Add to external:
```ts
external: ['vue']
```
### SFC Compilation Errors
Check unplugin-vue version:
```bash
pnpm add -D unplugin-vue@latest
```
## Related
- [Plugins](advanced-plugins.md) - Plugin system
- [Dependencies](option-dependencies.md) - External packages
- [DTS](option-dts.md) - Type declarations
- [React Recipe](recipe-react.md) - React component libraries

View File

@@ -0,0 +1,125 @@
# WASM Support
Bundle WebAssembly modules in your TypeScript/JavaScript project.
## Overview
tsdown supports WASM through [`rolldown-plugin-wasm`](https://github.com/sxzz/rolldown-plugin-wasm), enabling direct `.wasm` imports with synchronous and asynchronous instantiation.
## Setup
### Install
```bash
pnpm add -D rolldown-plugin-wasm
```
### Configure
```ts
import { wasm } from 'rolldown-plugin-wasm'
import { defineConfig } from 'tsdown'
export default defineConfig({
entry: ['./src/index.ts'],
plugins: [wasm()],
})
```
### TypeScript Support
Add type declarations to `tsconfig.json`:
```jsonc
{
"compilerOptions": {
"types": ["rolldown-plugin-wasm/types"]
}
}
```
## Importing WASM Modules
### Direct Import
```ts
import { add } from './add.wasm'
add(1, 2)
```
### Async Init
Use `?init` query for async initialization:
```ts
import init from './add.wasm?init'
const instance = await init(imports) // imports optional
instance.exports.add(1, 2)
```
### Sync Init
Use `?init&sync` query for synchronous initialization:
```ts
import initSync from './add.wasm?init&sync'
const instance = initSync(imports) // imports optional
instance.exports.add(1, 2)
```
## wasm-bindgen Support
### Target `bundler` (Recommended)
```ts
import { add } from 'some-pkg'
add(1, 2)
```
### Target `web` (Node.js)
```ts
import { readFile } from 'node:fs/promises'
import init, { add } from 'some-pkg'
import wasmUrl from 'some-pkg/add_bg.wasm?url'
await init({
module_or_path: readFile(new URL(wasmUrl, import.meta.url)),
})
add(1, 2)
```
### Target `web` (Browser)
```ts
import init, { add } from 'some-pkg/add.js'
import wasmUrl from 'some-pkg/add_bg.wasm?url'
await init({ module_or_path: wasmUrl })
add(1, 2)
```
`nodejs` and `no-modules` wasm-bindgen targets are not supported.
## Plugin Options
```ts
wasm({
maxFileSize: 14 * 1024, // Max size for inline (default: 14KB)
fileName: '[hash][extname]', // Output file name pattern
publicPath: '', // Prefix for non-inlined file paths
targetEnv: 'auto', // 'auto' | 'auto-inline' | 'browser' | 'node'
})
```
| Option | Default | Description |
|--------|---------|-------------|
| `maxFileSize` | `14 * 1024` | Max file size for inlining. Set to `0` to always copy. |
| `fileName` | `'[hash][extname]'` | Pattern for emitted WASM files |
| `publicPath` | — | Prefix for non-inlined WASM file paths |
| `targetEnv` | `'auto'` | `'auto'` detects at runtime; `'browser'` omits Node builtins; `'node'` omits fetch |
## Related Options
- [Plugins](advanced-plugins.md) - Plugin system overview
- [Platform](option-platform.md) - Target platform configuration

View File

@@ -0,0 +1,395 @@
# CLI Reference
Complete reference for tsdown command-line interface.
## Overview
All CLI flags can also be set in the config file. CLI flags override config file options.
## Flag Patterns
CLI flag mapping rules:
- `--foo` sets `foo: true`
- `--no-foo` sets `foo: false`
- `--foo.bar` sets `foo: { bar: true }`
- `--format esm --format cjs` sets `format: ['esm', 'cjs']`
CLI flags support both camelCase and kebab-case. For example, `--outDir` and `--out-dir` are equivalent.
## Basic Commands
### Build
```bash
# Build with default config
tsdown
# Build specific files
tsdown src/index.ts src/cli.ts
# Build with watch mode
tsdown --watch
```
## Configuration
### `--config, -c <filename>`
Specify custom config file:
```bash
tsdown --config build.config.ts
tsdown -c custom-config.js
```
### `--no-config`
Disable config file loading:
```bash
tsdown --no-config src/index.ts
```
### `--config-loader <loader>`
Choose config loader (`auto`, `native`, `unrun`):
```bash
tsdown --config-loader unrun
```
### `--tsconfig <file>`
Specify TypeScript config file:
```bash
tsdown --tsconfig tsconfig.build.json
```
## Entry Points
### `[...files]`
Specify entry files as arguments:
```bash
tsdown src/index.ts src/utils.ts
```
## Output Options
### `--format <format>`
Output format (`esm`, `cjs`, `iife`, `umd`):
```bash
tsdown --format esm
tsdown --format esm --format cjs
```
### `--out-dir, -d <dir>`
Output directory:
```bash
tsdown --out-dir lib
tsdown -d dist
```
### `--dts`
Generate TypeScript declarations:
```bash
tsdown --dts
```
### `--clean`
Clean output directory before build:
```bash
tsdown --clean
```
## Build Options
### `--target <target>`
JavaScript target version:
```bash
tsdown --target es2020
tsdown --target node18
tsdown --target chrome100
tsdown --no-target # Disable transformations
```
### `--platform <platform>`
Target platform (`node`, `browser`, `neutral`):
```bash
tsdown --platform node
tsdown --platform browser
```
### `--minify`
Enable minification:
```bash
tsdown --minify
tsdown --no-minify
```
### `--sourcemap`
Generate source maps:
```bash
tsdown --sourcemap
tsdown --sourcemap inline
```
### `--treeshake`
Enable/disable tree shaking:
```bash
tsdown --treeshake
tsdown --no-treeshake
```
## Dependencies
### `--external <module>`
Mark module as external (not bundled):
```bash
tsdown --external react --external react-dom
```
### `--shims`
Add ESM/CJS compatibility shims:
```bash
tsdown --shims
```
## Development
### `--watch, -w [path]`
Enable watch mode:
```bash
tsdown --watch
tsdown -w
tsdown --watch src # Watch specific directory
```
### `--ignore-watch <path>`
Ignore paths in watch mode:
```bash
tsdown --watch --ignore-watch test
```
### `--on-success <command>`
Run command after successful build:
```bash
tsdown --watch --on-success "echo Build complete!"
```
## Environment Variables
### `--env.* <value>`
Set compile-time environment variables:
```bash
tsdown --env.NODE_ENV=production --env.API_URL=https://api.example.com
```
Access as `import.meta.env.*` or `process.env.*`.
### `--env-file <file>`
Load environment variables from file:
```bash
tsdown --env-file .env.production
```
### `--env-prefix <prefix>`
Filter environment variables by prefix (default: `TSDOWN_`):
```bash
tsdown --env-file .env --env-prefix APP_ --env-prefix TSDOWN_
```
## Assets
### `--copy <dir>`
Copy directory to output:
```bash
tsdown --copy public
tsdown --copy assets --copy static
```
## Package Management
### `--exports`
Auto-generate package.json exports field:
```bash
tsdown --exports
```
### `--publint`
Enable package validation:
```bash
tsdown --publint
```
### `--attw`
Enable "Are the types wrong" validation:
```bash
tsdown --attw
```
### `--unused`
Check for unused dependencies:
```bash
tsdown --unused
```
## Logging
### `--log-level <level>`
Set logging verbosity (`silent`, `error`, `warn`, `info`):
```bash
tsdown --log-level error
tsdown --log-level warn
```
### `--report` / `--no-report`
Enable/disable build report:
```bash
tsdown --no-report # Disable size report
tsdown --report # Enable (default)
```
### `--debug [feat]`
Show debug logs:
```bash
tsdown --debug
tsdown --debug rolldown # Debug specific feature
```
## Integration
### `--from-vite [vitest]`
Extend Vite or Vitest config:
```bash
tsdown --from-vite # Use vite.config.*
tsdown --from-vite vitest # Use vitest.config.*
```
## Common Usage Patterns
### Basic Build
```bash
tsdown
```
### Library (ESM + CJS + Types)
```bash
tsdown --format esm --format cjs --dts --clean
```
### Production Build
```bash
tsdown --minify --clean --no-report
```
### Development (Watch)
```bash
tsdown --watch --sourcemap
```
### Browser Bundle (IIFE)
```bash
tsdown --format iife --platform browser --minify
```
### Node.js CLI Tool
```bash
tsdown --format esm --platform node --shims
```
### Monorepo Package
```bash
tsdown --clean --dts --exports --publint
```
### With Environment Variables
```bash
tsdown --env-file .env.production --env.BUILD_TIME=$(date +%s)
```
### Copy Assets
```bash
tsdown --copy public --copy assets --clean
```
## Tips
1. **Use config file** for complex setups
2. **CLI flags override** config file options
3. **Chain multiple formats** for multi-target builds
4. **Use --clean** to avoid stale files
5. **Enable --dts** for TypeScript libraries
6. **Use --watch** during development
7. **Add --on-success** for post-build tasks
8. **Use --exports** to auto-generate package.json fields
## Related Documentation
- [Config File](option-config-file.md) - Configuration file options
- [Entry](option-entry.md) - Entry point configuration
- [Output Format](option-output-format.md) - Format options
- [Watch Mode](option-watch-mode.md) - Watch mode details