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

Архитектура плагинов SWC построена вокруг идеи компилятора как набора изолированных этапов трансформации синтаксического дерева (AST), где каждый этап может быть расширен или заменён через строго определённые точки расширения. Основная цель такой модели — сохранить высокую производительность Rust-ядра при возможности кастомизации поведения компиляции на уровне JavaScript/TypeScript проектов.

Плагинная система SWC не является монолитной. Она разделена на несколько слоёв:

  • ядро компилятора (парсер, трансформер, генератор кода)
  • слой промежуточного представления (AST)
  • система проходов (passes)
  • интерфейсы расширений (plugins)

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


Позиция плагинов в компиляционном пайплайне

Общий пайплайн SWC можно представить как последовательность стадий:

  1. Парсинг исходного кода

    • исходный код → AST
    • учитываются ECMAScript и TypeScript синтаксические расширения
  2. Трансформации AST

    • применение встроенных оптимизаций
    • применение пользовательских плагинов
    • выполнение preset-преобразований (например, TypeScript → JavaScript)
  3. Генерация кода

    • AST → строковый JavaScript
    • минификация (если включена)

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


AST как основа плагинной системы

SWC использует структурированный AST, близкий по модели к ESTree, но с расширениями под Rust-реализацию.

Ключевые особенности:

  • строгая типизация узлов (Rust enums + structs)
  • отсутствие динамических полей
  • иммутабельная модель обработки (частично копирующая)
  • оптимизация под zero-cost abstractions

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


Visitor-модель и обход дерева

Основной механизм модификации AST в SWC — паттерн Visitor.

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

  • visit_module
  • visit_function
  • visit_expression
  • visit_statement

Обход дерева происходит рекурсивно:

  • вход в узел
  • обработка дочерних узлов
  • возможная модификация текущего узла
  • возврат результата

Особенности реализации Visitor в SWC

  • обход оптимизирован на уровне Rust (без динамической диспетчеризации там, где это возможно)
  • использование макросов для генерации boilerplate-кода
  • минимизация аллокаций при трансформациях
  • возможность раннего выхода из посещения поддеревьев

Типы плагинов SWC

Архитектура расширений не ограничивается одним типом плагина. В зависимости от уровня интеграции выделяются несколько классов.

AST Transform Plugins

Наиболее распространённый тип.

Функции:

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

Примеры задач:

  • преобразование JSX
  • удаление console.log
  • инлайнинг констант

Особенность: работают исключительно на уровне AST, не затрагивая лексический анализ.


Parser Extensions

Менее распространённый, но более низкоуровневый тип.

Функции:

  • расширение синтаксиса языка
  • поддержка нестандартных конструкций
  • изменение поведения парсера

Ограничение:

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

Resolver Plugins

Используются на этапе разрешения модулей.

Функции:

  • изменение правил импорта
  • кастомизация alias-резолвинга
  • обработка виртуальных модулей

Характерная особенность:

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

Codegen Hooks (ограниченные расширения)

Финальный этап пайплайна.

Функции:

  • постобработка сгенерированного кода
  • форматирование
  • внедрение source maps

Ограничения:

  • минимальный доступ к AST
  • преимущественно текстовая стадия

WASM-плагины и изоляция выполнения

В экосистеме SWC значительная часть плагинов реализуется через WebAssembly.

Причины выбора WASM:

  • безопасность выполнения стороннего кода
  • переносимость между средами Node.js и браузера
  • совместимость с Rust-инфраструктурой
  • предсказуемая производительность

Архитектура WASM-плагина

WASM-плагин состоит из:

  • скомпилированного модуля (.wasm)
  • JavaScript-обёртки
  • описания типов входных AST-структур

Поток выполнения:

  1. SWC сериализует AST
  2. передаёт его в WASM-модуль
  3. модуль модифицирует структуру
  4. результат десериализуется обратно в Rust AST

Ограничения WASM-слоя

Несмотря на гибкость, WASM-плагины имеют ограничения:

  • невозможность прямого доступа к памяти компилятора
  • необходимость сериализации AST
  • ограниченная работа с внешними API
  • дополнительный overhead на обмен данными

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


Модель данных между ядром и плагинами

Передача данных между слоями осуществляется через строго определённые структуры:

  • JSON-подобные промежуточные представления
  • бинарные сериализации AST
  • Rust-совместимые типы через FFI

Ключевой принцип — минимизация потерь структуры AST при сериализации.


Цепочка трансформаций (plugin pipeline)

Плагинная система SWC организована как последовательность проходов:

AST → Plugin 1 → AST → Plugin 2 → AST → Plugin N → AST

Каждый плагин:

  • получает входной AST
  • возвращает новый AST
  • не имеет глобального состояния (в идеале)

Особенности выполнения:

  • порядок плагинов критичен
  • некоторые плагины могут изменять поведение последующих
  • возможна оптимизация цепочки (fusion passes)

Система пресетов и композиция плагинов

SWC поддерживает группировку трансформаций в пресеты.

Пресет — это:

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

Преимущества:

  • стандартизация пайплайнов (например, React, TypeScript)
  • повторное использование конфигураций
  • упрощение сборки проектов

Производительность и zero-cost подход

Плагинная архитектура SWC проектируется с учётом производительности компилятора как критического инструмента.

Основные стратегии:

  • минимизация динамической диспетчеризации
  • использование Rust enum вместо object-based AST
  • избегание глубокого копирования дерева
  • оптимизация проходов Visitor
  • inline-операции там, где возможно

Ошибки и модель диагностики в плагинах

Плагины могут возвращать ошибки на разных этапах:

  • синтаксические (на этапе парсинга)
  • трансформационные (некорректный AST)
  • резолвинга модулей

Система ошибок:

  • типизированные Rust error enums
  • переносимые сообщения в JS-слой
  • привязка к узлам AST (source mapping)

Безопасность плагинной архитектуры

Безопасность обеспечивается несколькими уровнями:

  • изоляция WASM
  • отсутствие прямого доступа к файловой системе
  • ограниченные API взаимодействия
  • контроль времени выполнения

Дополнительно:

  • плагины не могут изменять ядро компилятора
  • отсутствует возможность перехвата глобального состояния без явного API

Расширяемость и эволюция модели

Архитектура плагинов SWC развивается в сторону:

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

Текущая модель ориентирована на баланс между:

  • скоростью Rust-ядра
  • гибкостью JavaScript-экосистемы
  • безопасностью выполнения стороннего кода