В Webpack 5 механизм Asset Modules заменил многие
возможности file-loader, url-loader и
raw-loader. Один из наиболее важных режимов —
asset, автоматически выбирающий между двумя вариантами
обработки:
asset/inline);asset/resource).Решение принимается на основании размера ресурса. Именно для
настройки этого поведения используется параметр
parser.dataUrlCondition.
По умолчанию Webpack встраивает небольшие файлы в bundle как Base64-строку, а крупные сохраняет как отдельные файлы в каталоге сборки.
Тип asset работает как интеллектуальный гибрид:
{
test: /\.(png|jpg|svg)$/i,
type: 'asset'
}
При такой конфигурации Webpack:
анализирует размер ресурса;
сравнивает его с лимитом;
принимает решение:
Data URL — строковое представление бинарного файла.
Пример:
data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAA...
Такой контент может использоваться:
После встраивания браузеру не требуется отдельный HTTP-запрос для получения файла.
Встраивание ресурсов полезно только для небольших файлов.
Если inline применяется к крупным изображениям:
Поэтому Webpack использует ограничение размера.
Настройка производится внутри parser.
Пример:
module.exports = {
module: {
rules: [
{
test: /\.(png|jpg|gif)$/i,
type: 'asset',
parser: {
dataUrlCondition: {
maxSize: 8 * 1024
}
}
}
]
}
};
Здесь:
maxSize: 8 * 1024
означает:
8192 байта = 8 KB
Webpack сравнивает размер файла с указанным лимитом.
Если файл меньше:
размер <= maxSize
используется:
asset/inline
Если файл больше:
asset/resource
{
test: /\.svg$/i,
type: 'asset',
parser: {
dataUrlCondition: {
maxSize: 4 * 1024
}
}
}
| Файл | Размер | Результат |
|---|---|---|
| icon.svg | 2 KB | inline |
| logo.svg | 3 KB | inline |
| illustration.svg | 12 KB | resource |
Импорт:
import icon from './icon.svg';
После сборки:
const icon =
"data:image/svg+xml;base64,PHN2ZyB4bWxucz0...";
Импорт:
import image from './photo.png';
После сборки:
const image = "/assets/photo.a1b2c3.png";
Файл физически копируется в output-директорию.
Размер inline-ресурсов напрямую влияет на производительность.
Проблемы:
Проблемы:
Подходит для:
maxSize: 4 * 1024
Наиболее популярный вариант.
maxSize: 8 * 1024
Используется во многих production-конфигурациях.
Подходит для:
maxSize: 16 * 1024
SVG хорошо сжимается и часто имеет маленький размер.
Поэтому для SVG обычно используют более высокий лимит.
{
test: /\.svg$/i,
type: 'asset',
parser: {
dataUrlCondition: {
maxSize: 12 * 1024
}
}
}
PNG и JPG быстро увеличиваются в размере.
Для них обычно применяют меньший порог.
{
test: /\.(png|jpg|jpeg)$/i,
type: 'asset',
parser: {
dataUrlCondition: {
maxSize: 4 * 1024
}
}
}
Частая production-практика:
module.exports = {
module: {
rules: [
{
test: /\.svg$/i,
type: 'asset',
parser: {
dataUrlCondition: {
maxSize: 10 * 1024
}
}
},
{
test: /\.(png|jpg|gif)$/i,
type: 'asset',
parser: {
dataUrlCondition: {
maxSize: 4 * 1024
}
}
}
]
}
};
Base64 увеличивает размер данных примерно на:
~33%
Например:
| Исходный файл | После Base64 |
|---|---|
| 3 KB | ~4 KB |
| 6 KB | ~8 KB |
| 12 KB | ~16 KB |
Поэтому чрезмерный inline может существенно увеличить bundle.
Браузер кеширует файл отдельно:
logo.png
Если JavaScript изменился, изображение может остаться в кеше.
Изображение становится частью JS-файла.
При изменении bundle:
main.js
браузер заново скачивает и JavaScript, и встроенные ресурсы.
Inline уменьшает количество запросов:
HTML → JS → всё внутри
Это полезно для:
Но крупный inline:
module.exports = {
module: {
rules: [
{
test: /\.svg$/i,
type: 'asset',
parser: {
dataUrlCondition: {
maxSize: 10 * 1024
}
}
},
{
test: /\.(png|jpg|jpeg|gif)$/i,
type: 'asset',
parser: {
dataUrlCondition: {
maxSize: 5 * 1024
}
}
},
{
test: /\.(woff2?|ttf|eot)$/i,
type: 'asset/resource'
}
]
}
};
Шрифты:
Поэтому чаще применяется:
type: 'asset/resource'
а не inline.
dataUrlCondition может быть функцией.
Пример:
{
test: /\.png$/i,
type: 'asset',
parser: {
dataUrlCondition: (source, { filename }) => {
return source.length < 3 * 1024;
}
}
}
Функция позволяет:
{
test: /\.(png|svg)$/i,
type: 'asset',
parser: {
dataUrlCondition: (source, { filename }) => {
if (filename.includes('icons')) {
return source.length < 15 * 1024;
}
return source.length < 4 * 1024;
}
}
}
{
test: /\.svg$/i,
type: 'asset',
parser: {
dataUrlCondition: (source, { filename }) => {
return filename.includes('.icon.');
}
}
}
Если необходимо всегда создавать отдельные файлы:
{
test: /\.(png|jpg)$/i,
type: 'asset/resource'
}
Либо:
{
test: /\.(png|jpg)$/i,
type: 'asset',
parser: {
dataUrlCondition: {
maxSize: 0
}
}
}
{
test: /\.svg$/i,
type: 'asset/inline'
}
В этом случае dataUrlCondition уже не используется.
Автоматический выбор:
inline или resource
Всегда inline:
data:image/png;base64,...
Автоматическое решение по размеру.
Всегда отдельный файл.
Во времена HTTP/1.1 inline использовали значительно чаще, чтобы уменьшить количество запросов.
HTTP/2 изменил ситуацию:
Поэтому современные конфигурации используют более консервативные лимиты.
Webpack может использовать URI-кодирование вместо Base64 для SVG.
Это уменьшает размер строки.
Пример:
data:image/svg+xml,%3Csvg...
SVG особенно хорошо подходит для inline.
При большом количестве inline-ресурсов:
Для оценки влияния inline часто используют:
Особенно важно отслеживать:
Ошибка:
maxSize: 200 * 1024
Результат:
JPEG и PNG-фотографии редко подходят для inline.
Плохая практика:
test: /\.(jpg|jpeg)$/i,
type: 'asset/inline'
SVG и PNG имеют разные характеристики.
Лучше разделять правила.
На практике обычно используют:
| Тип файла | Стратегия |
|---|---|
| SVG-иконки | inline |
| Маленькие PNG | inline |
| Большие изображения | resource |
| Шрифты | resource |
| Видео | resource |
module.exports = {
module: {
rules: [
{
test: /\.svg$/i,
type: 'asset',
parser: {
dataUrlCondition: {
maxSize: 8 * 1024
}
}
},
{
test: /\.(png|jpg|jpeg|gif)$/i,
type: 'asset',
parser: {
dataUrlCondition: {
maxSize: 4 * 1024
}
}
},
{
test: /\.(woff2?|ttf|eot)$/i,
type: 'asset/resource'
}
]
}
};