Оптимизация изображений является одной из ключевых задач
фронтенд-сборки. Размер графических ресурсов напрямую влияет на скорость
загрузки, показатель Largest Contentful Paint (LCP), время рендеринга и
потребление трафика. В Webpack обработка изображений давно вышла за
пределы простого копирования файлов в директорию dist.
Современные проекты используют автоматическую генерацию оптимизированных
форматов, сжатие, адаптивные размеры и конвертацию изображений во время
сборки.
Наиболее востребованными форматами для веба стали WebP и AVIF. Оба обеспечивают значительно меньший размер файлов по сравнению с JPEG и PNG при сохранении качества изображения.
Формат WebP разработан компанией Google как универсальная замена JPEG, PNG и GIF.
| Формат | Размер |
|---|---|
| JPEG | 420 KB |
| WebP | 240 KB |
При большом количестве изображений экономия становится существенной.
AVIF считается следующим поколением оптимизированной веб-графики.
| Формат | Размер |
|---|---|
| JPEG | 420 KB |
| WebP | 240 KB |
| AVIF | 160 KB |
Поддерживается практически всеми современными браузерами:
Поддержка AVIF появилась позже:
В старых браузерах AVIF может отсутствовать, поэтому обычно используется fallback.
Webpack 5 содержит встроенные Asset Modules, которые заменили:
Для изображений чаще всего используется:
type: 'asset/resource'
module.exports = {
module: {
rules: [
{
test: /\.(png|jpg|jpeg|gif|svg)$/i,
type: 'asset/resource',
},
],
},
}
Webpack будет:
dist;Современные проекты обычно расширяют правило:
module.exports = {
module: {
rules: [
{
test: /\.(png|jpg|jpeg|webp|avif)$/i,
type: 'asset/resource',
},
],
},
}
Теперь Webpack умеет импортировать:
import image from './photo.avif'
module.exports = {
module: {
rules: [
{
test: /\.(png|jpg|jpeg|webp|avif)$/i,
type: 'asset/resource',
generator: {
filename: 'images/[name].[contenthash][ext]',
},
},
],
},
}
Сам Webpack не выполняет сжатие изображений. Для этого используются дополнительные плагины.
Наиболее популярный инструмент:
npm install image-minimizer-webpack-plugin imagemin --save-dev
Дополнительно устанавливаются кодеки:
npm install imagemin-webp imagemin-avif --save-dev
const ImageMinimizerPlugin = require('image-minimizer-webpack-plugin')
module.exports = {
optimization: {
minimizer: [
new ImageMinimizerPlugin({
minimizer: {
implementation:
ImageMinimizerPlugin.imageminMinify,
options: {
plugins: [
['imagemin-mozjpeg', {
quality: 75,
}],
['imagemin-pngquant', {
quality: [0.6, 0.8],
}],
],
},
},
}),
],
},
}
Webpack может автоматически создавать WebP-версии файлов во время сборки.
npm install imagemin-webp --save-dev
const ImageMinimizerPlugin = require('image-minimizer-webpack-plugin')
module.exports = {
optimization: {
minimizer: [
new ImageMinimizerPlugin({
generator: [
{
preset: 'webp',
implementation:
ImageMinimizerPlugin.imageminGenerate,
filename: '[path][name].webp',
options: {
plugins: [
['imagemin-webp', {
quality: 80,
}],
],
},
},
],
}),
],
},
}
Исходный файл:
photo.jpg
После сборки:
photo.jpg
photo.webp
Webpack создаёт дополнительный оптимизированный формат автоматически.
npm install imagemin-avif --save-dev
const ImageMinimizerPlugin = require('image-minimizer-webpack-plugin')
module.exports = {
optimization: {
minimizer: [
new ImageMinimizerPlugin({
generator: [
{
preset: 'avif',
implementation:
ImageMinimizerPlugin.imageminGenerate,
filename: '[path][name].avif',
options: {
plugins: [
['imagemin-avif', {
quality: 50,
}],
],
},
},
],
}),
],
},
}
Часто используются сразу оба формата.
const ImageMinimizerPlugin = require('image-minimizer-webpack-plugin')
module.exports = {
optimization: {
minimizer: [
new ImageMinimizerPlugin({
generator: [
{
preset: 'webp',
implementation:
ImageMinimizerPlugin.imageminGenerate,
filename: '[path][name].webp',
options: {
plugins: [
['imagemin-webp', {
quality: 80,
}],
],
},
},
{
preset: 'avif',
implementation:
ImageMinimizerPlugin.imageminGenerate,
filename: '[path][name].avif',
options: {
plugins: [
['imagemin-avif', {
quality: 50,
}],
],
},
},
],
}),
],
},
}
<picture>Для корректной работы fallback обычно применяется тег
<picture>.
<picture>
<source
srcset="photo.avif"
type="image/avif"
/>
<source
srcset="photo.webp"
type="image/webp"
/>
<img
src="photo.jpg"
alt="Photo"
/>
</picture>
Браузер выбирает:
import photoJpg from './photo.jpg'
import photoWebp from './photo.webp'
import photoAvif from './photo.avif'
В проектах с Pug, Handlebars или HTMLWebpackPlugin часто используются динамические пути:
<img src="<%= photo %>" />
Некоторые плагины умеют автоматически заменять изображения в HTML.
Например:
Плагин умеет:
npm install responsive-loader sharp --save-dev
module.exports = {
module: {
rules: [
{
test: /\.(png|jpg|jpeg)$/i,
use: [
{
loader: 'responsive-loader',
options: {
adapter: require('responsive-loader/sharp'),
sizes: [320, 640, 1280],
format: 'webp',
},
},
],
},
],
},
}
Webpack создаёт:
image-320.webp
image-640.webp
image-1280.webp
<img
srcset="
image-320.webp 320w,
image-640.webp 640w,
image-1280.webp 1280w
"
sizes="(max-width: 768px) 100vw, 50vw"
src="image-640.webp"
alt=""
/>
Библиотека Sharp является одним из самых быстрых инструментов обработки изображений в Node.js.
const sharp = require('sharp')
sharp('input.jpg')
.webp({ quality: 80 })
.toFile('output.webp')
const sharp = require('sharp')
sharp('input.jpg')
.avif({ quality: 50 })
.toFile('output.avif')
Многие плагины используют Sharp как backend:
Ещё один популярный загрузчик:
npm install image-webpack-loader --save-dev
module.exports = {
module: {
rules: [
{
test: /\.(png|jpg|gif)$/i,
use: [
{
loader: 'file-loader',
},
{
loader: 'image-webpack-loader',
options: {
mozjpeg: {
progressive: true,
quality: 75,
},
webp: {
quality: 80,
},
},
},
],
},
],
},
}
Сжатие существующего файла:
photo.jpg → photo.jpg
Размер уменьшается.
Создание нового формата:
photo.jpg → photo.webp
photo.jpg → photo.avif
Небольшие изображения можно встраивать как Data URL.
module.exports = {
module: {
rules: [
{
test: /\.(png|webp)$/i,
type: 'asset',
parser: {
dataUrlCondition: {
maxSize: 8 * 1024,
},
},
},
],
},
}
Несмотря на преимущества, AVIF имеет особенности.
Сборка проекта может стать значительно медленнее.
Особенно заметно при CI/CD.
Для маленьких иконок WebP может оказаться эффективнее.
WebP хорошо подходит для:
AVIF особенно эффективен для:
Наиболее распространённый современный подход:
| Формат | Назначение |
|---|---|
| AVIF | основной |
| WebP | fallback |
| JPEG/PNG | поддержка старых браузеров |
Использование AVIF и WebP положительно влияет на:
Lighthouse напрямую рекомендует современные форматы изображений.
Хеширование особенно важно для изображений.
generator: {
filename: 'images/[name].[contenthash][ext]'
}
Преимущества:
output: {
publicPath: 'https://cdn.example.com/',
}
Изображения будут загружаться через CDN.
Современные браузеры поддерживают:
<img
src="photo.webp"
loading="lazy"
alt=""
>
<link
rel="preload"
as="image"
href="/images/hero.avif"
>
Даже favicon можно хранить в WebP или AVIF, если браузер поддерживает формат.
SVG обычно не конвертируют в WebP или AVIF, поскольку:
src/
assets/
images/
dist/
images/
photo.webp
photo.avif
photo.jpg
const ImageMinimizerPlugin =
require('image-minimizer-webpack-plugin')
module.exports = {
mode: 'production',
module: {
rules: [
{
test: /\.(png|jpg|jpeg|webp|avif)$/i,
type: 'asset/resource',
generator: {
filename:
'images/[name].[contenthash][ext]',
},
},
],
},
optimization: {
minimizer: [
'...',
new ImageMinimizerPlugin({
minimizer: {
implementation:
ImageMinimizerPlugin.imageminMinify,
options: {
plugins: [
['imagemin-mozjpeg', {
quality: 75,
}],
],
},
},
generator: [
{
preset: 'webp',
implementation:
ImageMinimizerPlugin.imageminGenerate,
filename:
'[path][name][ext].webp',
options: {
plugins: [
['imagemin-webp', {
quality: 80,
}],
],
},
},
{
preset: 'avif',
implementation:
ImageMinimizerPlugin.imageminGenerate,
filename:
'[path][name][ext].avif',
options: {
plugins: [
['imagemin-avif', {
quality: 50,
}],
],
},
},
],
}),
],
},
}