Назначение loader по расширению файла

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

Каждый модуль, который попадает в процесс сборки, идентифицируется по расширению файла. На основании этого расширения esbuild выбирает соответствующий loader и решает, что делать с содержимым:

  • преобразовать в JavaScript-код;
  • включить как строку;
  • встроить как base64;
  • оставить как внешний файл;
  • проигнорировать преобразования и обработать как JSON.

Ключевая идея заключается в том, что loader не анализирует содержимое файла глубоко — он работает на уровне типа ресурса.

Основные типы loader в esbuild

В конфигурации esbuild доступен набор встроенных загрузчиков, каждый из которых выполняет строго определённую роль:

  • js — стандартная обработка JavaScript без трансформации синтаксиса
  • jsx — поддержка JSX-разметки
  • ts / tsx — обработка TypeScript
  • json — импорт JSON как объекта
  • text — загрузка файла как строки
  • binary — представление файла в виде Uint8Array
  • base64 — кодирование содержимого в base64 строку
  • file — копирование файла в выходной каталог с возвратом URL

Каждый loader отвечает за то, как импорт будет представлен в итоговом бандле.

Конфигурация loader в API esbuild

В JavaScript API esbuild загрузчики задаются через объект loader, где ключом выступает расширение файла:

import * as esbuild from 'esbuild';

esbuild.build({
  entryPoints: ['src/index.js'],
  bundle: true,
  outdir: 'dist',
  loader: {
    '.js': 'js',
    '.png': 'file',
    '.svg': 'text',
    '.json': 'json'
  }
});

В этом примере разные типы файлов обрабатываются по-разному:

  • JavaScript остаётся исполняемым кодом;
  • изображения копируются как отдельные файлы;
  • SVG импортируется как строка;
  • JSON превращается в объект.

Связь расширения и поведения загрузчика

Связка расширения и loader является ключевым механизмом управления ресурсами. Например:

loader: {
  '.png': 'file',
  '.jpg': 'file',
  '.css': 'text',
  '.wasm': 'binary'
}

Здесь видно, что:

  • изображения не встраиваются в JS-код, а выносятся в отдельные файлы;
  • CSS обрабатывается как строка (что позволяет вручную инжектировать стили);
  • WebAssembly читается как бинарный буфер.

Поведение loader file

Loader file изменяет модель импорта. Вместо содержимого файла возвращается строка-URL, указывающая на итоговый файл в сборке:

import logoUrl from './logo.png';

console.log(logoUrl);

После сборки logoUrl будет содержать путь вроде:

assets/logo-8f3a2c.png

Это позволяет работать с ассетами как с обычными модулями, не перегружая JavaScript-код бинарными данными.

Loader text и работа со строковыми ресурсами

Loader text преобразует содержимое файла в строку:

import template from './template.html';

console.log(template);

В результате переменная template содержит весь HTML как текстовую строку. Это полезно для:

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

Loader json и статическая типизация данных

JSON-файлы обрабатываются как JavaScript-объекты:

import data from './config.json';

console.log(data.apiUrl);

При этом esbuild выполняет статическую инлайнизацию JSON, что исключает необходимость runtime-парсинга через JSON.parse.

Loader base64 и инлайнинг ресурсов

Loader base64 преобразует файл в строку base64:

loader: {
  '.png': 'base64'
}

Использование:

import icon from './icon.png';

const img = new Image();
img.src = `data:image/png;base64,${icon}`;

Такой подход полезен для маленьких ресурсов, где важно уменьшить количество HTTP-запросов.

Loader binary и работа с бинарными данными

Loader binary возвращает содержимое файла в виде Uint8Array:

import wasmBytes from './module.wasm';

Дальше эти данные можно использовать, например, для инициализации WebAssembly:

WebAssembly.instantiate(wasmBytes);

Loader jsx, ts и tsx

Для языков с расширенным синтаксисом используются специализированные загрузчики:

loader: {
  '.tsx': 'tsx',
  '.ts': 'ts',
  '.jsx': 'jsx'
}

Их задача — преобразовать исходный код в чистый JavaScript до этапа связывания модулей.

JSX преобразуется в вызовы React.createElement или аналогичные структуры, а TypeScript — в JavaScript с удалением типов.

Механизм сопоставления расширений

esbuild использует точное сопоставление расширений. Это означает:

  • .js и .mjs считаются разными ключами;
  • .ts и .tsx требуют отдельного указания;
  • при отсутствии loader для расширения используется поведение по умолчанию.

Пример:

loader: {
  '.ts': 'ts'
}

Файлы .tsx в этом случае не будут обрабатываться корректно без дополнительной настройки.

Приоритеты и поведение по умолчанию

Если loader не указан явно, esbuild применяет стандартные правила:

  • JavaScript-файлы обрабатываются как js;
  • JSON — как json;
  • изображения — как file в зависимости от контекста;
  • неизвестные расширения могут вызывать ошибку или требовать явного назначения.

Это делает конфигурацию предсказуемой: поведение всегда определяется либо стандартом, либо явной настройкой.

Использование loader в CLI

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

esbuild src/index.js \
  --bundle \
  --outdir=dist \
  --loader:.png=file \
  --loader:.svg=text

Каждое расширение указывается отдельно, что делает конфигурацию явной и читаемой.

Комбинация loader с другими опциями

Loader тесно взаимодействует с другими механизмами сборки:

  • bundle — влияет на то, как модули объединяются;
  • splitting — влияет на разделение кода;
  • assetNames — управляет именованием файлов при loader file;
  • publicPath — влияет на формирование URL.

Пример:

esbuild.build({
  entryPoints: ['src/app.ts'],
  bundle: true,
  outdir: 'dist',
  publicPath: '/static',
  assetNames: 'assets/[name]-[hash]',
  loader: {
    '.png': 'file'
  }
});

В этом случае loader определяет тип обработки ресурса, а остальные параметры формируют итоговую структуру вывода.

Ограничения loader-модели

Модель loader в esbuild намеренно упрощена:

  • отсутствуют цепочки трансформаций;
  • нельзя комбинировать несколько loader для одного расширения;
  • нет возможности динамически менять loader в процессе сборки;
  • обработка строго привязана к расширению файла.

Эта ограниченность компенсируется высокой скоростью и предсказуемостью поведения.

Практика выбора loader для ассетов

При проектировании сборки обычно применяется следующая логика:

  • крупные изображения → file
  • мелкие иконки → base64
  • текстовые шаблоны → text
  • конфигурации → json
  • бинарные форматы → binary

Такое разделение позволяет контролировать баланс между скоростью загрузки и размером бандла.

Поведение при конфликтующих расширениях

Если в конфигурации указано несколько правил для одного и того же расширения, последнее определение перекрывает предыдущие:

loader: {
  '.png': 'file',
  '.png': 'base64'
}

Фактически будет применён base64. Это важно учитывать при генерации конфигураций программно.

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

Внутри esbuild весь процесс можно свести к следующей логике:

  1. Определение расширения файла
  2. Поиск loader в конфигурации
  3. Применение преобразования
  4. Интеграция результата в граф модулей

Эта модель делает систему предельно детерминированной и легко прогнозируемой при масштабировании проектов.