Тип resource в системе Asset Modules предназначен для
физического вынесения файла в директорию сборки. В отличие от
asset/inline, который преобразует содержимое файла в
Base64-строку и внедряет её в JavaScript или CSS, тип
resource создаёт отдельный файл в папке output
и возвращает путь к нему.
Такой механизм заменяет работу file-loader,
использовавшегося в Webpack 4 и более ранних версиях.
resourceПри импорте файла Webpack:
Пример импорта изображения:
import logo from './images/logo.png';
console.log(logo);
После сборки значение переменной logo может выглядеть
так:
/images/a1b2c3d4.png
При этом сам файл физически появится в директории сборки:
dist/
└── images/
└── a1b2c3d4.png
Простейшая конфигурация:
module.exports = {
module: {
rules: [
{
test: /\.(png|jpg|jpeg|gif)$/i,
type: 'asset/resource'
}
]
}
};
Теперь все изображения:
Тип resource не возвращает содержимое файла.
Он возвращает строку URL.
Пример:
import image from './image.png';
const img = document.createElement('img');
img.src = image;
document.body.append(img);
Webpack:
src.assetТип asset автоматически выбирает:
Выбор зависит от размера файла.
Тип asset/resource всегда:
asset/inlineasset/inlinetype: 'asset/inline'
Результат:
data:image/png;base64,...
Файл не создаётся.
asset/resourcetype: 'asset/resource'
Результат:
dist/images/file.png
Файл существует физически.
asset/sourceasset/source возвращает текстовое содержимое файла:
import svg from './icon.svg';
console.log(svg);
Результат:
<svg>...</svg>
resource вместо содержимого возвращает URL.
file-loaderСтарый способ:
{
test: /\.(png|jpg)$/i,
use: [
{
loader: 'file-loader'
}
]
}
Современный вариант:
{
test: /\.(png|jpg)$/i,
type: 'asset/resource'
}
Asset Modules:
По умолчанию Webpack создаёт хэшированные имена:
a7d9f2e1.png
Это необходимо для:
Для изменения имени используется generator.filename.
Пример:
module.exports = {
module: {
rules: [
{
test: /\.(png|jpg)$/i,
type: 'asset/resource',
generator: {
filename: 'images/[name][ext]'
}
}
]
}
};
Результат:
dist/
└── images/
└── logo.png
[name]Имя файла без расширения.
logo
[ext]Расширение файла.
.png
[hash]Хэш содержимого.
a1b2c3
[contenthash]Хэш содержимого файла.
Используется чаще всего для долгосрочного кэширования.
[query]Строка запроса.
generator: {
filename: 'assets/images/[name].[contenthash][ext]'
}
Результат:
assets/images/logo.a12f8e1d.png
Разные типы файлов можно раскладывать по разным директориям.
{
test: /\.(png|jpg|gif)$/i,
type: 'asset/resource',
generator: {
filename: 'images/[name].[hash][ext]'
}
}
{
test: /\.(woff2?|eot|ttf|otf)$/i,
type: 'asset/resource',
generator: {
filename: 'fonts/[name][ext]'
}
}
{
test: /\.(mp4|webm)$/i,
type: 'asset/resource',
generator: {
filename: 'video/[name][ext]'
}
}
При использовании css-loader ссылки из CSS автоматически
обрабатываются Webpack.
Пример:
background-image: url('./images/bg.png');
Webpack:
asset/resource;Результат:
background-image: url(/images/a1b2c3.png);
SVG часто обрабатываются через resource.
{
test: /\.svg$/i,
type: 'asset/resource'
}
Импорт:
import icon from './icon.svg';
Использование:
img.src = icon;
Типичный пример:
@font-face {
font-family: 'Roboto';
src: url('./fonts/Roboto.woff2') format('woff2');
}
Webpack:
publicPathИногда файлы должны загружаться не из корня сайта, а из CDN или другого пути.
Используется:
output: {
publicPath: '/static/'
}
Теперь URL станет:
/static/images/logo.png
publicPathМожно задавать путь отдельно для конкретного правила.
{
test: /\.(png|jpg)$/i,
type: 'asset/resource',
generator: {
publicPath: '/assets/'
}
}
Пример:
output: {
publicPath: 'https://cdn.example.com/'
}
Webpack будет генерировать:
https://cdn.example.com/images/logo.png
outputPathМожно управлять физическим расположением файлов.
generator: {
outputPath: 'images'
}
publicPath и outputPathoutputPathОпределяет:
куда файл записывается на диске
publicPathОпределяет:
какой URL получит браузер
{
test: /\.(png|jpg)$/i,
type: 'asset/resource',
generator: {
outputPath: 'static/images',
publicPath: '/cdn/images/',
filename: '[name][ext]'
}
}
Хэширование файлов позволяет браузеру:
Обычно используется:
filename: 'images/[contenthash][ext]'
Если файл не изменился:
logo.a1b2c3.png
останется прежним.
Если содержимое изменится:
logo.f8d9e2.png
Браузер увидит новый URL и скачает обновлённую версию.
resource особенно важен для:
Встраивание таких файлов через Base64 привело бы к:
{
test: /\.pdf$/i,
type: 'asset/resource',
generator: {
filename: 'docs/[name][ext]'
}
}
Использование:
import manual from './manual.pdf';
link.href = manual;
{
test: /\.(mp3|wav)$/i,
type: 'asset/resource',
generator: {
filename: 'audio/[name][ext]'
}
}
{
test: /\.(mp4|webm)$/i,
type: 'asset/resource',
generator: {
filename: 'video/[name][ext]'
}
}
Webpack сам:
При генерации HTML:
<img src="./logo.png">
Webpack:
import avatar from './avatar.jpg';
document.querySelector('.avatar').src = avatar;
Webpack гарантирует:
const image = await import('./image.png');
Результат:
image.default
содержит URL ресурса.
Ресурсы автоматически связываются с чанками.
Если изображение используется только в ленивом модуле:
import('./gallery');
то ресурс загрузится только вместе с этим чанком.
В production-сборке:
Типичный шаблон:
filename: 'assets/[contenthash][ext]'
testОшибка:
test: /\.png$/
не обрабатывает JPG и GIF.
Лучше:
test: /\.(png|jpg|gif)$/i
Нельзя одновременно использовать:
type: 'asset/resource'
и:
file-loader
Это приведёт к дублированию обработки.
publicPathЕсли путь задан неправильно:
404 Not Found
в браузере.
Ошибка:
filename: 'images/[name]'
Результат:
logo
без .png.
Следует использовать:
filename: 'images/[name][ext]'
Тип resource:
Особенно заметно это:
asset/resourceТип resource подходит для:
resourceНе рекомендуется для:
В таких случаях чаще используют:
type: 'asset/inline'
или:
type: 'asset'
с автоматическим выбором стратегии.