Интеграция через @rollup/plugin-typescript

Роль TypeScript в сборке Rollup

TypeScript в экосистеме Rollup используется не как отдельный этап компиляции, а как часть цепочки трансформаций модулей. В отличие от tsc, который выполняет полноценную компиляцию проекта, Rollup работает с графом модулей и ожидает, что каждый подключаемый плагин будет преобразовывать входные файлы в валидный JavaScript.

Плагин @rollup/plugin-typescript выступает промежуточным звеном между исходным TypeScript-кодом и финальной сборкой. Его основная задача — трансформировать .ts и .tsx файлы в JavaScript на этапе построения графа зависимостей.

Ключевой принцип работы заключается в том, что Rollup не заменяет TypeScript-компилятор, а использует его API (через tslib и typescript) для преобразования модулей.


Архитектура @rollup/plugin-typescript

Плагин построен вокруг стандартного TypeScript Compiler API. Внутри используется typescript.createProgram, который создаёт виртуальный проект на основе конфигурации tsconfig.json.

Основные компоненты:

  • Parser интеграции Rollup — перехватывает файлы с расширениями .ts и .tsx
  • TypeScript Program — анализирует проект, строит AST и выполняет трансформации
  • Emitter — генерирует JavaScript-код и декларации .d.ts
  • Cache слой — оптимизирует повторные сборки
  • Diagnostics система — выводит ошибки компиляции

Важно понимать, что плагин не выполняет отдельный процесс компиляции, а работает внутри процесса Rollup.


Установка и базовая конфигурация

Для интеграции требуется установить сам плагин и TypeScript как peer dependency:

npm install @rollup/plugin-typescript typescript --save-dev

Минимальная конфигурация Rollup:

import typescript from '@rollup/plugin-typescript';

export default {
  input: 'src/index.ts',
  output: {
    file: 'dist/bundle.js',
    format: 'esm'
  },
  plugins: [
    typescript()
  ]
};

При такой конфигурации Rollup автоматически использует tsconfig.json, если он находится в корне проекта.


Использование tsconfig.json

Плагин полностью опирается на конфигурацию TypeScript. Наиболее важные параметры:

rootDir и outDir

{
  "compilerOptions": {
    "rootDir": "src",
    "outDir": "dist"
  }
}

В контексте Rollup outDir фактически игнорируется, так как вывод контролируется Rollup, но rootDir влияет на структуру модулей и диагностику.


module и target

{
  "compilerOptions": {
    "target": "ES2019",
    "module": "ESNext"
  }
}

Rollup ожидает ES-модули, поэтому использование CommonJS на этом этапе нецелесообразно. При неправильной настройке может происходить двойная трансформация модулей.


declaration и sourceMap

{
  "compilerOptions": {
    "declaration": true,
    "sourceMap": true
  }
}
  • declaration включает генерацию .d.ts
  • sourceMap позволяет связать итоговый bundle с исходным TypeScript-кодом

Механизм обработки файлов

При запуске сборки происходит следующий процесс:

  1. Rollup строит граф зависимостей начиная с entry point
  2. При встрече .ts файла плагин перехватывает модуль
  3. TypeScript компилятор анализирует файл и его зависимости
  4. Выполняется трансформация AST в JavaScript
  5. Rollup получает готовый модуль и продолжает сборку

Особенность заключается в ленивой компиляции: файлы обрабатываются только при необходимости, а не весь проект сразу.


Работа с декларациями типов

Одним из ключевых режимов является генерация .d.ts файлов.

Конфигурация:

typescript({
  declaration: true,
  declarationDir: 'dist/types'
})

Однако в Rollup важно учитывать, что генерация деклараций может конфликтовать с tree-shaking и многопроходной сборкой.

На практике часто используется разделение:

  • Rollup — для JS-бандла
  • tsc — для .d.ts

Разделение ответственности Rollup и TypeScript

Существует два подхода:

1. TypeScript только как транспайлер

В этом случае:

  • TypeScript не проверяет типы строго
  • используется transpileOnly
typescript({
  noEmitOnError: false,
  declaration: false
})

Преимущество — скорость сборки.


2. Полная типизация через TypeScript

typescript({
  check: true
})

В этом режиме TypeScript выполняет полную проверку типов, но увеличивается время сборки.


Интеграция с tslib

Плагин часто использует tslib для оптимизации output-кода. Вместо инлайна вспомогательных функций (__extends, __awaiter) используется импорт из библиотеки.

npm install tslib

В tsconfig.json:

{
  "compilerOptions": {
    "importHelpers": true
  }
}

Это уменьшает размер итогового bundle.


Поддержка incremental сборки

Для больших проектов важна инкрементальная компиляция:

typescript({
  incremental: true,
  cacheDir: '.rollup_cache'
})

Механизм основан на хранении информации о предыдущих сборках и повторном использовании AST.


Взаимодействие с другими плагинами Rollup

Порядок плагинов критически важен.

Типичная цепочка:

plugins: [
  typescript(),
  resolve(),
  commonjs()
]

Ошибочная конфигурация (например, commonjs до typescript) может привести к некорректной трансформации модулей.


Обработка внешних зависимостей

TypeScript плагин не управляет external напрямую, но тесно с ним связан.

external: ['react', 'lodash']

Если типы этих пакетов отсутствуют, TypeScript выдаст ошибки, даже если Rollup исключает их из бандла.


Использование project references

В крупных монорепозиториях применяется project references:

{
  "references": [
    { "path": "../shared" }
  ]
}

Rollup плагин может работать с таким проектом, но требует аккуратной настройки tsconfig.json, чтобы избежать дублирования компиляции.


Типичные проблемы интеграции

Конфликт ESM и CommonJS

При неправильном module:

  • Rollup ожидает ES modules
  • TypeScript может выдавать CommonJS

Решение:

{
  "compilerOptions": {
    "module": "ESNext"
  }
}

Дублирование трансформаций

Если одновременно используются:

  • @rollup/plugin-typescript
  • tsc в watch mode

возникает двойная компиляция и рассинхронизация output.


Проблемы с type-only imports

import type { User } from './types';

При неправильной конфигурации такие импорты могут сохраняться в output, что ломает runtime.


Оптимизация сборки

Для ускорения работы применяются следующие подходы:

  • отключение проверки типов в dev-сборке
  • использование skipLibCheck
  • разделение build и typecheck процессов
  • кэширование через incremental

Поддержка TSX

При использовании React-подобных проектов:

typescript({
  jsx: 'react'
})

или через tsconfig:

{
  "compilerOptions": {
    "jsx": "react-jsx"
  }
}

Rollup корректно обрабатывает TSX через TypeScript transformer без дополнительных Babel шагов.


Режим isolatedModules

{
  "compilerOptions": {
    "isolatedModules": true
  }
}

Этот режим критичен для Rollup-пайплайна, так как гарантирует, что каждый файл может быть транспилирован независимо, что соответствует модели Rollup.


Использование кастомного tsconfig

typescript({
  tsconfig: './tsconfig.build.json'
})

Это позволяет разделять:

  • dev-конфигурацию
  • production-сборку
  • типизацию

Поведение в watch режиме

Rollup watch mode совместно с TypeScript:

  • отслеживает изменения файлов
  • пересобирает только затронутые модули
  • использует кэш TypeScript program

Однако при изменении tsconfig.json происходит полная пересборка графа.


Итоговая модель взаимодействия

Внутренний pipeline можно представить как последовательность:

TypeScript AST → трансформация типов → JavaScript emission → Rollup graph integration → final bundle generation

Плагин @rollup/plugin-typescript выступает связующим слоем, который обеспечивает совместимость строгой типизации TypeScript с модульной моделью Rollup без необходимости отдельного этапа компиляции.