Loader file: копирование файлов с хешем

Назначение loader file

Loader file в esbuild применяется для обработки импортируемых ресурсов, которые должны быть вынесены в отдельные файлы при сборке. При встрече такого импорта исходный файл не встраивается в бандл и не преобразуется в код, а копируется в выходной каталог, после чего в JavaScript-модуле заменяется на строку с путём к итоговому файлу.

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

Типичный набор сценариев:

  • изображения (png, jpg, svg, gif)
  • шрифты (woff, woff2, ttf)
  • любые бинарные или статические ресурсы
  • ассеты, используемые через import

Базовое поведение file loader

При использовании:

import logo from './logo.png'

и конфигурации esbuild:

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

происходит следующее:

  1. файл logo.png читается как внешний ресурс;
  2. создаётся копия в директории сборки (outdir);
  3. имя файла может быть преобразовано согласно шаблону именования;
  4. переменная logo получает строку — путь до итогового файла.

Пример результата:

console.log(logo)
// "/assets/logo-8f3a9c2d.png"

Механизм генерации выходных файлов

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

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

Хеширование файлов

Одной из ключевых возможностей является добавление хеша в имя файла для инвалидации кэша.

За это отвечает параметр:

assetNames

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

esbuild.build({
  entryPoints: ['src/index.js'],
  outdir: 'dist',
  loader: {
    '.png': 'file'
  },
  assetNames: 'assets/[name]-[hash]'
})

Шаблоны именования ассетов

В assetNames поддерживаются плейсхолдеры:

  • [name] — оригинальное имя файла без расширения
  • [ext] — расширение файла
  • [hash] — хеш содержимого
  • [dir] — относительная директория исходного файла

Пример:

assets/logo-8f3a9c2d.png

Принцип формирования хеша

Хеш генерируется на основе содержимого файла. Это означает:

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

Используемый хеш обычно укорочен (не SHA-256 целиком), что оптимизирует длину имени файла при сохранении уникальности.


Отличие file от dataurl и binary

esbuild предоставляет несколько альтернативных loaders:

Loader Поведение
file копирует файл в output и возвращает URL
dataurl встраивает файл как base64 data URI
binary импортирует как бинарный буфер

file используется, когда:

  • файл должен остаться отдельным ресурсом;
  • требуется кэширование через HTTP;
  • размер файла значителен.

Поведение с путями и URL

Результирующая строка зависит от конфигурации:

  • outdir — базовая директория вывода;
  • publicPath — префикс для URL;
  • assetNames — формирование имени файла.

Пример:

publicPath: '/static/',
assetNames: 'img/[name]-[hash]'

Результат импорта:

"/static/img/logo-8f3a9c2d.png"

Работа с дубликатами файлов

esbuild оптимизирует сборку:

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

Это снижает размер итоговой сборки при повторных импортax идентичных ресурсов.


Интеграция с CSS и HTML импортами

Loader file часто участвует в обработке:

  • url() внутри CSS;
  • импортов изображений из JavaScript;
  • генерации ссылок в стилях.

Пример CSS:

background-image: url('./bg.png');

После сборки:

background-image: url(/assets/bg-a1b2c3d4.png);

Метаданные сборки (metafile)

При включении:

metafile: true

esbuild сохраняет информацию о каждом asset:

  • исходный путь
  • путь выхода
  • размер
  • связи с модулями

Фрагмент структуры:

{
  "outputs": {
    "assets/logo-8f3a9c2d.png": {
      "imports": [],
      "bytes": 15342
    }
  }
}

Это позволяет анализировать:

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

Особенности работы в watch-режиме

При включённом режиме наблюдения:

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

Поведение при вложенных каталогах

Если исходный файл находится глубже структуры проекта:

src/images/icons/logo.png

и используется:

assetNames: 'assets/[dir]/[name]-[hash]'

результат:

assets/images/icons/logo-8f3a9c2d.png

Таким образом сохраняется структура вложенности.


Влияние на производительность сборки

Loader file относится к категории лёгких операций:

  • чтение файла из диска;
  • вычисление хеша;
  • запись в output;
  • возврат строки.

Узкие места возникают только при:

  • большом количестве мелких ассетов;
  • отсутствии кэширования файловой системы;
  • глубокой вложенности ресурсов.

Типичные ошибки конфигурации

Некорректные сценарии использования:

  • отсутствие outdir, приводящее к невозможности корректного вывода ассетов;
  • конфликт publicPath, вызывающий некорректные URL;
  • использование file для очень маленьких файлов, где более эффективно dataurl;
  • отсутствие assetNames, приводящее к однообразным именам.

Роль loader file в архитектуре сборки

Loader file выполняет функцию связующего слоя между кодом и файловой системой. Он обеспечивает:

  • отделение бинарных ресурсов от JavaScript;
  • стабильные URL для загрузки ресурсов в браузере;
  • поддержку долгоживущего кэша через хеширование;
  • предсказуемую структуру выходного каталога.

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