tsup の使い方完全ガイド — TypeScriptライブラリを設定なしでバンドル
一言でいうと
tsup は、esbuild をベースにした TypeScript ライブラリ向けのバンドルツールです。設定ファイルなし(ゼロコンフィグ)で .ts / .tsx ファイルを高速にバンドルし、ESM / CJS / IIFE 形式で出力できます。
⚠️ 重要な注意(2025年時点) tsup は公式にメンテナンス終了が宣言されています。新規プロジェクトでは後継の tsdown への移行が推奨されています。ただし、既存プロジェクトで広く使われており、動作自体に問題はないため、本記事では tsup v8.5.1 を基に解説します。
どんな時に使う?
- npm パッケージ(ライブラリ)の公開 — ESM と CJS の両方を同時に出力し、
package.jsonのexportsフィールドに対応したビルドを簡単に構築できます。 - CLI ツールのバンドル — エントリポイントを指定するだけで、依存関係を解決した単一ファイルの CLI バイナリを生成できます。
- モノレポ内の共有パッケージのビルド — 設定が最小限で済むため、複数パッケージのビルドパイプラインを統一的に管理できます。
インストール
# npm
npm install tsup -D
# yarn
yarn add tsup --dev
# pnpm
pnpm add tsup -D
TypeScript がプロジェクトにインストールされていない場合は、併せてインストールしてください。
npm install typescript -D
基本的な使い方
最小構成でのバンドル
npx tsup src/index.ts
これだけで dist/index.js(CJS 形式)が生成されます。
package.json にスクリプトを追加
{
"name": "my-library",
"scripts": {
"build": "tsup src/index.ts --format cjs,esm --dts",
"dev": "tsup src/index.ts --format cjs,esm --dts --watch"
}
}
設定ファイルを使う(推奨)
プロジェクトルートに tsup.config.ts を作成します。
// tsup.config.ts
import { defineConfig } from 'tsup'
export default defineConfig({
entry: ['src/index.ts'],
format: ['cjs', 'esm'],
dts: true,
splitting: true,
sourcemap: true,
clean: true,
})
npx tsup
設定ファイルがあれば、引数なしで tsup を実行するだけでビルドが走ります。
出力される package.json の設定例
{
"name": "my-library",
"version": "1.0.0",
"main": "./dist/index.js",
"module": "./dist/index.mjs",
"types": "./dist/index.d.ts",
"exports": {
".": {
"import": "./dist/index.mjs",
"require": "./dist/index.js",
"types": "./dist/index.d.ts"
}
},
"files": ["dist"]
}
よく使う API・オプション
1. format — 出力フォーマットの指定
CJS・ESM・IIFE の3形式をサポートしています。
import { defineConfig } from 'tsup'
export default defineConfig({
entry: ['src/index.ts'],
format: ['cjs', 'esm', 'iife'],
})
| format | 出力拡張子 | 用途 |
|---|---|---|
cjs | .js | Node.js (CommonJS) |
esm | .mjs | Node.js / ブラウザ (ES Modules) |
iife | .global.js | ブラウザ <script> タグ |
2. dts — TypeScript 型定義ファイルの生成
import { defineConfig } from 'tsup'
export default defineConfig({
entry: ['src/index.ts'],
format: ['esm'],
dts: true, // .d.ts / .d.mts を自動生成
})
型定義の生成だけを別プロセスで行いたい場合は --dts-only フラグも使えます。
npx tsup src/index.ts --dts-only
3. entry — 複数エントリポイントとグロブ
import { defineConfig } from 'tsup'
export default defineConfig({
// 配列で複数指定
entry: ['src/index.ts', 'src/cli.ts'],
// オブジェクト形式で出力名を制御
// entry: {
// index: 'src/index.ts',
// cli: 'src/cli.ts',
// },
format: ['cjs', 'esm'],
})
グロブパターンも使用可能です。
export default defineConfig({
entry: ['src/**/*.ts'],
format: ['esm'],
})
4. external / noExternal — 依存関係のバンドル制御
デフォルトでは dependencies と peerDependencies に記載されたパッケージは外部モジュール扱い(バンドルしない)になります。
import { defineConfig } from 'tsup'
export default defineConfig({
entry: ['src/index.ts'],
format: ['esm'],
// 明示的に外部化
external: ['react', 'react-dom'],
// 逆に、特定のパッケージを強制的にバンドルに含める
noExternal: ['lodash-es'],
})
5. onSuccess — ビルド成功後のフック
ビルド完了後にコマンドを実行できます。開発時のサーバー再起動などに便利です。
import { defineConfig } from 'tsup'
export default defineConfig({
entry: ['src/index.ts'],
format: ['esm'],
onSuccess: 'node dist/index.mjs',
// async 関数も指定可能
// onSuccess: async () => {
// console.log('Build succeeded!')
// },
})
watch モードと組み合わせると、ファイル変更 → ビルド → 自動実行のサイクルが回ります。
npx tsup --watch
類似パッケージとの比較
| 特徴 | tsup | tsdown | unbuild | rollup + plugins | tsc (単体) |
|---|---|---|---|---|---|
| ベースエンジン | esbuild | rolldown | rollup + esbuild | rollup | TypeScript compiler |
| ゼロコンフィグ | ✅ | ✅ | ✅ | ❌ | ✅ |
| ビルド速度 | ⚡ 非常に速い | ⚡ 非常に速い | 🔶 速い | 🔶 普通 | 🐢 遅い |
| 型定義生成 | ✅ | ✅ | ✅ | 要プラグイン | ✅(本業) |
| ESM + CJS 同時出力 | ✅ | ✅ | ✅ | ✅ | 手動設定 |
| Tree Shaking | ✅ | ✅ | ✅ | ✅ | ❌ |
| メンテナンス状況 | ⚠️ 終了宣言 | ✅ 活発 | ✅ 活発 | ✅ 活発 | ✅ 活発 |
新規プロジェクトでの推奨: tsup の後継である tsdown が最有力候補です。API が tsup と非常に似ているため、移行コストも低いです。
注意点・Tips
1. dts 生成は esbuild ではなく TypeScript コンパイラで行われる
バンドル自体は esbuild で高速に処理されますが、dts: true を指定した場合の型定義生成は TypeScript の API を使います。そのため、大規模プロジェクトでは型定義の生成がボトルネックになることがあります。
// 型定義の生成を並列実行にする(デフォルト動作)
export default defineConfig({
dts: true, // バンドルと並列で .d.ts を生成
})
ビルド時間が問題になる場合は、tsc --emitDeclarationOnly を別ステップで実行する運用も検討してください。
2. target の指定を忘れない
esbuild のデフォルトターゲットは esnext です。古い Node.js バージョンをサポートする場合は明示的に指定しましょう。
export default defineConfig({
entry: ['src/index.ts'],
target: 'node18',
format: ['cjs', 'esm'],
})
3. splitting は ESM 形式でのみ有効
コード分割(splitting: true)は ESM 出力でのみ動作します。CJS 形式では無視されます。
export default defineConfig({
entry: ['src/index.ts', 'src/utils.ts'],
format: ['esm'],
splitting: true, // 共通コードを別チャンクに分離
})
4. clean オプションで古い出力を削除
ビルド前に dist ディレクトリを自動クリーンアップできます。CI/CD 環境では必ず有効にしておくのがおすすめです。
export default defineConfig({
clean: true,
})
5. 環境変数の注入
export default defineConfig({
define: {
'process.env.NODE_ENV': JSON.stringify('production'),
},
env: {
API_URL: 'https://api.example.com',
},
})
env で指定した値は process.env.API_URL としてコード内で参照できます。
6. tsup.config.ts で条件分岐
defineConfig にはコールバック形式もあり、ビルドオプション(--watch かどうかなど)に応じて設定を切り替えられます。
import { defineConfig } from 'tsup'
export default defineConfig((options) => ({
entry: ['src/index.ts'],
format: ['cjs', 'esm'],
dts: true,
sourcemap: true,
minify: !options.watch, // watch モードではミニファイしない
clean: true,
}))
まとめ
tsup は「TypeScript ライブラリのバンドルをとにかく手軽に始めたい」というニーズに対する最適解として、長く支持されてきたツールです。esbuild による高速ビルド、ESM/CJS の同時出力、型定義の自動生成といった機能がゼロコンフィグで手に入る点は、今なお大きな魅力です。
ただし、公式にメンテナンス終了が宣言されているため、新規プロジェクトでは後継の tsdown を第一候補として検討してください。既存プロジェクトについても、移行ガイドを参照しながら段階的に移行を進めることをおすすめします。