Начиная с React 17, JSX больше не требует явного импорта
React в каждом файле. Новый трансформ JSX разделяет
ответственность между компилятором и рантаймом:
React.createElementreact/jsx-runtime)Esbuild поддерживает этот режим через опцию
jsx: "automatic", которая генерирует современный JSX
transform без необходимости вручную подключать React.
Основная конфигурация включает выбор JSX-режима:
import esbuild from 'esbuild';
esbuild.build({
entryPoints: ['src/index.jsx'],
bundle: true,
outfile: 'dist/bundle.js',
jsx: 'automatic'
});
В этом режиме Esbuild:
import React from "react"Для TypeScript используется аналогичная конфигурация:
esbuild.build({
entryPoints: ['src/index.tsx'],
bundle: true,
outfile: 'dist/bundle.js',
loader: {
'.tsx': 'tsx'
},
jsx: 'automatic'
});
jsx: 'transform'
JSX:
const el = <div>Hello</div>;
Трансформируется в:
const el = React.createElement("div", null, "Hello");
Требуется:
import React from "react";
jsx: 'automatic'
Тот же JSX:
const el = <div>Hello</div>;
Трансформируется в:
import { jsx as _jsx } from "react/jsx-runtime";
const el = _jsx("div", { children: "Hello" });
Ключевые отличия:
Reactreact/jsx-runtimeEsbuild позволяет переопределить источник JSX runtime через
jsxImportSource.
Это особенно важно при использовании альтернатив React-совместимых библиотек, например Preact.
esbuild.build({
entryPoints: ['src/index.jsx'],
bundle: true,
outfile: 'dist/bundle.js',
jsx: 'automatic',
jsxImportSource: 'preact'
});
JSX:
const app = <h1>Hello</h1>;
Будет преобразован в:
import { jsx as _jsx } from "preact/jsx-runtime";
const app = _jsx("h1", { children: "Hello" });
TypeScript 4.1+ также поддерживает automatic JSX runtime через:
{
"compilerOptions": {
"jsx": "react-jsx"
}
}
Однако при использовании Esbuild TypeScript используется только как транспайлер, поэтому важно согласовать настройки:
jsx: "automatic"jsx: "react-jsx" (если используется type-checking
отдельно)Несовпадение режимов может приводить к:
Esbuild автоматически различает режимы сборки:
esbuild.build({
entryPoints: ['src/index.jsx'],
bundle: true,
outfile: 'dist/bundle.js',
jsx: 'automatic',
minify: true,
sourcemap: true
});
В development режиме JSX может включать дополнительные проверки:
Production-режим:
_jsxEsbuild реализует собственный трансформ JSX, который отличается от Babel:
Пример генерации фрагментов:
<>
<span>A</span>
<span>B</span>
</>
Результат:
import { Fragment as _Fragment, jsx as _jsx } from "react/jsx-runtime";
_jsx(_Fragment, {
children: [
_jsx("span", { children: "A" }),
_jsx("span", { children: "B" })
]
});
Хотя automatic runtime предпочтителен, Esbuild позволяет использовать
старые подходы через jsxFactory и
jsxFragment.
esbuild.build({
entryPoints: ['src/index.jsx'],
bundle: true,
outfile: 'dist/bundle.js',
jsx: 'transform',
jsxFactory: 'h',
jsxFragment: 'Fragment'
});
Однако при jsx: "automatic" эти параметры игнорируются,
поскольку runtime управляется через jsxImportSource.
При использовании automatic runtime React может не попасть в итоговый бандл, если:
Это нормальное поведение tree-shaking системы Esbuild.
Некоторые библиотеки ожидают classic runtime:
React.createElementReact в scopeВ таких случаях требуется либо:
jsx: "transform"Esbuild не обрабатывает JSX в .js по умолчанию без
указания loader:
loader: {
'.js': 'jsx'
}
Иначе JSX код может интерпретироваться как обычный JavaScript и вызывать ошибки синтаксиса.
Esbuild реализует JSX transform на Go-ядре, что даёт:
Особенно заметно на проектах с:
Automatic JSX напрямую влияет на итоговую оптимизацию:
Пример:
const Button = () => <button>OK</button>;
После сборки:
import { jsx as _jsx } from "react/jsx-runtime";
const Button = () => _jsx("button", { children: "OK" });
Без необходимости подключения React как глобальной зависимости.