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

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

SWC разделяет систему на несколько слоёв:

  • ядро компилятора (core), реализованное на Rust
  • слой трансформаций (transform pipeline)
  • плагины (пользовательские или встроенные трансформеры)
  • интеграционные обёртки (swc-loader, next.js integration, CLI)

Ключевая особенность: плагины в SWC часто зависят не от абстрактного интерфейса, а от конкретных версий структур AST и внутренних типов, что делает совместимость более чувствительной, чем в классических JS-инструментах.

Версионирование ядра SWC

Ядро SWC использует семантическое версионирование:

  • MAJOR — изменения AST, удаление или переименование узлов, перестройка трансформационного пайплайна
  • MINOR — добавление новых возможностей без ломки существующих трансформаций
  • PATCH — исправления багов и оптимизации без влияния на поведение API

На практике даже MINOR-обновления могут влиять на плагины, если они используют внутренние API вместо публичных контрактов.

Плагинная модель и её ограничения

Плагины SWC делятся на несколько типов:

Rust-плагины (native transforms)

Это наиболее тесно интегрированный вариант. Они:

  • компилируются вместе с SWC
  • используют внутренние структуры swc_ecma_ast
  • напрямую зависят от версии core

Такая модель даёт максимальную производительность, но минимальную переносимость.

Ключевая проблема совместимости: любое изменение AST (например, добавление нового поля в выражения или изменение enum-ветки) может потребовать пересборки всех плагинов.

WASM-плагины

Более изолированная модель:

  • выполняются в WebAssembly runtime
  • используют сериализованный AST
  • меньше зависят от внутренних Rust-структур

Однако здесь возникает другая проблема: стабильность формата AST между версиями SWC.

JavaScript/TypeScript трансформеры

Иногда SWC используется как раннер для JS-логики трансформаций:

  • совместимость зависит от версии API обёртки
  • ограниченная работа с низкоуровневыми структурами
  • чаще всего используются через @swc/core

Проблема связки core + plugin

Главный источник несовместимости — несоответствие версий между:

  • @swc/core
  • @swc/helpers
  • @swc/plugin-*
  • интеграционными пакетами (например, swc-loader)

Если плагин собран против одной версии AST, а runtime использует другую, возникают ошибки:

  • unknown variant
  • mismatched types
  • silent failure трансформации
  • частичное применение transforms

Peer Dependencies и строгая привязка версий

Многие SWC-плагины используют peerDependencies для фиксации совместимости:

{
  "peerDependencies": {
    "@swc/core": "^1.3.0"
  }
}

Это означает, что плагин не гарантирует работу с другими major-версиями.

В сложных монорепозиториях это приводит к необходимости:

  • централизованного управления версиями
  • использования lockfile
  • строгого выравнивания зависимостей через npm/yarn/pnpm resolution

ABI и внутренняя несовместимость

SWC — это Rust-компилятор, и его плагины могут зависеть не только от API, но и от ABI-структур.

Типичный сценарий несовместимости:

  • плагин использует swc_ecma_ast v0.120
  • core обновляется до v0.130
  • структура CallExpression изменяется (добавляется поле или меняется enum)
  • плагин компилируется успешно, но падает в runtime

Это делает SWC более чувствительным к версиям, чем Babel, где AST более стабилен между мажорными релизами.

SWC и экосистема Next.js

В связке с Next.js проблема совместимости усиливается:

  • Next.js фиксирует свою версию SWC
  • пользовательские плагины могут требовать другую версию
  • обновление Next.js часто сопровождается обновлением SWC core

В результате возникает жёсткая матрица совместимости:

  • Next.js version ↔︎ SWC core version ↔︎ plugin version

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

Миграции между версиями SWC

При переходе между версиями SWC необходимо учитывать:

Изменения AST

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

Изменения transform pipeline

  • порядок применения трансформаций
  • разделение фаз (parse → transform → emit)
  • изменения в оптимизациях

Изменения plugin API

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

Практика стабилизации совместимости

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

Жёсткая фиксация версий

{
  "dependencies": {
    "@swc/core": "1.3.96",
    "@swc/plugin-transform-imports": "1.3.96"
  }
}

Главная цель — исключить автоматическое обновление minor/patch версий, которые могут затронуть AST.

Единая версия SWC во всём монорепозитории

Используется hoisting и централизованный resolution:

  • pnpm overrides
  • yarn resolutions
  • npm overrides

Пересборка плагинов при обновлении core

Любое обновление SWC требует:

  • очистки build cache
  • пересборки native plugins
  • проверка трансформаций snapshot-тестами

Типичные ошибки несовместимости

  1. Silent transform failure

Плагин выполняется, но AST не изменяется из-за несовпадения типов узлов.

  1. Runtime panic в Rust-плагинах

Нарушение ожиданий структуры AST.

  1. Ошибки сериализации WASM

Неверный формат промежуточного AST между версиями.

  1. Несовпадение helper-функций

@swc/helpers генерирует код, несовместимый с версией runtime.

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

  • использование только официально поддерживаемых плагинов
  • избегание прямого доступа к внутренним Rust-структурам
  • проверка compatibility matrix в каждом обновлении
  • тестирование трансформаций на CI с фиксированной версией SWC
  • отказ от смешивания разных major-версий в одном пайплайне

Особенности долгосрочной поддержки

SWC развивается быстрее, чем большинство JS-инструментов, что приводит к следующей динамике:

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

Это означает, что плагины, рассчитанные на долгий срок, должны быть:

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