Тип inline: встраивание в Base64

Тип asset/inline в Webpack предназначен для встраивания файлов непосредственно в итоговый JavaScript-бандл в виде строки Data URL. Чаще всего используется Base64-кодирование, хотя Webpack способен применять и другие форматы представления данных.

После обработки ресурс перестаёт существовать как отдельный физический файл в директории сборки. Вместо ссылки на файл в коде появляется строка вида:

data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAA...

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


Принцип работы asset/inline

При импорте файла Webpack:

  1. Читает содержимое ресурса.
  2. Кодирует его.
  3. Преобразует в Data URL.
  4. Вставляет строку прямо в JavaScript-модуль.

Пример:

import logo fr om './logo.png';

console.log(logo);

Результат:

data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAA...

Файл logo.png не копируется в папку dist.


Настройка asset/inline

Базовая конфигурация:

module.exports = {
    module: {
        rules: [
            {
                test: /\.png$/,
                type: 'asset/inline'
            }
        ]
    }
};

Теперь каждый PNG-файл будет автоматически встроен в бандл.


Что такое Base64

Base64 — это способ представления бинарных данных в текстовом формате.

Например:

Hello

После кодирования:

SGVsbG8=

Для изображений или шрифтов данные становятся значительно длиннее:

data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAA...

Структура Data URL

Data URL состоит из нескольких частей:

data:[MIME-TYPE];base64,[DATA]

Пример:

data:image/svg+xml;base64,PHN2ZyB4bWxucz0...

Разбор:

Часть Назначение
data: Префикс Data URL
image/svg+xml MIME-тип файла
base64 Формат кодирования
PHN2Zy... Закодированные данные

Пример с изображением

Исходная структура

src/
├── index.js
└── images/
    └── icon.png

Конфигурация

module.exports = {
    module: {
        rules: [
            {
                test: /\.png$/,
                type: 'asset/inline'
            }
        ]
    }
};

Импорт

import icon from './images/icon.png';

const image = document.createElement('img');

image.src = icon;

document.body.append(image);

Что попадёт в сборку

const icon = "data:image/png;base64,iVBORw0KGgoAAAANS...";

Где используется asset/inline

Иконки

Маленькие PNG-файлы:

16x16
24x24
32x32

SVG

Небольшие SVG особенно хорошо подходят для inline-встраивания.

{
    test: /\.svg$/,
    type: 'asset/inline'
}

SVG-файлы часто имеют маленький размер и отлично сжимаются.


Шрифты

Иногда inline используется для небольших WOFF2-файлов:

{
    test: /\.woff2$/,
    type: 'asset/inline'
}

Фоновые изображения

.button {
    background-image: url('./icon.png');
}

Webpack преобразует путь в Data URL.


Преимущества asset/inline

Уменьшение количества HTTP-запросов

Без inline:

index.html
main.js
logo.png
icon.png
font.woff2

Браузер выполняет несколько запросов.

С inline:

index.html
main.js

Все ресурсы встроены в код.


Быстрая загрузка мелких ресурсов

Особенно полезно для:

  • иконок;
  • маленьких SVG;
  • preload-ресурсов;
  • встроенных шрифтов;
  • UI-элементов.

Отсутствие отдельных файлов

В папке сборки:

dist/
└── bundle.js

Не создаются дополнительные изображения.


Простота деплоя

Меньше файлов:

  • проще CDN-кэширование;
  • проще перенос сборки;
  • меньше операций файловой системы.

Недостатки asset/inline

Увеличение размера JavaScript

Base64 увеличивает размер данных примерно на 33%.

Например:

Оригинал Base64
3 KB ~4 KB
30 KB ~40 KB

Увеличение времени парсинга JS

Большой встроенный Base64:

const img = "data:image/png;base64,....";

увеличивает размер бандла, который:

  • скачивается;
  • распаковывается;
  • парсится;
  • компилируется движком JavaScript.

Невозможность отдельного кэширования

Если изображение встроено:

bundle.js

то браузер не может закэшировать картинку отдельно.

Даже небольшое изменение JS-инструкций инвалидирует весь бандл.


Ухудшение читаемости sourcemap

В sourcemap и devtools появляются огромные строки Base64.


Когда использовать asset/inline

Подходит для:

Тип ресурса Рекомендация
SVG-иконки Отлично
Маленькие PNG Хорошо
Мини-шрифты Допустимо
Большие изображения Плохо
Видео Недопустимо

Размер ресурса и производительность

Главное правило:

Inline используется только для небольших файлов.

Практические ориентиры:

Размер Подход
до 2 KB Отлично
до 4 KB Хорошо
4–10 KB Осторожно
более 10 KB Лучше отдельный файл

Разница между asset/inline и asset/resource

asset/resource

Создаёт физический файл:

dist/
├── main.js
└── logo.a1b2c3.png

Импорт:

import logo from './logo.png';

Результат:

"/logo.a1b2c3.png"

asset/inline

Ничего не создаёт:

dist/
└── main.js

Результат:

"data:image/png;base64,iVBOR..."

Разница между asset/inline и asset/source

asset/inline

Преобразует файл в Data URL:

data:image/svg+xml;base64,...

asset/source

Возвращает содержимое файла как строку:

"<svg>...</svg>"

Это принципиально разные механизмы.


Использование вместе с CSS

CSS

.block {
    background: url('./bg.png');
}

Конфигурация

module.exports = {
    module: {
        rules: [
            {
                test: /\.png$/,
                type: 'asset/inline'
            }
        ]
    }
};

Результат

background:
    url(data:image/png;base64,iVBORw0KGgoAAAANS...)

Inline для SVG

SVG особенно хорошо подходит для встраивания.

Пример:

<svg xmlns="http://www.w3.org/2000/svg">
    <circle cx="50" cy="50" r="40"/>
</svg>

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

data:image/svg+xml;base64,PHN2ZyB4bWxucz0...

Почему SVG часто лучше PNG для inline

SVG:

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

PNG:

  • бинарный;
  • тяжелее;
  • хуже подходит для Base64.

Автоматический выбор между inline и resource

Webpack поддерживает тип asset, который автоматически выбирает способ обработки.

Пример:

{
    test: /\.(png|svg)$/i,
    type: 'asset',
    parser: {
        dataUrlCondition: {
            maxSize: 4 * 1024
        }
    }
}

Логика:

Размер файла Результат
< 4 KB inline
> 4 KB resource

Как работает dataUrlCondition

Параметр:

maxSize

указывает максимальный размер файла для inline-встраивания.

Пример:

maxSize: 8 * 1024

означает:

8 KB

Настройка разных лимитов

Для SVG

{
    test: /\.svg$/,
    type: 'asset',
    parser: {
        dataUrlCondition: {
            maxSize: 2 * 1024
        }
    }
}

Для PNG

{
    test: /\.png$/,
    type: 'asset',
    parser: {
        dataUrlCondition: {
            maxSize: 1 * 1024
        }
    }
}

Inline и кеширование

Отдельный файл

logo.png

может кешироваться независимо.


Inline

main.js

содержит всё внутри себя.

Изменение одной строки JS:

console.log('test');

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


Влияние на Tree Shaking

Inline-ресурсы участвуют в графе зависимостей Webpack.

Если модуль не используется:

import icon from './icon.svg';

то изображение тоже удаляется из бандла.


Dev Server и inline

Во время разработки:

type: 'asset/inline'

ускоряет отображение мелких ресурсов, потому что dev server не отдаёт множество отдельных файлов.

Но слишком большие inline-данные ухудшают HMR и скорость обновления.


Source Map и Base64

Большие inline-ресурсы:

data:image/png;base64,...

могут сильно увеличивать размер source map.

Особенно проблемно:

  • при большом количестве SVG;
  • при встраивании шрифтов;
  • при inline PNG.

Пример комплексной конфигурации

module.exports = {
    module: {
        rules: [
            {
                test: /\.svg$/,
                type: 'asset/inline'
            },
            {
                test: /\.png$/,
                type: 'asset',
                parser: {
                    dataUrlCondition: {
                        maxSize: 2 * 1024
                    }
                }
            },
            {
                test: /\.(woff2|woff)$/i,
                type: 'asset/resource'
            }
        ]
    }
};

Практический подход

Наиболее распространённая стратегия:

Ресурс Подход
SVG-иконки inline
Мелкие PNG auto asset
Фото resource
Видео resource
Шрифты resource

Старый подход через url-loader

До Webpack 5 использовался:

url-loader

Пример:

{
    test: /\.png$/,
    use: {
        loader: 'url-loader',
        options: {
            lim it: 4096
        }
    }
}

В Webpack 5 этот механизм заменён Asset Modules.


Преимущества Asset Modules перед url-loader

Меньше зависимостей

Не нужны:

file-loader
url-loader
raw-loader

Проще конфигурация

Достаточно:

type: 'asset/inline'

Лучшая интеграция

Asset Modules встроены в ядро Webpack.


Частые ошибки

Inline больших изображений

Плохо:

banner.jpg — 500 KB

Результат:

  • огромный JS;
  • медленная загрузка;
  • плохой кеш.

Inline шрифтов большого размера

Проблемы:

  • раздутый CSS;
  • долгий парсинг;
  • ухудшение First Load.

Использование inline для всех ресурсов

Конфигурация:

{
    test: /\.(png|jpg|svg|woff2)$/,
    type: 'asset/inline'
}

обычно приводит к деградации производительности.


Inline и gzip

Хотя Base64 увеличивает размер файла, gzip частично компенсирует потери.

Особенно эффективно для:

  • SVG;
  • повторяющихся структур;
  • текстовых ресурсов.

Но бинарные PNG всё равно часто проигрывают отдельным файлам.


Inline и HTTP/2

Раньше inline активно использовался для уменьшения количества HTTP-запросов.

С появлением HTTP/2 ситуация изменилась:

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

Поэтому сегодня asset/inline применяется более избирательно.


Оптимальные сценарии использования

UI-иконки

menu.svg
close.svg
search.svg

Логотипы

Небольшие SVG-логотипы.


Встроенные preload-ресурсы

Критические изображения интерфейса.


Email-шаблоны

Inline помогает избежать внешних запросов.


Когда inline почти всегда вреден

Большие JPEG

hero.jpg
background.jpg

Видео

intro.mp4

Аудио

sound.mp3

Крупные шрифты

Roboto-Regular.woff2