Директива @jsxRuntime в комментариях

JSX-компиляция в esbuild опирается на заранее заданные параметры трансформации, а не на богатую систему директив внутри исходного кода, как это реализовано в Babel или частично в TypeScript. В контексте экосистемы JavaScript под «директивой @jsxRuntime в комментариях» обычно понимается механизм управления режимом JSX-трансформации через специальные комментарии вида /** @jsxRuntime automatic */ или /** @jsxRuntime classic */, которые позволяют переключать поведение JSX-компилятора на уровне файла.

JSX может компилироваться двумя основными способами:

Classic runtime предполагает явный вызов функции создания элементов:

  • JSX:

    <App />
  • Преобразуется в:

    React.createElement(App, null)

Automatic runtime (новый формат JSX transform):

  • JSX:

    <App />
  • Преобразуется в:

    import { jsx as _jsx } from "react/jsx-runtime";
    _jsx(App, {});

Ключевое различие заключается в том, что automatic runtime не требует явного импорта React в каждом файле и использует функции из react/jsx-runtime или альтернативного источника, заданного через конфигурацию.

Назначение директивы @jsxRuntime в комментариях

Комментарий вида:

/** @jsxRuntime automatic */

или

/** @jsxRuntime classic */

служит инструкцией для трансформера JSX, определяя, какой runtime использовать при компиляции конкретного файла.

Основная идея:

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

В классическом Babel-пайплайне эта директива может учитываться через соответствующие плагины, а в TypeScript — через совместимую JSX-трансформацию.

Поведение esbuild относительно @jsxRuntime

В esbuild важно учитывать принципиальную особенность: инструмент не реализует полноценный парсинг JSX-директив из комментариев на уровне Babel-плагинов. Вместо этого он использует строго конфигурационный подход.

JSX-трансформация в esbuild задаётся через параметры:

  • jsx
  • jsxFactory
  • jsxFragment
  • jsxImportSource

Пример конфигурации:

esbuild.build({
  jsx: "automatic",
})

или:

esbuild.build({
  jsx: "transform",
  jsxFactory: "h",
  jsxFragment: "Fragment",
})

Таким образом, поведение JSX определяется глобально для всего процесса сборки или конкретного файла через loader/опции, но не через inline-комментарии.

Почему комментарий @jsxRuntime не является стандартным механизмом esbuild

С точки зрения архитектуры esbuild:

  1. Нет AST-уровня Babel-плагинов Esbuild реализует собственный быстрый парсер и трансформер, оптимизированный под скорость, а не под расширяемые AST-правила.

  2. Отсутствие директивного анализа комментариев JSX Комментарии не участвуют в выборе runtime.

  3. Конфигурация вместо контекстных инструкций Любая настройка должна быть задана до начала компиляции.

Это приводит к тому, что:

  • /** @jsxRuntime automatic */ игнорируется
  • управление runtime осуществляется только через jsx опцию

Практическое влияние при переносе проектов с Babel

При миграции проектов, где ранее использовались JSX-директивы в комментариях, возникает типичная ситуация:

  • Babel-проект:

    /** @jsxRuntime automatic */
    /** @jsxImportSource preact */
  • Esbuild-проект требует замены на конфигурацию:

esbuild.build({
  jsx: "automatic",
  jsxImportSource: "preact",
})

Это означает, что управление переносится:

  • из файла исходного кода
  • в сборочный слой

JSX Import Source и его роль вместо runtime-директив

В современном JSX pipeline ключевую роль играет jsxImportSource. Он определяет, из какого пакета импортируются функции JSX runtime.

Пример:

esbuild.build({
  jsx: "automatic",
  jsxImportSource: "preact",
})

Тогда JSX:

<div />

будет компилироваться в:

import { jsx as _jsx } from "preact/jsx-runtime";
_jsx("div", {});

Это полностью заменяет необходимость в комментариях, которые ранее могли переключать runtime.

Ограничения концепции directive-based управления JSX

Использование директив в комментариях, подобных @jsxRuntime, имеет ряд особенностей:

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

В esbuild подход противоположный:

  • поведение строго определено build-time настройками
  • отсутствует неоднозначность на уровне файлов
  • исключается необходимость анализа комментариев

Совместимость с экосистемой React и альтернативными JSX runtime

При использовании React 17+ или альтернативных JSX runtime (Preact, Solid, Inferno) ключевым становится не директива в комментариях, а конфигурация:

  • React:

    • jsx: "automatic"
    • jsxImportSource: "react"
  • Preact:

    • jsxImportSource: "preact"
  • Solid:

    • часто требует отдельного preset или aliasing

Esbuild выступает как низкоуровневый инструмент, который лишь применяет выбранную стратегию трансформации.

Типичные ошибки при ожидании поддержки @jsxRuntime в esbuild

При переносе кода часто предполагается, что:

  • комментарии управляют сборкой
  • JSX runtime можно переключать локально
  • esbuild читает Babel-директивы

Фактически:

  • комментарии не влияют на трансформацию
  • runtime задаётся только через API сборки
  • файл не может самостоятельно изменить JSX поведение

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

Итоговое понимание роли директивы

Директива @jsxRuntime в комментариях относится к более гибким трансформерам JSX, где код может нести метаинформацию о компиляции. В контексте esbuild эта модель не применяется: JSX runtime определяется исключительно конфигурацией сборщика, а не содержимым исходных файлов.