Поддержка JSX: React, Preact, SolidJS

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

JSX изначально ассоциируется с React, однако в современных проектах он используется также в связке с альтернативными библиотеками, такими как Preact и SolidJS. Parcel поддерживает каждую из этих экосистем через комбинацию автоматического распознавания, транспиляции и, при необходимости, дополнительных плагинов или алиасов.


Механизм обработки JSX в Parcel

Parcel использует систему трансформеров, которая анализирует тип входного файла и применяет соответствующую цепочку преобразований. Для JSX-файлов (.jsx, .tsx) применяются следующие этапы:

  • определение языка исходного файла;
  • парсинг AST;
  • трансформация JSX в JavaScript;
  • последующая оптимизация и бандлинг.

В большинстве случаев Parcel автоматически использует внутренние трансформеры на базе SWC или Babel (в зависимости от версии и конфигурации проекта), что позволяет избежать явного подключения пресетов вроде @babel/preset-react.

Ключевым элементом является автоматическое определение JSX-среды, включая выбор runtime:

  • classic runtime (React.createElement)
  • automatic runtime (React JSX Transform)

Автоматический JSX Runtime

Современные версии JSX поддерживают автоматический runtime, при котором не требуется явный импорт React в каждом файле. Parcel способен определить использование нового JSX transform и сгенерировать соответствующие импорты автоматически.

Пример исходного кода:

function Button() {
  return <button>Click</button>;
}

После трансформации:

import { jsx as _jsx } from "react/jsx-runtime";

function Button() {
  return _jsx("button", { children: "Click" });
}

При использовании React 17+ Parcel корректно выбирает runtime и минимизирует необходимость ручных настроек.


Поддержка TypeScript и TSX

Parcel обрабатывает .tsx файлы аналогично .jsx, добавляя дополнительный этап удаления типов.

type Props = {
  title: string;
};

export function Header({ title }: Props) {
  return <h1>{title}</h1>;
}

Pipeline трансформации включает:

  • удаление TypeScript-аннотаций;
  • преобразование JSX;
  • оптимизацию модулей.

При этом конфигурация TypeScript (tsconfig.json) учитывается автоматически, включая параметры:

  • jsx: react-jsx
  • jsxImportSource
  • target

JSX в React-проектах

При работе с React Parcel обеспечивает стандартный набор возможностей:

  • поддержка React Fast Refresh;
  • корректная обработка hooks;
  • оптимизация production-бандла;
  • tree-shaking компонентов.

Fast Refresh интегрируется через dev-сервер Parcel и позволяет сохранять состояние компонентов при изменениях в коде.

Пример структуры проекта:

src/
  App.jsx
  components/
    Button.jsx

Parcel автоматически связывает модули без дополнительной настройки entry points.


JSX и Preact: алиасирование React

Preact использует совместимый JSX runtime, но требует замены React-импорта на Preact-эквиваленты.

Parcel решает эту задачу через систему alias в конфигурации:

{
  "alias": {
    "react": "preact/compat",
    "react-dom": "preact/compat"
  }
}

После применения алиасов JSX продолжает компилироваться в тот же формат, но runtime заменяется на Preact.

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

  • сохранение React-совместимого API через compat-слой;
  • уменьшение размера бандла;
  • частичная несовместимость с редкими React-расширениями.

JSX остаётся неизменным:

import { useState } from "react";

export function Counter() {
  const [count, setCount] = useState(0);
  return <button onCl ick={() => setCount(count + 1)}>{count}</button>;
}

Parcel на уровне резолвинга модулей заменяет зависимости, не затрагивая сам JSX.


SolidJS и компиляция JSX в реактивные выражения

SolidJS использует JSX иначе, чем React: JSX компилируется не в виртуальный DOM, а в прямые реактивные вызовы.

Parcel поддерживает SolidJS через соответствующий трансформер (обычно babel-preset-solid или SWC-плагин).

Пример:

import { createSignal } from "solid-js";

function Counter() {
  const [count, setCount] = createSignal(0);

  return (
    <button onCl ick={() => setCount(count() + 1)}>
      {count()}
    </button>
  );
}

После трансформации JSX:

import { createSignal } from "solid-js";

function Counter() {
  const [count, setCount] = createSignal(0);

  return (() => {
    const _el$ = document.createElement("button");
    _el$.addEventListener("click", () => setCount(count() + 1));
    _el$.textContent = count();
    return _el$;
  })();
}

Parcel в этом случае выступает не как JSX-интерпретатор, а как оркестратор плагина трансформации.


Конфигурация JSX-трансформации

Parcel минимизирует необходимость ручных конфигураций, но поддерживает расширенные настройки через:

package.json

{
  "browserslist": [
    "last 2 versions"
  ]
}

.parcelrc

{
  "extends": "@parcel/config-default",
  "transformers": {
    "*.jsx": ["@parcel/transformer-babel"]
  }
}

Babel (при необходимости кастомизации)

{
  "presets": [
    ["@babel/preset-react", { "runtime": "automatic" }]
  ]
}

Однако в большинстве случаев Parcel полностью заменяет необходимость Babel-конфигурации.


JSX и HMR (Hot Module Replacement)

Hot Module Replacement интегрирован в Parcel на уровне runtime-сервера. JSX-компоненты пересобираются модульно, без полной перезагрузки страницы.

Поведение при изменении JSX:

  • пересборка только изменённого модуля;
  • сохранение состояния компонента (в React и Preact при корректной структуре);
  • мгновенное обновление DOM.

В React это достигается через React Refresh runtime. В Preact используется аналогичный механизм совместимости.


JSX и оптимизация бандла

Parcel применяет несколько уровней оптимизации JSX-кода:

  • удаление неиспользуемых импортов;
  • инлайнинг статических элементов;
  • хеширование модулей;
  • дедупликация runtime-helpers.

В production-сборке JSX преобразуется в максимально компактные вызовы функций, особенно при использовании automatic runtime.


Различия поведения JSX в разных рантаймах

React

  • виртуальный DOM;
  • reconciliation;
  • hooks API;
  • строгие правила порядка вызовов.

Preact

  • облегчённый виртуальный DOM;
  • меньший runtime;
  • частичная совместимость API.

SolidJS

  • отсутствие виртуального DOM;
  • компиляция в реактивные выражения;
  • обновления на уровне сигналов.

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


JSX в монорепозиториях

В монорепозиториях Parcel корректно обрабатывает JSX за счёт:

  • workspace resolution;
  • shared node_modules;
  • единых трансформеров.

Типичная структура:

packages/
  ui/
    Button.jsx
  app/
    App.jsx

JSX-компоненты из разных пакетов обрабатываются единым пайплайном, независимо от библиотеки UI-слоя.


Условная компиляция JSX

Parcel поддерживает tree-shaking JSX-веток при использовании условных выражений:

function View({ isMobile }) {
  return (
    <div>
      {isMobile ? <MobileLayout /> : <DesktopLayout />}
    </div>
  );
}

В production-сборке неиспользуемая ветка может быть исключена при статическом анализе, если значение выражения определяется на этапе сборки.


Обработка JSX в связке с CSS и ассетами

JSX в Parcel тесно интегрирован с системой модулей:

import styles from "./Button.module.css";

export function Button() {
  return <button className={styles.root}>OK</button>;
}

Parcel автоматически:

  • обрабатывает CSS Modules;
  • связывает классы с JSX;
  • изолирует стили по компонентам.

Ошибки трансформации JSX

Типовые проблемы возникают при:

  • отсутствии нужного preset для нестандартного JSX;
  • конфликте alias при Preact;
  • смешении разных JSX runtimes в одном проекте;
  • некорректной настройке TypeScript JSX режима.

Parcel обычно сообщает об ошибках на этапе dev-сервера с точной привязкой к модулю и AST-узлу, где произошёл сбой трансформации.


Итоговое поведение JSX-пайплайна Parcel

JSX в Parcel представляет собой автоматизированный конвейер:

  • распознавание синтаксиса;
  • выбор runtime (React / Preact / SolidJS через плагины);
  • трансформация AST;
  • оптимизация;
  • интеграция с HMR и бандлером.

Такой подход позволяет использовать JSX как универсальный UI-синтаксис независимо от выбранной библиотеки, сохраняя единый инструмент сборки и одинаковую модель разработки.