tsup для TypeScript: полное руководство с примерами

Онлайн-тренажер Python для начинающих

Изучайте Python легко и без перегрузки теорией. Решайте практические задачи с автоматической проверкой, получайте подсказки на русском языке и пишите код прямо в браузере — без необходимости что-либо устанавливать.

Начать курс

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')); //                    

Рекомендаций