Архитектура плагинов Parcel 2

Parcel 2 построен вокруг строго типизированной и событийно-ориентированной системы плагинов, в которой весь процесс сборки разбивается на последовательные этапы трансформации графа зависимостей. Вместо монолитной логики сборщика используется конвейер, где каждый плагин отвечает за узкую область: поиск модулей, преобразование кода, оптимизацию, упаковку и финальную эмиссию ассетов.

В основе архитектуры лежит концепция Asset Graph — графа ассетов, где каждый узел представляет файл или модуль, а рёбра отражают зависимости. Сборка в Parcel 2 — это последовательное построение и модификация этого графа через цепочку плагинов.

Плагинная система ориентирована на несколько ключевых принципов:

  • Декомпозиция этапов сборки на независимые хуки
  • Изоляция ответственности каждого плагина
  • Детерминированность результатов при одинаковом входе
  • Кешируемость на уровне трансформаций
  • Поддержка параллельного выполнения

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

Основные типы плагинов

Архитектура Parcel 2 определяет несколько категорий плагинов, каждая из которых подключается на определённом этапе пайплайна.

Resolver plugins

Резолверы отвечают за преобразование строковых импортов в реальные файлы графа.

Основные задачи:

  • разрешение модулей (import 'react' → путь к пакету)
  • обработка алиасов
  • поддержка расширений файлов
  • виртуальные модули

Резолвер работает до построения графа и определяет структуру зависимостей.

Transformer plugins

Трансформеры — центральная часть системы. Они модифицируют содержимое ассетов.

Функции:

  • транспиляция (TypeScript → JavaScript)
  • преобразование JSX
  • компиляция SASS/LESS/Stylus
  • инлайн ресурсов
  • кодогенерация

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

Validator plugins

Валидаторы выполняют статический анализ:

  • проверка типов
  • линтинг
  • анализ корректности зависимостей
  • выявление ошибок до бандлинга

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

Optimizer plugins

Оптимизаторы применяются после формирования бандлов.

Они отвечают за:

  • минификацию JavaScript и CSS
  • удаление dead code
  • tree-shaking на уровне бандлов
  • оптимизацию изображений
  • сжатие ресурсов

Оптимизация происходит уже на уровне готовой структуры output-графа.

Namer plugins

Namer определяет, как будут называться итоговые файлы:

  • content hashing
  • структурирование output директории
  • предотвращение конфликтов имён

Этот слой критичен для кеширования и CDN-доставки.

Packager plugins

Packager собирает ассеты в финальные бандлы.

Он определяет:

  • формат выходного файла
  • стратегию объединения модулей
  • вставку runtime-кода Parcel
  • структуру чанков

Reporter plugins

Репортёры не влияют на сборку, но наблюдают за процессом:

  • логирование
  • прогресс сборки
  • метрики производительности
  • диагностика

Жизненный цикл сборки

Parcel 2 строит пайплайн как последовательность фаз:

  1. Initialization
  2. Module resolution
  3. Dependency graph construction
  4. Transformation phase
  5. Bundle graph creation
  6. Packaging
  7. Optimization
  8. Emission

Каждая фаза открывает доступ к соответствующим хукам плагинов.

Хуки и контракт выполнения

Плагин в Parcel 2 — это объект, регистрирующий функции-хуки. Хуки вызываются движком в строго определённые моменты.

resolve

Отвечает за преобразование specifier в абсолютный путь.

Поведение:

  • получает исходный запрос
  • возвращает resolved asset reference
  • может делегировать другим резолверам

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

load / transform

Эти хуки формируют содержимое ассета.

  • load получает сырой контент
  • transform последовательно модифицирует его

Transform pipeline может быть асинхронным и зависеть от других ассетов.

generate

Используется для генерации выходного кода из промежуточного представления.

Применяется, например, при:

  • сборке CSS модулей
  • генерации JS-обёрток
  • создании runtime glue-кода

optimize

Вызывается после построения bundle graph.

Позволяет модифицировать финальные бандлы:

  • переписывать импорты
  • объединять чанки
  • убирать дубли

Кеширование и инвалидация

Одной из ключевых особенностей Parcel 2 является агрессивная система кеширования.

Каждая стадия пайплайна:

  • имеет входные хэши
  • учитывает зависимости
  • сохраняет промежуточные результаты

Кеш привязан к:

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

При изменении любого параметра происходит точечная инвалидизация, а не полный пересбор.

Изоляция плагинов и контекст выполнения

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

  • текущий asset
  • метаданные графа
  • конфигурацию target environment

Parcel избегает глобальных singleton-состояний, заменяя их контекстными объектами, что улучшает:

  • тестируемость
  • параллелизм
  • предсказуемость сборки

Асинхронность и параллельное выполнение

Пайплайн Parcel 2 изначально рассчитан на конкурентную обработку:

  • трансформеры могут выполняться параллельно
  • независимые ветки графа обрабатываются одновременно
  • I/O операции не блокируют pipeline

Это достигается за счёт task scheduler внутри ядра сборщика, который управляет очередями задач.

Bundle Graph как центральная структура

После этапа трансформации формируется Bundle Graph — структура, отличающаяся от исходного asset graph.

Если asset graph описывает зависимости на уровне файлов, то bundle graph:

  • группирует модули в чанки
  • учитывает code splitting
  • оптимизирует загрузку

Плагины на этапе bundling работают уже не с файлами, а с логическими единицами доставки.

Runtime-слой Parcel

Parcel вставляет runtime-код, который обеспечивает:

  • динамическую загрузку чанков
  • разрешение зависимостей в браузере
  • управление кешем на клиенте
  • hot module replacement

Плагины могут модифицировать или расширять runtime, добавляя свою логику поведения.

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

Несмотря на модульность, плагины взаимодействуют через общие структуры данных:

  • Asset
  • Dependency
  • Bundle
  • BundleGraph
  • Plugin options

Ключевая идея — отсутствие прямых вызовов между плагинами. Все взаимодействие происходит через изменение состояния графа.

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

Каждый плагин может учитывать target-среду:

  • browser
  • node
  • electron

Target влияет на:

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

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

Расширяемость системы

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

Добавление нового поведения обычно включает:

  • регистрацию плагина в соответствующем hook
  • определение области обработки ассетов
  • работу с метаданными графа

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

Внутренние гарантии выполнения

Система плагинов опирается на ряд гарантий:

  • порядок вызова хуков строго определён
  • результат трансформации детерминирован при одинаковом входе
  • каждый asset имеет уникальный идентификатор в графе
  • кеширование не влияет на семантику сборки

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