Transformer: преобразование одного типа файла

В архитектуре Parcel трансформация файлов является центральным этапом сборки. Любой входной файл — JavaScript, TypeScript, CSS, HTML, изображение или иной ресурс — рассматривается как asset, который проходит через цепочку преобразований до момента включения в финальный бандл. За преобразование конкретного типа ресурса отвечает механизм трансформеров.

Трансформер в Parcel представляет собой модуль, который принимает исходный файл и возвращает изменённое представление этого файла в формате, пригодном для дальнейшей обработки или включения в граф зависимостей.

Ключевая задача трансформера — обеспечить единообразие входных данных для следующих этапов сборки независимо от исходного формата файла.


Положение трансформации в сборочном конвейере

Сборка в Parcel строится вокруг последовательного преобразования ассетов:

  1. Поиск и резолв модулей
  2. Загрузка исходных файлов
  3. Определение типа ассета
  4. Применение трансформеров
  5. Построение графа зависимостей
  6. Оптимизация и бандлинг

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


Определение типа ассета

Перед запуском трансформеров Parcel определяет тип файла. Это происходит на основе расширения, содержимого и настроек конфигурации.

Тип ассета определяет набор трансформеров, которые будут применены. Например:

  • .js, .mjs, .cjs → JavaScript трансформеры
  • .ts, .tsx → TypeScript трансформеры
  • .css → CSS трансформеры
  • .html → HTML трансформеры
  • изображения → image transformers
  • шрифты → font transformers

Механизм применения трансформеров

Parcel использует цепочку трансформаций. Один ассет может проходить через несколько трансформеров последовательно.

Каждый трансформер получает на вход:

  • исходный код или бинарные данные
  • метаданные ассета (путь, тип, зависимости)
  • контекст сборки

И возвращает:

  • изменённый код
  • обновлённые зависимости
  • source map (при необходимости)

Результат одного трансформера становится входом следующего.


Встроенные трансформеры Parcel

Parcel поставляется с набором стандартных трансформеров, охватывающих основные типы ресурсов.

JavaScript и TypeScript

JavaScript трансформер отвечает за:

  • транспиляцию современных стандартов ECMAScript
  • обработку JSX
  • поддержку TypeScript через интеграцию с компилятором
  • удаление TypeScript типов
  • преобразование модульных форматов

TypeScript обрабатывается через специализированный трансформер, который:

  • удаляет типизацию
  • преобразует синтаксис в JavaScript
  • сохраняет структуру модулей

В процессе часто используются внутренние пакеты вида @parcel/transformer-babel и @parcel/transformer-typescript.


CSS трансформация

CSS трансформеры выполняют:

  • обработку @import
  • разрешение зависимостей внутри CSS
  • поддержку CSS Modules
  • постобработку (autoprefixing, nesting)

Каждый CSS файл превращается в граф зависимостей, где отдельные импортируемые стили становятся самостоятельными ассетами.


HTML трансформация

HTML трансформер выполняет:

  • парсинг HTML-документа
  • извлечение <script>, <link>, <img> как зависимостей
  • обработку встроенных стилей и скриптов
  • преобразование ссылок в валидные ассеты графа

HTML в Parcel — не просто статический файл, а точка входа графа зависимостей.


Работа с изображениями и шрифтами

Для бинарных ресурсов применяются специализированные трансформеры:

  • оптимизация изображений
  • генерация нескольких форматов (например, WebP, AVIF)
  • инлайнинг малых файлов
  • обработка метаданных

Шрифты проходят через трансформацию, обеспечивающую корректное включение в CSS и оптимизацию доставки.


Конфигурация трансформеров через .parcelrc

Parcel позволяет управлять цепочкой трансформаций через файл конфигурации .parcelrc.

Пример структуры:

{
  "extends": "@parcel/config-default",
  "transformers": {
    "*.svg": ["@parcel/transformer-svg"]
  }
}

Каждое правило определяет, какие трансформеры применяются к конкретным типам файлов.

Переопределение стандартных цепочек позволяет:

  • заменить встроенный трансформер
  • добавить дополнительный этап обработки
  • отключить часть стандартной логики

Пользовательские трансформеры

Parcel поддерживает создание собственных трансформеров, что позволяет интегрировать нестандартные форматы и кастомные языки.

Трансформер реализуется как Node.js модуль, экспортирующий функцию обработки ассета.

Базовая структура:

export default function transformer({ asset }) {
  const code = asset.getCode();

  const transformed = code.replace(/foo/g, "bar");

  asset.setCode(transformed);

  return [asset];
}

Возможности API ассета

Внутри трансформера доступен объект ассета с методами:

  • получение исходного кода
  • изменение содержимого
  • добавление зависимостей
  • работа с метаданными
  • генерация source map

Управление зависимостями внутри трансформера

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

Пример:

asset.addDependency({
  specifier: "./utils.js",
  specifierType: "esm"
});

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


Кэширование и производительность

Parcel активно использует кэширование результатов трансформации. Каждый трансформированный ассет сохраняется с учётом:

  • содержимого файла
  • версии трансформера
  • конфигурации сборки
  • зависимостей

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


Source maps в трансформерах

Трансформеры могут генерировать source maps для корректного отображения исходного кода в отладчике.

Source map связывает:

  • исходные строки
  • трансформированный код
  • позиции в бандле

При цепочке трансформеров source maps объединяются в единое отображение, позволяющее отслеживать оригинальный код через несколько уровней преобразований.


Порядок применения нескольких трансформеров

Если для одного типа файлов задано несколько трансформеров, Parcel применяет их последовательно.

Пример цепочки:

  1. TypeScript трансформация
  2. Babel преобразование
  3. дополнительная кастомная обработка

Каждый этап оперирует уже преобразованным кодом, что позволяет строить сложные пайплайны обработки.


Условные трансформации и контекст

Трансформеры могут изменять поведение в зависимости от:

  • режима сборки (development / production)
  • наличия HMR
  • платформы сборки (browser / node)
  • параметров конфигурации

Контекст передаётся через объект окружения сборки и может использоваться для условной логики внутри трансформера.


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

При возникновении ошибки трансформации Parcel:

  • привязывает ошибку к конкретному ассету
  • сохраняет контекст файла
  • отображает исходное место ошибки через source map
  • при возможности продолжает сборку других ассетов

Это позволяет локализовать проблему без остановки всего процесса.


Расширение цепочки трансформации

Механизм трансформеров позволяет:

  • внедрять препроцессоры (например, SCSS → CSS)
  • подключать транспиляторы нестандартных языков
  • реализовывать оптимизацию на уровне исходного кода
  • интегрировать генерацию кода (например, GraphQL → JS)

Каждый новый слой обработки становится частью общей графовой модели проекта.


Взаимодействие трансформеров с другими этапами Parcel

Трансформеры тесно связаны с другими компонентами системы:

  • Resolver определяет, какие файлы попадут в трансформацию
  • Bundler использует результат трансформации для упаковки
  • Optimizer работает уже с готовыми бандлами

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