JSX в процессе компиляции превращается в обычные вызовы функций. Каждое
JSX-выражение транслируется в так называемую JSX factory —
функцию, которая создаёт виртуальные элементы. Конфигурация этой фабрики
определяет, во что именно будет преобразован JSX-код: в
React.createElement, в h (как в
Vue/Preact-подобных реализациях) или в кастомную функцию.
В SWC эта логика управляется через настройки трансформации React в
секции jsc.transform.react. Хотя в экосистеме TypeScript
используются параметры jsxFactory и
jsxFragmentFactory, в SWC им соответствуют
pragma и pragmaFrag, а также режим
runtime.
Параметр jsxFactory в TypeScript задаёт функцию, которая
будет использоваться для преобразования JSX-элементов.
Пример TypeScript-конфигурации:
{
"compilerOptions": {
"jsxFactory": "h"
}
}
JSX:
const el = <div className="box">Hello</div>;
После трансформации:
const el = h("div", { className: "box" }, "Hello");
В SWC аналогичная настройка задаётся через:
{
"jsc": {
"transform": {
"react": {
"pragma": "h"
}
}
}
}
Значение pragma полностью заменяет jsxFactory
в режиме classic.
pragma определяет базовую функцию, которая вызывается для
каждого JSX-элемента, за исключением фрагментов. Она принимает три
основных аргумента:
“div”, “span” или компонент)
Пример результата трансформации:
h("button", { disabled: true }, "Click");
Фрагменты JSX:
<>
<span>A</span>
<span>B</span>
</>
В TypeScript параметр jsxFragmentFactory задаёт функцию,
создающую фрагменты без DOM-обёртки:
{
"compilerOptions": {
"jsxFragmentFactory": "Fragment"
}
}
Результат трансформации:
Fragment(null, [A, B]);
В SWC эта роль выполняется параметром pragmaFrag:
{
"jsc": {
"transform": {
"react": {
"pragma": "h",
"pragmaFrag": "Fragment"
}
}
}
}
pragmaFrag определяет функцию, которая используется
исключительно для JSX-фрагментов.
Пример трансформации:
<>
<Item />
<Item />
</>
После компиляции:
Fragment(null, [
Item(null),
Item(null)
]);
SWC поддерживает два основных режима JSX-трансформации:
classic — используется pragma и
pragmaFrag
automatic — используется новый JSX runtime без явных фабрик
Конфигурация classic:
{
"jsc": {
"transform": {
"react": {
"runtime": "classic",
"pragma": "h",
"pragmaFrag": "Fragment"
}
}
}
}
В этом режиме весь JSX-код зависит от указанных фабрик. Любое изменение
pragma напрямую влияет на итоговый JavaScript.
В режиме automatic концепции jsxFactory и
jsxFragmentFactory фактически перестают использоваться.
{
"jsc": {
"transform": {
"react": {
"runtime": "automatic"
}
}
}
}
JSX:
const el = <div>Hello</div>;
Преобразуется в:
import { jsx as _jsx } from "react/jsx-runtime";
const el = _jsx("div", { children: "Hello" });
Фрагменты:
<>
<A />
<B />
</>
Преобразуются в:
import { Fragment as _Fragment, jsxs as _jsxs } from "react/jsx-runtime";
_jsxs(_Fragment, { children: [A, B] });
В этом режиме:
pragma игнорируется
pragmaFrag игнорируется
| TypeScript | SWC (classic) | Назначение |
|---|---|---|
| jsxFactory | pragma | функция создания элементов |
| jsxFragmentFactory | pragmaFrag | функция создания фрагментов |
Ключевое отличие состоит в том, что SWC централизует управление через
jsc.transform.react, а TypeScript распределяет настройки по
compilerOptions.
Использование нестандартных фабрик позволяет полностью заменить модель JSX.
Пример гиперскрипт-функции:
function h(type, props, ...children) {
return {
type,
props: props || {},
children
};
}
SWC-конфигурация:
{
"jsc": {
"transform": {
"react": {
"runtime": "classic",
"pragma": "h",
"pragmaFrag": "Fragment"
}
}
}
}
JSX:
<div>
<span>1</span>
<span>2</span>
</div>
Результат:
h(
"div",
null,
h("span", null, "1"),
h("span", null, "2")
);
Такой подход используется в лёгких UI-библиотеках, где React не нужен, но JSX синтаксис сохраняется.
При использовании pragma SWC придерживается следующих
правил трансформации:
null и undefined могут быть опущены в
зависимости от оптимизации
props всегда передаются вторым аргументом, даже если пустые
Пример:
<Button disabled />
Результат:
h("Button", { disabled: true });
Хотя SWC является транспайлером, он учитывает синтаксическую структуру JSX:
div, span) передаются как
строки
MyComponent) передаются как идентификаторы
pragmaFrag
Пример различия:
<div />
<MyComponent />
Результат:
h("div", null);
h(MyComponent, null);
Если установлен runtime: automatic, но задан
pragma, он будет проигнорирован, что приводит к ложному
ощущению «неработающей конфигурации».
При использовании фрагментов без pragmaFrag возможны ошибки
компиляции или fallback на дефолтный Fragment из React (если он
подразумевается окружением).
При интеграции с Preact, Solid-подобными системами или собственными runtime важно синхронизировать:
SWC может выполнять дополнительные оптимизации:
null
React.createElement-подобных вызовов до прямых
фабрик
Эти оптимизации особенно заметны при больших деревьях JSX, где количество вложенных вызовов существенно влияет на итоговый код.
При проектировании трансформации ключевым становится выбор архитектурного режима:
classic + pragma + pragmaFrag — полный контроль над
фабриками, максимальная гибкость
automatic — минимальная конфигурация, зависимость от JSX
runtime
Фактически jsxFactory и jsxFragmentFactory в
SWC существуют как концептуальная совместимость с TypeScript, но
реализуются через pragma-модель, что делает конфигурацию
более унифицированной внутри компилятора.