Архитектура плагинов в SWC построена вокруг строгой сериализации конфигурации: любые параметры, передаваемые в плагин, приводятся к JSON-совместимому виду и проходят через единый слой инициализации трансформации. Это означает, что границы между JavaScript-кодом и Rust-реализацией плагина определяются форматом входных данных, а не динамическими объектами исполнения.
Ключевая особенность заключается в том, что конфигурация плагина не исполняется, а интерпретируется. Передача опций происходит через заранее определённые структуры, которые SWC преобразует в внутренние Rust-типы.
В большинстве сценариев плагины подключаются через объект конфигурации трансформации:
{
"jsc": {
"transform": {},
"experimental": {
"plugins": []
}
}
}
Каждый элемент массива plugins описывает отдельный плагин и
его параметры:
{
"jsc": {
"experimental": {
"plugins": [
["plugin-path-or-name", { "optionA": true, "optionB": 123 }]
]
}
}
}
Первый элемент массива определяет идентификатор плагина (путь к WASM-модулю или зарегистрированное имя), второй — объект опций, сериализуемый в JSON.
Опции плагина проходят через строгий JSON-слой. Это накладывает ограничения на допустимые типы данных:
Подобная модель обеспечивает совместимость между JavaScript runtime и Rust-исполнением, где конфигурация десериализуется в структуры с фиксированной схемой.
Особое значение имеет стабильность типов: любое несоответствие схеме приводит к ошибке инициализации плагина ещё до этапа трансформации AST.
При использовании программного API через пакет @swc/core
конфигурация передаётся напрямую в функцию трансформации:
import { transform } from "@swc/core";
const output = await transform(sourceCode, {
jsc: {
parser: {
syntax: "ecmascript"
},
experimental: {
plugins: [
[
"/path/to/plugin.wasm",
{
debug: false,
level: 2,
prefix: "log"
}
]
]
}
}
});
В этом случае объект конфигурации проходит два этапа обработки:
Каждый плагин получает собственный экземпляр конфигурации, изолированный от остальных.
При увеличении сложности плагина возникает необходимость группировки параметров. Для этого используется вложенная структура:
[
"plugin.wasm",
{
"featureFlags": {
"minify": true,
"inline": false
},
"rules": {
"consoleRemoval": {
"enabled": true,
"exclude": ["error", "warn"]
}
}
}
]
Такая форма позволяет формировать декларативные схемы поведения плагина, при этом SWC не накладывает ограничений на глубину вложенности, пока структура остаётся JSON-валидной.
Если второй элемент массива отсутствует, плагин получает пустую конфигурацию:
[
"plugin.wasm"
]
Эквивалентом становится пустой объект {}. Это поведение
важно для плагинов, имеющих дефолтные настройки и не требующих явной
инициализации параметров.
При построении цепочки трансформаций несколько плагинов могут использовать пересекающиеся ключи конфигурации. Однако SWC не выполняет слияние опций между плагинами. Каждый плагин изолирован и получает только свой объект параметров.
Конфликты возникают только на уровне пользовательской сборки конфигурации, а не внутри компилятора.
WASM-плагины используют дополнительный слой десериализации. Передача параметров осуществляется через линейную память модуля, а структура данных преобразуется в компактный бинарный формат.
Типичный процесс включает:
Такой подход минимизирует накладные расходы на сериализацию при повторных вызовах трансформации.
При использовании SWC в TypeScript-окружении конфигурация плагинов часто типизируется вручную:
type PluginOptions = {
debug: boolean;
level: number;
prefix?: string;
};
Однако эта типизация существует только на стороне конфигуратора. SWC не выполняет проверку типов в runtime, полагаясь исключительно на корректность JSON-структуры.
Конфигурации плагинов часто формируются программно:
const createPluginConfig = (env) => [
"plugin.wasm",
{
debug: env !== "production",
level: env === "production" ? 0 : 2
}
];
Подобный подход позволяет адаптировать поведение трансформации без изменения самого плагина, изменяя только входные параметры.
Файл .swcrc остаётся основным способом декларативного
описания конфигурации:
{
"jsc": {
"experimental": {
"plugins": [
[
"plugin.wasm",
{
"removeLogs": true
}
]
]
}
}
}
При этом SWC загружает конфигурацию на этапе инициализации процесса компиляции, а затем кэширует разобранную структуру до завершения процесса.
Конфигурация плагина не является реактивной. Изменение объекта опций во время выполнения не влияет на уже загруженный экземпляр плагина. Для применения новых параметров требуется повторная инициализация трансформации.
Это поведение обеспечивает детерминированность результатов компиляции при одинаковых входных данных и конфигурации.
В сложных плагинах применяется косвенная передача данных через конфигурацию:
Пример расширенной конфигурации:
[
"plugin.wasm",
{
"mode": "aggressive",
"targets": ["es2019", "browser"],
"excludePatterns": ["**/*.test.js"],
"metadata": {
"sourceMap": true,
"preserveComments": false
}
}
]
Такая структура превращает плагин в параметризуемый модуль, поведение которого определяется исключительно входными данными.
Модель конфигурации SWC накладывает несколько фундаментальных ограничений:
Эти ограничения компенсируются предсказуемостью выполнения и высокой скоростью инициализации трансформаций.
Плагины часто определяют собственную схему опций, которая документируется отдельно от SWC. Эта схема фактически становится контрактом между конфигурацией и логикой трансформации.
Внутри плагина опции обычно десериализуются в структуру:
struct PluginOptions {
debug: bool,
level: i32,
prefix: Option<String>,
}
Любое несоответствие JSON-структуры этой схеме приводит к ошибке десериализации на этапе загрузки плагина.
Некорректные или неожиданные поля в конфигурации могут:
SWC не выполняет автоматическую валидацию семантики опций, ограничиваясь проверкой структуры данных.