tsup для TypeScript: полное руководство с примерами
1. Что это и зачем нужна
tsup — это современный, быстрый и простой в использовании сборщик (bundler) для TypeScript, созданный на основе esbuild. Его основная задача — собрать вашу TypeScript библиотеку в один или несколько файлов, готовых к публикации в npm или использованию в других проектах. В отличие от сложных конфигураций Webpack или Rollup, tsup предлагает конфигурацию "из коробки" с нулевой настройкой для большинства случаев.
Зачем нужен tsup? При разработке библиотек на TypeScript вы сталкиваетесь с несколькими проблемами: нужно скомпилировать TypeScript в JavaScript, сгенерировать декларации типов (.d.ts), объединить множество файлов в один (bundle) для удобства использования, и сделать это для разных форматов модулей (CommonJS, ESM). tsup решает все эти задачи одной командой. Он автоматически обрабатывает импорты, минифицирует код (опционально), генерирует source maps и поддерживает tree-shaking.
tsup идеально подходит для: создания npm-пакетов, утилитарных библиотек, React/Vue компонентов, API-клиентов и любых других проектов, где нужна быстрая и простая сборка TypeScript. Благодаря использованию esbuild, tsup работает в 10-100 раз быстрее традиционных сборщиков, что особенно заметно на больших проектах.
2. Установка
tsup устанавливается через npm или yarn как dev-зависимость:
# npm
npm install --save-dev tsup
# yarn
yarn add --dev tsup
# pnpm
pnpm add --save-dev tsup
После установки вы можете запускать tsup через npx или добавить скрипт в package.json.
3. Быстрый старт — минимальный рабочий пример
Создадим простую библиотеку и соберём её с помощью tsup.
Шаг 1: Создайте файл src/index.ts:
// src/index.ts
export function greet(name: string): string {
return `Hello, ${name}! Welcome to tsup.`;
}
export function add(a: number, b: number): number {
return a + b;
}
Шаг 2: Создайте файл конфигурации tsup.config.ts (или используйте аргументы командной строки):
// tsup.config.ts
import { defineConfig } from 'tsup';
export default defineConfig({
entry: ['src/index.ts'], // точка входа
format: ['cjs', 'esm'], // форматы вывода
dts: true, // генерировать .d.ts файлы
splitting: false, // не разделять на чанки
sourcemap: true, // генерировать source maps
clean: true, // очищать папку dist перед сборкой
});
Шаг 3: Добавьте скрипт в package.json:
{
"scripts": {
"build": "tsup"
}
}
Шаг 4: Запустите сборку:
npm run build
Результат появится в папке dist/:
dist/
├── index.js (CommonJS)
├── index.mjs (ESM)
├── index.d.ts (декларации типов)
├── index.d.mts (декларации для ESM)
└── index.js.map (source map)
4. Основные методы/функции/классы
В tsup нет классов в традиционном понимании. Основной API — это функция defineConfig и объект конфигурации. Рассмотрим 8 ключевых опций конфигурации.
4.1. entry
Сигнатура: entry: string | string[] | Record<string, string>
Что делает: Определяет точки входа для сборки. Можно указать один файл, массив файлов или объект для создания нескольких выходных файлов.
import { defineConfig } from 'tsup';
export default defineConfig({
// Одна точка входа
entry: ['src/index.ts'],
// Несколько точек входа
entry: ['src/index.ts', 'src/cli.ts'],
// Объект для кастомных имён выходных файлов
entry: {
main: 'src/index.ts',
utils: 'src/utils/index.ts',
},
});
4.2. format
Сигнатура: format: ('cjs' | 'esm' | 'iife')[]
Что делает: Определяет форматы модулей для выходных файлов. cjs — CommonJS, esm — ES Modules, iife — для браузера.
import { defineConfig } from 'tsup';
export default defineConfig({
entry: ['src/index.ts'],
format: ['cjs', 'esm'], // Создаст и .js, и .mjs
});
4.3. dts
Сигнатура: dts: boolean | { entry?: string; compilerOptions?: object }
Что делает: Включает генерацию файлов деклараций типов (.d.ts). Это критически важно для TypeScript библиотек.
import { defineConfig } from 'tsup';
export default defineConfig({
entry: ['src/index.ts'],
dts: true, // Просто включить
// Или с кастомными настройками:
dts: {
entry: 'src/index.ts',
compilerOptions: {
strict: true,
},
},
});
4.4. splitting
Сигнатура: splitting: boolean
Что делает: Включает разделение кода на чанки (code splitting). Полезно для больших библиотек, чтобы уменьшить размер первоначальной загрузки.
import { defineConfig } from 'tsup';
export default defineConfig({
entry: ['src/index.ts'],
splitting: true, // Включить code splitting
format: 'esm', // Работает только с ESM
});
4.5. sourcemap
Сигнатура: sourcemap: boolean | 'inline' | 'external'
Что делает: Генерирует source maps для отладки. true — внешние файлы, 'inline' — встраивает в код.
import { defineConfig } from 'tsup';
export default defineConfig({
entry: ['src/index.ts'],
sourcemap: true, // Внешние .map файлы
// sourcemap: 'inline', // Встроенные source maps
});
4.6. minify
Сигнатура: minify: boolean | 'terser' | 'esbuild'
Что делает: Минифицирует выходной код. По умолчанию использует esbuild, можно указать 'terser' для более агрессивной минификации.
import { defineConfig } from 'tsup';
export default defineConfig({
entry: ['src/index.ts'],
minify: true, // Использует esbuild
// minify: 'terser', // Использует Terser (медленнее, но лучше сжимает)
});
4.7. external
Сигнатура: external: string[]
Что делает: Исключает указанные зависимости из сборки. Полезно для peer dependencies или больших библиотек, которые пользователь установит сам.
import { defineConfig } from 'tsup';
export default defineConfig({
entry: ['src/index.ts'],
external: ['react', 'react-dom', 'lodash'], // Не включать в бандл
});
4.8. clean
Сигнатура: clean: boolean
Что делает: Очищает выходную директорию перед каждой сборкой. Предотвращает накопление старых файлов.
import { defineConfig } from 'tsup';
export default defineConfig({
entry: ['src/index.ts'],
clean: true, // Удалить dist/ перед сборкой
});
5. Реальный практический пример (100-200 строк кода)
Создадим полноценную библиотеку для работы с датами и строками, соберём её с помощью tsup и опубликуем.
Структура проекта:
my-ts-lib/
├── src/
│ ├── index.ts
│ ├── date-helpers.ts
│ └── string-helpers.ts
├── tsup.config.ts
├── package.json
└── tsconfig.json
1. src/date-helpers.ts — утилиты для дат:
// src/date-helpers.ts
export function formatDate(date: Date, format: string = 'YYYY-MM-DD'): string {
const map: Record = {
'YYYY': date.getFullYear(),
'MM': date.getMonth() + 1,
'DD': date.getDate(),
'HH': date.getHours(),
'mm': date.getMinutes(),
'ss': date.getSeconds(),
};
let result = format;
for (const [key, value] of Object.entries(map)) {
result = result.replace(key, String(value).padStart(2, '0'));
}
return result;
}
export function daysBetween(date1: Date, date2: Date): number {
const diff = Math.abs(date2.getTime() - date1.getTime());
return Math.ceil(diff / (1000 * 60 * 60 * 24));
}
export function isWeekend(date: Date): boolean {
const day = date.getDay();
return day === 0 || day === 6;
}
2. src/string-helpers.ts — утилиты для строк:
// src/string-helpers.ts
export function capitalize(str: string): string {
if (!str) return str;
return str.charAt(0).toUpperCase() + str.slice(1).toLowerCase();
}
export function truncate(str: string, maxLength: number, suffix: string = '...'): string {
if (str.length <= maxLength) return str;
return str.slice(0, maxLength - suffix.length) + suffix;
}
export function slugify(str: string): string {
return str
.toLowerCase()
.trim()
.replace(/[^\w\s-]/g, '')
.replace(/[\s_]+/g, '-')
.replace(/-+/g, '-');
}
3. src/index.ts — точка входа:
// src/index.ts
export { formatDate, daysBetween, isWeekend } from './date-helpers';
export { capitalize, truncate, slugify } from './string-helpers';
// Дополнительная функция-комбинация
export function formatDateAndCapitalize(date: Date, name: string): string {
const formatted = formatDate(date);
const capitalized = capitalize(name);
return `${capitalized} — ${formatted}`;
}
4. tsup.config.ts — конфигурация сборки:
// tsup.config.ts
import { defineConfig } from 'tsup';
export default defineConfig({
entry: ['src/index.ts'],
format: ['cjs', 'esm'],
dts: true,
splitting: false,
sourcemap: true,
clean: true,
minify: true,
// Исключаем стандартные модули Node.js
external: ['fs', 'path', 'os'],
});
5. package.json — настройка публикации:
{
"name": "my-ts-lib",
"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"
}
},
"scripts": {
"build": "tsup",
"prepublishOnly": "npm run build"
},
"devDependencies": {
"tsup": "^8.0.0",
"typescript": "^5.0.0"
}
}
6. Запуск сборки и публикация:
# Сборка
npm run build
# Проверка содержимого dist/
ls dist/
# Публикация в npm (если зарегистрированы)
npm publish
7. Использование готовой библиотеки в другом проекте:
// В другом проекте
import { formatDate, capitalize, slugify } from 'my-ts-lib';
const today = new Date();
console.log(formatDate(today, 'DD.MM.YYYY')); //