Плагины в Webpack предназначены для расширения возможностей сборщика. Если loaders работают на уровне преобразования отдельных файлов, то plugins вмешиваются в процесс сборки целиком: изменяют выходные файлы, управляют оптимизацией, внедряют переменные окружения, очищают директории, генерируют HTML, анализируют бандлы и выполняют десятки других задач.
Плагин представляет собой JavaScript-класс или объект, подключаемый
через секцию plugins в конфигурации Webpack.
Базовая структура:
module.exports = {
plugins: [
// экземпляры плагинов
]
};
Большинство плагинов подключаются через оператор
new.
Пример:
const HtmlWebpackPlugin = require('html-webpack-plugin');
module.exports = {
plugins: [
new HtmlWebpackPlugin()
]
};
Loaders обрабатывают конкретные файлы.
Примеры:
babel-loadercss-loadersass-loaderОни работают через секцию module.rules.
module.exports = {
module: {
rules: [
{
test: /\.js$/,
use: 'babel-loader'
}
]
}
};
Plugins влияют на весь процесс сборки.
Примеры задач:
dist;Все плагины подключаются внутри массива plugins.
module.exports = {
plugins: []
};
Пример подключения нескольких плагинов:
const HtmlWebpackPlugin = require('html-webpack-plugin');
const MiniCssExtractPlugin = require('mini-css-extract-plugin');
module.exports = {
plugins: [
new HtmlWebpackPlugin(),
new MiniCssExtractPlugin()
]
};
Порядок подключения иногда имеет значение, особенно если плагины работают с одними и теми же ресурсами.
Большинство плагинов устанавливаются через npm.
Пример:
npm install html-webpack-plugin --save-dev
После установки плагин импортируется в конфигурацию.
const HtmlWebpackPlugin = require('html-webpack-plugin');
Один из самых популярных плагинов Webpack.
Назначение:
npm install html-webpack-plugin --save-dev
const HtmlWebpackPlugin = require('html-webpack-plugin');
module.exports = {
plugins: [
new HtmlWebpackPlugin()
]
};
Webpack создаст HTML-файл автоматически.
Чаще всего используется собственный шаблон.
Структура проекта:
src/
index.js
index.html
Конфигурация:
const HtmlWebpackPlugin = require('html-webpack-plugin');
module.exports = {
plugins: [
new HtmlWebpackPlugin({
template: './src/index.html'
})
]
};
new HtmlWebpackPlugin({
filename: 'main.html'
})
Результат:
dist/
main.html
new HtmlWebpackPlugin({
template: './src/index.html',
title: 'Webpack Application'
})
В шаблоне:
<title><%= htmlWebpackPlugin.options.title %></title>
Используется для очистки папки сборки перед созданием новых файлов.
Без очистки старые файлы могут накапливаться в dist.
npm install clean-webpack-plugin --save-dev
const { CleanWebpackPlugin } = require('clean-webpack-plugin');
module.exports = {
plugins: [
new CleanWebpackPlugin()
]
};
Извлекает CSS в отдельные файлы.
Без него стили часто встраиваются в JavaScript.
npm install mini-css-extract-plugin --save-dev
const MiniCssExtractPlugin = require('mini-css-extract-plugin');
module.exports = {
module: {
rules: [
{
test: /\.css$/,
use: [
MiniCssExtractPlugin.loader,
'css-loader'
]
}
]
},
plugins: [
new MiniCssExtractPlugin({
filename: 'css/style.css'
})
]
};
Плагин для создания глобальных констант.
Чаще всего используется для переменных окружения.
const webpack = require('webpack');
module.exports = {
plugins: [
new webpack.DefinePlugin({
API_URL: JSON.stringify('https://api.site.com')
})
]
};
Использование:
console.log(API_URL);
new webpack.DefinePlugin({
'process.env.NODE_ENV': JSON.stringify('production')
})
Копирует файлы без обработки.
Подходит для:
npm install copy-webpack-plugin --save-dev
const CopyWebpackPlugin = require('copy-webpack-plugin');
module.exports = {
plugins: [
new CopyWebpackPlugin({
patterns: [
{
from: 'public',
to: ''
}
]
})
]
};
Создаёт gzip-версии файлов.
npm install compression-webpack-plugin --save-dev
const CompressionPlugin = require('compression-webpack-plugin');
module.exports = {
plugins: [
new CompressionPlugin()
]
};
Используется для анализа размера бандла.
Позволяет определить:
npm install webpack-bundle-analyzer --save-dev
const { BundleAnalyzerPlugin } = require('webpack-bundle-analyzer');
module.exports = {
plugins: [
new BundleAnalyzerPlugin()
]
};
После сборки открывается интерактивная диаграмма.
Обеспечивает горячую замену модулей без полной перезагрузки страницы.
const webpack = require('webpack');
module.exports = {
devServer: {
hot: true
},
plugins: [
new webpack.HotModuleReplacementPlugin()
]
};
Автоматически импортирует модули.
Пример с jQuery:
const webpack = require('webpack');
module.exports = {
plugins: [
new webpack.ProvidePlugin({
$: 'jquery',
jQuery: 'jquery'
})
]
};
Теперь можно использовать:
$('.menu').hide();
Без явного импорта:
import $ from 'jquery';
Позволяет исключать ненужные зависимости.
Пример:
const webpack = require('webpack');
module.exports = {
plugins: [
new webpack.IgnorePlugin({
resourceRegExp: /^\.\/locale$/,
contextRegExp: /moment$/
})
]
};
Этот код исключает локализации библиотеки moment.
Отображает прогресс сборки.
const webpack = require('webpack');
module.exports = {
plugins: [
new webpack.ProgressPlugin()
]
};
Упрощённая версия DefinePlugin.
const webpack = require('webpack');
module.exports = {
plugins: [
new webpack.EnvironmentPlugin([
'NODE_ENV'
])
]
};
Используется для минификации JavaScript.
Webpack 5 уже включает его автоматически в production-режиме, однако возможна ручная настройка.
const TerserPlugin = require('terser-webpack-plugin');
module.exports = {
optimization: {
minimizer: [
new TerserPlugin()
]
}
};
Минифицирует CSS.
npm install css-minimizer-webpack-plugin --save-dev
const CssMinimizerPlugin = require('css-minimizer-webpack-plugin');
module.exports = {
optimization: {
minimizer: [
'...',
new CssMinimizerPlugin()
]
}
};
'...' сохраняет стандартные minimizer-плагины
Webpack.
Автоматически генерирует favicon разных размеров.
npm install favicons-webpack-plugin --save-dev
const FaviconsWebpackPlugin = require('favicons-webpack-plugin');
module.exports = {
plugins: [
new FaviconsWebpackPlugin('./src/logo.png')
]
};
Подгружает переменные из .env.
npm install dotenv-webpack --save-dev
const Dotenv = require('dotenv-webpack');
module.exports = {
plugins: [
new Dotenv()
]
};
В реальных проектах используется множество плагинов одновременно.
Пример production-конфигурации:
const HtmlWebpackPlugin = require('html-webpack-plugin');
const MiniCssExtractPlugin = require('mini-css-extract-plugin');
const CssMinimizerPlugin = require('css-minimizer-webpack-plugin');
const { CleanWebpackPlugin } = require('clean-webpack-plugin');
module.exports = {
mode: 'production',
module: {
rules: [
{
test: /\.css$/,
use: [
MiniCssExtractPlugin.loader,
'css-loader'
]
}
]
},
plugins: [
new CleanWebpackPlugin(),
new HtmlWebpackPlugin({
template: './src/index.html'
}),
new MiniCssExtractPlugin({
filename: 'css/style.[contenthash].css'
})
],
optimization: {
minimizer: [
'...',
new CssMinimizerPlugin()
]
}
};
Часто плагины подключаются только в определённом режиме.
Пример:
const isProd = process.env.NODE_ENV === 'production';
module.exports = {
plugins: [
...(isProd ? [
new MiniCssExtractPlugin()
] : [])
]
};
const plugins = [];
if (process.env.NODE_ENV === 'production') {
plugins.push(new MiniCssExtractPlugin());
}
module.exports = {
plugins
};
Плагин представляет собой класс с методом apply.
Простейший пример:
class MyPlugin {
apply(compiler) {
console.log('Webpack plugin initialized');
}
}
module.exports = MyPlugin;
Подключение:
const MyPlugin = require('./MyPlugin');
module.exports = {
plugins: [
new MyPlugin()
]
};
compiler предоставляет доступ к внутренним механизмам
Webpack.
Через него можно:
Webpack использует систему hooks.
Пример:
class MyPlugin {
apply(compiler) {
compiler.hooks.done.tap(
'MyPlugin',
() => {
console.log('Build finished');
}
);
}
}
Вызывается перед запуском сборки.
compiler.hooks.beforeRun.tap('Plugin', () => {});
Запуск compiler.
compiler.hooks.run.tap('Plugin', () => {});
Перед записью файлов.
compiler.hooks.emit.tap('Plugin', compilation => {});
После завершения сборки.
compiler.hooks.done.tap('Plugin', stats => {});
Синхронный хук.
compiler.hooks.done.tap('Plugin', () => {});
Асинхронный вариант.
compiler.hooks.emit.tapAsync(
'Plugin',
(compilation, callback) => {
callback();
}
);
Работа через Promise.
compiler.hooks.emit.tapPromise(
'Plugin',
async compilation => {
}
);
class BuildInfoPlugin {
apply(compiler) {
compiler.hooks.emit.tap(
'BuildInfoPlugin',
compilation => {
compilation.assets['build.txt'] = {
source: () => 'Build completed',
size: () => 15
};
}
);
}
}
Неправильно:
plugins: [
HtmlWebpackPlugin()
]
Правильно:
plugins: [
new HtmlWebpackPlugin()
]
const HtmlWebpackPlugin = require('html-webpack-plugin');
Некоторые плагины зависят друг от друга.
Например:
Webpack содержит собственные плагины:
DefinePluginProvidePluginEnvironmentPluginHotModuleReplacementPluginIgnorePluginProgressPluginПодключаются через объект webpack.
const webpack = require('webpack');
const path = require('path');
const HtmlWebpackPlugin = require('html-webpack-plugin');
const MiniCssExtractPlugin = require('mini-css-extract-plugin');
const CssMinimizerPlugin = require('css-minimizer-webpack-plugin');
const { CleanWebpackPlugin } = require('clean-webpack-plugin');
module.exports = {
mode: 'production',
entry: './src/index.js',
output: {
path: path.resolve(__dirname, 'dist'),
filename: 'js/main.[contenthash].js'
},
module: {
rules: [
{
test: /\.css$/,
use: [
MiniCssExtractPlugin.loader,
'css-loader'
]
}
]
},
plugins: [
new CleanWebpackPlugin(),
new HtmlWebpackPlugin({
template: './src/index.html'
}),
new MiniCssExtractPlugin({
filename: 'css/style.[contenthash].css'
})
],
optimization: {
minimizer: [
'...',
new CssMinimizerPlugin()
]
}
};