Webpack Plugins
Зачем нужно
Plugins расширяют возможности Webpack на этапе сборки. Если loaders трансформируют отдельные файлы, то plugins работают с результатом сборки целиком: генерируют HTML, извлекают CSS в отдельные файлы, определяют переменные окружения, анализируют размер бандла.
Где используется
- Генерация HTML с подключёнными бандлами
- Извлечение CSS в отдельные файлы для production
- Определение переменных окружения (API URL, версия)
- Анализ размера бандла и оптимизация
- Копирование статических файлов, очистка dist
HtmlWebpackPlugin
Генерирует HTML-файл и автоматически подключает бандлы:
npm install --save-dev html-webpack-plugin
const HtmlWebpackPlugin = require('html-webpack-plugin');
module.exports = {
plugins: [
new HtmlWebpackPlugin({
template: './src/index.html', // Шаблон
filename: 'index.html', // Имя выходного файла
title: 'Моё приложение', // <title>
minify: { // Минификация в production
collapseWhitespace: true,
removeComments: true,
},
inject: 'body', // Куда вставить <script>
favicon: './src/favicon.ico', // Фавиконка
}),
],
};
<!-- src/index.html — шаблон -->
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title><%= htmlWebpackPlugin.options.title %></title>
</head>
<body>
<div id="app"></div>
<!-- Webpack автоматически вставит <script> сюда -->
</body>
</html>
// Несколько HTML-страниц (multi-page)
plugins: [
new HtmlWebpackPlugin({
template: './src/index.html',
filename: 'index.html',
chunks: ['app'], // Только бандл app
}),
new HtmlWebpackPlugin({
template: './src/admin.html',
filename: 'admin.html',
chunks: ['admin'], // Только бандл admin
}),
],
MiniCssExtractPlugin
Извлекает CSS в отдельные файлы (вместо <style> тегов):
npm install --save-dev mini-css-extract-plugin
const MiniCssExtractPlugin = require('mini-css-extract-plugin');
module.exports = {
module: {
rules: [
{
test: /\.css$/,
use: [
MiniCssExtractPlugin.loader, // Вместо style-loader
'css-loader',
],
},
],
},
plugins: [
new MiniCssExtractPlugin({
filename: '[name].[contenthash].css', // Имя выходного CSS
}),
],
};
// Dev: style-loader (быстро, HMR работает)
// Prod: MiniCssExtractPlugin (отдельный файл, кэшируется)
const isDev = process.env.NODE_ENV === 'development';
{
test: /\.css$/,
use: [
isDev ? 'style-loader' : MiniCssExtractPlugin.loader,
'css-loader',
],
}
CssMinimizerPlugin
Минификация CSS:
npm install --save-dev css-minimizer-webpack-plugin
const CssMinimizerPlugin = require('css-minimizer-webpack-plugin');
module.exports = {
optimization: {
minimizer: [
'...', // Сохранить дефолтный JS-минификатор (Terser)
new CssMinimizerPlugin,
],
},
};
DefinePlugin
Определяет глобальные константы на этапе сборки (встроен в Webpack):
const webpack = require('webpack');
module.exports = {
plugins: [
new webpack.DefinePlugin({
// Значения подставляются КАК ЕСТЬ (как текст)
'process.env.API_URL': JSON.stringify('https://api.example.com'),
'process.env.NODE_ENV': JSON.stringify('production'),
__DEV__: JSON.stringify(false),
VERSION: JSON.stringify('1.0.0'),
}),
],
};
// В коде приложения — константы заменяются при сборке
if (process.env.NODE_ENV === 'production') {
// Этот if в production бандле станет: if ("production" === "production")
// Tree shaking удалит else-ветку
enableAnalytics;
}
console.log(`API: ${process.env.API_URL}`);
// В бандле: console.log(`API: ${"https://api.example.com"}`);
BundleAnalyzerPlugin
Визуализация содержимого бандла — помогает найти «тяжёлые» зависимости:
npm install --save-dev webpack-bundle-analyzer
const BundleAnalyzerPlugin =
require('webpack-bundle-analyzer').BundleAnalyzerPlugin;
module.exports = {
plugins: [
new BundleAnalyzerPlugin({
analyzerMode: 'static', // HTML-отчёт
openAnalyzer: false, // Не открывать автоматически
reportFilename: 'report.html', // Имя файла отчёта
}),
],
};
// Запуск только при анализе
// webpack.config.js
module.exports = (env) => ({
plugins: [
env.analyze && new BundleAnalyzerPlugin,
].filter(Boolean),
});
// npm run build -- --env analyze
CopyWebpackPlugin
Копирует статические файлы в dist:
npm install --save-dev copy-webpack-plugin
const CopyPlugin = require('copy-webpack-plugin');
module.exports = {
plugins: [
new CopyPlugin({
patterns: [
{ from: 'public', to: '.' }, // public/ → dist/
{ from: 'src/assets', to: 'assets' }, // → dist/assets/
],
}),
],
};
ProvidePlugin
Автоматический import модулей (встроен в Webpack):
const webpack = require('webpack');
module.exports = {
plugins: [
new webpack.ProvidePlugin({
$: 'jquery', // $ доступен везде без import
React: 'react', // React доступен в JSX файлах
}),
],
};
EnvironmentPlugin
Упрощённый DefinePlugin для process.env (встроен в Webpack):
const webpack = require('webpack');
module.exports = {
plugins: [
new webpack.EnvironmentPlugin({
NODE_ENV: 'development', // Значение по умолчанию
API_URL: 'http://localhost:3000',
DEBUG: false,
}),
],
};
Комбинация плагинов — полный конфиг
const path = require('path');
const webpack = require('webpack');
const HtmlWebpackPlugin = require('html-webpack-plugin');
const MiniCssExtractPlugin = require('mini-css-extract-plugin');
const CssMinimizerPlugin = require('css-minimizer-webpack-plugin');
const CopyPlugin = require('copy-webpack-plugin');
const isDev = process.env.NODE_ENV === 'development';
module.exports = {
mode: isDev ? 'development' : 'production',
entry: './src/index.js',
output: {
path: path.resolve(__dirname, 'dist'),
filename: isDev ? '[name].js' : '[name].[contenthash].js',
clean: true,
},
plugins: [
new HtmlWebpackPlugin({
template: './src/index.html',
minify: !isDev,
}),
!isDev && new MiniCssExtractPlugin({
filename: '[name].[contenthash].css',
}),
new webpack.DefinePlugin({
'process.env.API_URL': JSON.stringify(
isDev ? 'http://localhost:4000' : 'https://api.prod.com'
),
}),
new CopyPlugin({
patterns: [{ from: 'public', to: '.' }],
}),
].filter(Boolean),
optimization: {
minimizer: [
'...',
!isDev && new CssMinimizerPlugin,
].filter(Boolean),
},
};
Частые ошибки
JSON.stringifyзабывают в DefinePlugin —'production'вставится без кавычек → ошибка- style-loader + MiniCssExtract одновременно — в dev используют style-loader, в prod — MiniCssExtract
- Нет
contenthash— без хеша браузер кэширует старые файлы - CopyPlugin для обрабатываемых файлов — CSS/JS/картинки проходят через loaders, а не копируются
- BundleAnalyzer в production — забывают отключить, сборка замедляется
Практика
- Настроить HtmlWebpackPlugin с шаблоном и мета-тегами
- Подключить MiniCssExtractPlugin для production
- Использовать DefinePlugin для API_URL в разных окружениях
- Проанализировать бандл с BundleAnalyzerPlugin и найти тяжёлую зависимость
- Настроить CopyPlugin для статических файлов (robots.txt, favicon)
Связанные темы
- Webpack — общая настройка
- Webpack loaders — трансформация файлов
- Vite — альтернативный сборщик с встроенными плагинами