- PVSM.RU - https://www.pvsm.ru -
Доброго времени суток. Этим постом хочу начать серию статей про новые возможности грядущего webpack 5. Почему я хочу рассказывать про webpack? Как минимум потому, что я принимаю активное участие в его разработке и постоянно копаюсь в его внутренностях. В данном посте хочу рассказать про Asset Modules — экспериментальную фичу webpack 5, которая позволяет избавиться от нескольких привычных лоадеров, сохранив при этом их пользу.
Представим, что нам нужно собрать страницу с картинками и стилями.
Конфигурация webpack 4 под эту задачу может выглядеть следующим образом:
webpack.config.js
module.exports = {
module: {
rules: [
{
test: /.svg$/,
use: [
'file-loader',
'svgo-loader'
]
},
{
test: /.css$/,
use: [
'style-loader',
'css-loader'
]
}
]
}
};
src/index.js
import './styles.css';
// ...
src/styles.css
.logo {
background: url("/images/logo.svg") no-repeat;
background-size: cover;
width: 75px;
height: 65px;
}
Вывод:
/dist/main.js
/dist/eb4c5fa504857.svg
При таком подходе все svg-файлы будут обработаны при помощи svgo [1] и при помощи file-loader [2] помещены в директорию с собранным бандлом, а css, при помощи css-loader [3], превратится в нечто подобное:
.logo {
background: url("eb4c5fa504857.svg") no-repeat;
background-size: cover;
width: 75px;
height: 65px;
}
В какой-то момент нам может понадобиться оптимизировать нашу страничку и мы можем захотеть инлайнить изображения прямо в css. Для этого заменим file-loader на url-loader [4]:
{
test: /.svg$/,
use: [
- 'file-loader',
+ 'url-loader',
'svgo-loader'
]
},
Вывод:
/dist/main.js
Собранный css изменится следующим образом:
- background: url("eb4c5fa504857.svg") no-repeat;
+ background: url("data:image/svg+xml;base64,....") no-repeat;
Далее мы можем захотеть инлайнить только небольшие по размеру svg (например, до 8кб), а все остальные оставлять в виде отдельно лежащих файлов. Для этого, у url-loader есть специальная настройка limit:
{
test: /.svg$/,
use: [
- 'url-loader',
+ 'url-loader?limit=8192',
'svgo-loader'
]
},
После этого, инлайниться будут только svg-файлы до 8кб, остальные svg будут помещены в директорию с собранным бандлом, для них url-loader будет неявно использовать file-loader.
Задача решена, но с использованием webpack 5 и фичи Asset Modules, она решается проще, позволяя избавиться от url-loader и file-loader (его url-loader неявно использует для файлов, размером больше, чем указано в опции limit).
Для начала, необходимо явно указать, что мы хотим использовать Asset Modules. Для этого добавим в конфигурацию следующее:
module.exports = {
// ...
+ experiments: {
+ asset: true
+ }
};
На данный момент это экспериментальная фича и мы ждем от пользователей обратную связь по ее использованию.
После этого, достаточно просто пометить svg-файлы как asset и всё то, что было описано выше касаемо file-loader и url-loader — заработает само, из коробки, без каких-либо лоадеров:
{
test: /.svg$/,
- use: [
- 'url-loader?limit=8000',
- 'svgo-loader'
- ]
+ type: 'asset',
+ use: 'svgo-loader'
},
Вот и всё, для файлов, которые попадают под правило с type: 'asset' будет применяться следующая логика: Если файл меньше 8кб (по умолчанию), то встроить его в собранный бандл, в ином случае поместить его в директорию с собранным бандлом.
Свойство use так же учитывается.
Помимо asset есть и другие встроенные типы модулей.
Это аналог url-loader. Файлы, которые будут подпадать под правило с type: 'asset/inline' будут всегда инлайниться в бандл в виде data-url:
{
test: /.svg$/,
- type: 'asset',
+ type: 'asset/inline',
use: 'svgo-loader'
},
Более того, для type: 'asset/inline' можно задавать кастомный генератор data-url.
Например, для svg-файлов можно использовать mini-svg-data-uri, который инлайнит svg как data-url, но без использования base64, что позволяет уменьшить размер встроенного фрагмента:
+ const miniSVGDataURI = require('mini-svg-data-uri');
// ...
{
test: /.svg$/,
type: 'asset/inline',
+ generator: {
+ dataUrl(content) {
+ content = content.toString();
+ return miniSVGDataURI(content);
+ }
+ },
use: 'svgo-loader'
},
В результате получим такой css:
- background: url("data:image/svg+xml;base64,....") no-repeat;
+ background: url("data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg'....") no-repeat;
Таким образом можно совмещать использование лоадеров и кастомное поведение для генерирования data-url.
Это аналог file-loader [2]. Файлы, которые будут подпадать под правило с type: 'asset/resource' будут складываться в директорию с бандлом:
{
test: /.svg$/,
- type: 'asset/inline',
+ type: 'asset/resource',
- generator: {
- dataUrl(content) {
- content = content.toString();
- return miniSVGDataURI(content);
- }
- },
use: 'svgo-loader'
},
По умолчанию, модули с типом asset/resource складываются в директорию, которую вы указываете в output.path (по умолчанию dist), но при помощи output.assetModuleFilename можно переопределить это поведение:
module.exports = {
+ output: {
+ assetModuleFilename: 'assets/[name][ext]'
+ },
// ...
};
Вывод:
/dist/main.js
/dist/assets/logo.svg
А заменив [name] на [hash] мы получим прекрасный вариант для long term caching:
module.exports = {
output: {
- assetModuleFilename: 'assets/[name][ext]'
+ assetModuleFilename: 'assets/[hash][ext]'
},
// ...
};
Вывод:
/dist/main.js
/dist/assets/eb4c5fa504857.svg
Более того, мы можем переопределить имя выходного файла для конкретного asset-правила. Например, можно складывать svg-иконки в директорию dist/icons, а остальные asset-модули в директорию dist/assets:
{
test: /.svg$/,
type: 'asset/resource',
+ generator: {
+ filename: 'icons/[hash][ext]'
+ },
use: 'svgo-loader'
Вывод:
/dist/main.js
/dist/assets/fd441ca8b6d00.png
/dist/icons/eb4c5fa504857.svg
Это аналог raw-loader [5]. Файлы, которые будут подпадать под правило с type: 'asset/source' будут всегда инлайниться в бандл в неизменном виде:
file.txt
hello world
webpack.config.js
module.exports = {
// ...
{
test: /.svg$/,
type: 'asset/resource',
generator: {
filename: 'icons/[hash][ext]'
},
use: 'svgo-loader'
},
+ {
+ test: /.txt$/,
+ type: 'asset/source'
+ },
// ...
index.js
import './styles.css';
+ import txt from './file.txt';
+ console.log(txt); // hello world
Вывод:
/dist/main.js
/dist/icons/eb4c5fa504857.svg
Объединяет в себе asset/resource и asset/inline, автоматически выбирая что-то одно, в зависимости от некоторых условий. По умолчанию, если размер файла больше 8кб, то применяется стратегия asset/resource, в ином случае — asset/inline.
module.exports = {
// ...
{
test: /.svg$/,
- type: 'asset/resource',
+ type: 'asset'
- generator: {
- filename: 'icons/[hash][ext]'
- },
use: 'svgo-loader'
},
{
test: /.txt$/,
type: 'asset/source'
},
// ...
Лимит для применения asset/inline можно установить:
{
test: /.svg$/,
type: 'asset',
+ parser: {
+ dataUrlCondition: {
+ maxSize: 20 * 1024 // 20kb
+ }
+ },
use: 'svgo-loader'
},
Подводя итог: Asset Modules в webpack 5 позволяют отказаться от некоторых привычных лоадеров за счет поддержки их функциональности "из коробки".
Полноценный пример можно посмотреть здесь [6].
Пока нет точной даты выхода. На момент написания этого гайда, последней версией webpack 5 является beta.13, собирается обратная связь. Вы можете помочь в сборе обратной связи, попытавшись перенести свой проект на webpack 5 (конечно же, пока не используя его а production). Подробнее здесь [7]
Я и дальше планирую рассказывать о новых возможностях webpack 5 и о самом webpack. Некоторые из статей будут побольше, некоторые поменьше, а совсем мелкие заметки (не только про webpack) можно будет наблюдать в моем телеграмм-канале [8].
Спасибо за внимание.
Автор: Сергей Мелюков
Источник [9]
Сайт-источник PVSM.RU: https://www.pvsm.ru
Путь до страницы источника: https://www.pvsm.ru/javascript/346787
Ссылки в тексте:
[1] svgo: https://github.com/svg/svgo
[2] file-loader: https://github.com/webpack-contrib/file-loader
[3] css-loader: https://github.com/webpack-contrib/css-loader
[4] url-loader: https://github.com/webpack-contrib/url-loader
[5] raw-loader: https://github.com/webpack-contrib/raw-loader
[6] здесь: https://github.com/wdxlab/articles/tree/master/webpack-asset-modules
[7] здесь: https://github.com/webpack/webpack/issues/9802
[8] телеграмм-канале: https://t.me/wdxlab
[9] Источник: https://habr.com/ru/post/488464/?utm_source=habrahabr&utm_medium=rss&utm_campaign=488464
Нажмите здесь для печати.