# 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
