Files
stack/packages/mosaic/framework/skills/tsdown/references/advanced-programmatic.md
T
fargo 1a822493ba format: apply repo prettier (3.8.1) to the folded skills tree
963 markdown files reformatted with the repository's pinned prettier so
pnpm format:check covers the folded tree like every other repo file.

The formatter's embedded-language pass also normalized code fences
(TS semicolons, closed HTML tags in examples, lowercased CSS hex colors,
one renumbered list that skipped an index). Alphanumeric token deltas vs
the fold commit were audited file-by-file; all are formatter-equivalent
markup normalizations plus the four sanitized skills.
2026-08-19 14:37:17 -05:00

6.0 KiB

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

import { build } from 'tsdown';

await build({
  entry: ['src/index.ts'],
  format: ['esm', 'cjs'],
  dts: true,
});

With Options

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.

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:

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 for all options.

Common Patterns

Custom Build Script

// 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:

tsx scripts/build.ts

Multiple Builds

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

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

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

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

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:

// Use CLI for watch mode
import { spawn } from 'child_process';

spawn('tsdown', ['--watch'], {
  stdio: 'inherit',
  shell: true,
});

Integration Examples

With Task Runner

// 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

// 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

// .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

// 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:

pnpm add -D tsdown

Type Errors

Import types:

import type { UserConfig } from 'tsdown';

Build Fails Silently

Add error handling:

try {
  await build(config);
} catch (error) {
  console.error(error);
  process.exit(1);
}

Options Not Working

Check spelling and types:

// ✅ Correct
{
  format: ['esm', 'cjs'];
}

// ❌ Wrong
{
  formats: ['esm', 'cjs'];
}