Loader js и jsx

В esbuild загрузчик (loader) определяет, как конкретный тип файла должен быть интерпретирован и преобразован в процессе сборки. Каждый входной модуль сопоставляется с определённым обработчиком, который решает, будет ли файл трактоваться как JavaScript, JSX, JSON, текст, бинарные данные или другой формат.

Для расширений .js и .jsx используются встроенные загрузчики, ориентированные на быстрый синтаксический разбор и минимальные преобразования. Их ключевая особенность — отсутствие тяжёлой AST-трансформации в привычном смысле: esbuild работает через высокопроизводительный парсер и генератор кода, оптимизированный на уровне Go.

Loader для JavaScript (js)

Загрузчик js является базовым и применяется ко всем JavaScript-файлам без JSX-синтаксиса. Он предполагает стандартный ECMAScript-код, который не содержит JSX-элементов, TypeScript-аннотаций или других расширений синтаксиса.

Основные характеристики обработки .js:

  • поддержка ECMAScript модулей (ESM) и CommonJS
  • анализ import и export на уровне синтаксиса
  • сохранение структуры кода при отсутствии необходимости трансформации
  • минимальные изменения при сборке

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

Важная особенность заключается в том, что loader js не выполняет JSX-трансформацию. Любые JSX-конструкции в .js файле при использовании этого загрузчика приведут к синтаксической ошибке, если не изменена конфигурация.

Поведение обработки .js файлов

При обработке JavaScript-файлов esbuild выполняет несколько стадий:

  • синтаксический разбор исходного кода
  • построение графа зависимостей
  • инлайнинг модулей при бандлинге
  • оптимизация импортов и экспортов
  • минификация (если включена)

При этом loader js не добавляет дополнительной семантики к коду. Он строго следует спецификации ECMAScript и не пытается интерпретировать расширенные конструкции.

Особенность работы с современным JavaScript заключается в поддержке:

  • динамических импортов import()
  • top-level await
  • tree-shaking на уровне графа зависимостей

Loader JSX

Loader jsx предназначен для обработки файлов, содержащих JSX-синтаксис. JSX представляет собой расширение JavaScript, позволяющее описывать UI-структуры в декларативной форме.

Основная задача loader jsx — трансформировать JSX-выражения в вызовы функций JavaScript, которые могут быть выполнены в стандартной среде выполнения.

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

const element = <div className="box">Hello</div>;

После обработки esbuild:

const element = React.createElement("div", { className: "box" }, "Hello");

или, при использовании автоматического JSX runtime:

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

const element = _jsx("div", { className: "box", children: "Hello" });

Выбор модели трансформации зависит от параметров конфигурации jsxFactory, jsxFragment и jsxRuntime.

Различия между loader js и jsx

Разделение загрузчиков js и jsx основано на различии в синтаксической допустимости входного кода.

Ключевые отличия:

  • js не допускает JSX-синтаксис
  • jsx включает дополнительный этап трансформации JSX-выражений
  • js имеет меньшую стоимость обработки
  • jsx требует генерации дополнительных импортов и вызовов функций

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

Настройка loader в esbuild

Загрузчик задаётся на уровне расширений файлов через конфигурацию bundler-а.

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

import * as esbuild from "esbuild";

esbuild.build({
  entryPoints: ["src/main.js"],
  bundle: true,
  outdir: "dist",
  loader: {
    ".js": "js",
    ".jsx": "jsx"
  }
});

В данной конфигурации:

  • .js файлы обрабатываются как чистый JavaScript
  • .jsx файлы проходят JSX-трансформацию

Загрузчики можно переопределять для любых расширений, однако для .js и .jsx используются наиболее оптимизированные встроенные режимы.

CLI-конфигурация loader

В CLI esbuild загрузчики задаются через параметр --loader:

esbuild src/main.jsx --bundle --outfile=dist/bundle.js --loader:.jsx=jsx

Также возможно указание нескольких загрузчиков:

esbuild src/index.js --bundle \
  --loader:.js=js \
  --loader:.jsx=jsx

CLI-режим сохраняет ту же семантику, что и API-конфигурация, но предоставляет более компактный способ управления обработкой файлов.

JSX-трансформация и runtime

Esbuild поддерживает два основных режима JSX:

Classic runtime

/** @jsx React.createElement */

или через конфигурацию:

jsxFactory: "React.createElement",
jsxFragment: "React.Fragment"

В этом режиме каждый JSX-элемент компилируется в вызов функции фабрики.

Automatic runtime

Современный режим, при котором esbuild автоматически импортирует необходимые функции:

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

JSX преобразуется в вызовы _jsx, _jsxs и аналогичные функции.

Loader jsx не только распознаёт синтаксис, но и оптимизирует структуру вызовов, минимизируя количество создаваемых промежуточных объектов.

Внутренние особенности обработки JSX

При трансформации JSX выполняются следующие шаги:

  • парсинг JSX-дерева
  • нормализация атрибутов
  • обработка children-узлов
  • оптимизация статических элементов
  • генерация вызовов runtime-функций

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

Влияние loader на структуру бандла

Выбор между js и jsx напрямую влияет на итоговый размер и структуру бандла:

  • js приводит к более прямолинейному коду без дополнительных импортов
  • jsx добавляет runtime-зависимости (например, react/jsx-runtime)
  • при оптимизации tree-shaking часть JSX-элементов может быть удалена как неиспользуемая

Особенно заметна разница в проектах с большим количеством UI-компонентов, где JSX используется интенсивно.

Совместное использование js и jsx в одном проекте

В рамках одного проекта часто применяется смешанная модель:

  • бизнес-логика размещается в .js
  • UI-компоненты — в .jsx

Пример структуры:

src/
  app.js
  utils.js
  components/
    Button.jsx
    Modal.jsx

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

Поведение при ошибках загрузчика

Если файл содержит синтаксис, не соответствующий выбранному loader, сборка завершается ошибкой.

Типичный случай:

  • файл .js содержит JSX → синтаксическая ошибка
  • файл .jsx содержит недопустимые конструкции → ошибка парсинга

Это поведение основано на строгой типизации входного синтаксиса, которую esbuild использует для ускорения анализа без попыток «догадок» о намерении разработчика.

Производительность loader js и jsx

Loader js является наиболее быстрым, так как ограничивается минимальной обработкой синтаксического дерева.

Loader jsx добавляет дополнительный этап трансформации, но остаётся значительно быстрее аналогичных решений благодаря:

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

Разница в скорости особенно заметна при больших кодовых базах, где количество JSX-узлов велико.

Практика выбора loader

Выбор между js и jsx определяется исключительно наличием JSX-синтаксиса:

  • наличие JSX → jsx
  • отсутствие JSX → js

Попытка унифицировать всё под jsx приводит к лишним трансформациям без практической пользы, тогда как строгая сегрегация улучшает стабильность и скорость сборки.