Постобработка в Webpack — совокупность этапов, выполняемых после основной трансформации исходного кода. На этой стадии выполняются оптимизация, минификация, очистка артефактов, анализ бандла, генерация карт исходников, копирование ресурсов, компрессия файлов и другие действия, подготавливающие сборку к production-использованию.
Webpack разделяет процесс сборки на несколько фаз:
Именно на поздних стадиях активно работают плагины оптимизации.
Без постобработки итоговый бандл обычно:
Постобработка решает следующие задачи:
| Задача | Результат |
|---|---|
| Минификация | уменьшение размера JS/CSS |
| Tree Shaking | удаление мёртвого кода |
| Code Splitting | разделение бандла |
| Хеширование | эффективное кэширование |
| Сжатие | gzip/brotli |
| Оптимизация CSS | удаление дубликатов |
| Анализ сборки | поиск проблем |
| Очистка output | удаление старых файлов |
Основная часть постобработки настраивается через секцию
optimization.
module.exports = {
optimization: {
minimize: true
}
};
Webpack запускает оптимизаторы после формирования чанков и перед записью файлов на диск.
Параметр optimization.minimize включает или отключает
минимизацию ресурсов.
module.exports = {
optimization: {
minimize: true
}
};
По умолчанию:
truefalseПри отключении:
module.exports = {
optimization: {
minimize: false
}
};
Webpack перестаёт:
Размер сборки существенно увеличивается.
Основной минификатор JavaScript в Webpack 5 —
TerserPlugin.
npm install terser-webpack-plugin --save-dev
const TerserPlugin = require('terser-webpack-plugin');
module.exports = {
optimization: {
minimizer: [
new TerserPlugin()
]
}
};
Terser выполняет:
Опция compress отвечает за логические оптимизации.
new TerserPlugin({
terserOptions: {
compress: true
}
});
new TerserPlugin({
terserOptions: {
compress: {
drop_console: true
}
}
});
Удаляются:
console.logconsole.infoconsole.debugcompress: {
drop_debugger: true
}
mangle сокращает имена переменных и функций.
Исходный код:
function calculateTotalPrice(products) {
return products.reduce((sum, item) => {
return sum + item.price;
}, 0);
}
После минификации:
function n(n){return n.reduce(((n,r)=>n+r.price),0)}
Иногда имена классов и функций нужны для:
new TerserPlugin({
terserOptions: {
keep_classnames: true,
keep_fnames: true
}
});
Управление извлечением комментариев лицензий.
new TerserPlugin({
extractComments: false
});
Без этой настройки Webpack может создавать отдельные
.LICENSE.txt.
Параллельная минификация.
new TerserPlugin({
parallel: true
});
Webpack использует worker threads.
На больших проектах это существенно ускоряет сборку.
Для CSS используется отдельный минимизатор.
npm install css-minimizer-webpack-plugin --save-dev
const CssMinimizerPlugin = require('css-minimizer-webpack-plugin');
module.exports = {
optimization: {
minimizer: [
new CssMinimizerPlugin()
]
}
};
Минификатор CSS:
До:
.button {
margin-top: 10px;
margin-right: 10px;
margin-bottom: 10px;
margin-left: 10px;
}
После:
.button{margin:10px}
Оптимизация изображений уменьшает размер ассетов.
npm install image-minimizer-webpack-plugin imagemin --save-dev
const ImageMinimizerPlugin = require('image-minimizer-webpack-plugin');
module.exports = {
optimization: {
minimizer: [
new ImageMinimizerPlugin({
minimizer: {
implementation:
ImageMinimizerPlugin.imageminGenerate,
options: {
plugins: [
['mozjpeg', { quality: 70 }],
['pngquant', { quality: [0.6, 0.8] }]
]
}
}
})
]
}
};
Создание gzip/brotli-файлов.
npm install compression-webpack-plugin --save-dev
const CompressionPlugin = require(
'compression-webpack-plugin'
);
module.exports = {
plugins: [
new CompressionPlugin()
]
};
Webpack создаёт:
app.js
app.js.gz
Сервер может автоматически отдавать сжатую версию.
Brotli обеспечивает лучшее сжатие, чем gzip.
npm install brotli-webpack-plugin --save-dev
const BrotliPlugin = require(
'brotli-webpack-plugin'
);
module.exports = {
plugins: [
new BrotliPlugin()
]
};
Очистка output-директории перед сборкой.
npm install clean-webpack-plugin --save-dev
const { CleanWebpackPlugin } = require(
'clean-webpack-plugin'
);
module.exports = {
plugins: [
new CleanWebpackPlugin()
]
};
Без очистки:
dist/
app.a1.js
app.b2.js
app.c3.js
После множества сборок директория засоряется.
Копирование статических ресурсов.
npm install copy-webpack-plugin --save-dev
const CopyPlugin = require(
'copy-webpack-plugin'
);
module.exports = {
plugins: [
new CopyPlugin({
patterns: [
{
from: 'public',
to: 'assets'
}
]
})
]
};
Добавление баннера в начало файлов.
const webpack = require('webpack');
module.exports = {
plugins: [
new webpack.BannerPlugin({
banner: 'Copyright 2026'
})
]
};
Карты исходников связывают минифицированный код с оригинальным.
module.exports = {
devtool: 'source-map'
};
Webpack создаёт:
bundle.js
bundle.js.map
devtool: 'hidden-source-map'
Файл карты создаётся, но не подключается автоматически.
Используется для:
devtool: 'nosources-source-map'
Карта содержит стек вызовов без исходного кода.
devtool: 'eval'
Очень быстрый режим для development.
Не подходит для production.
Анализ размеров бандла.
npm install webpack-bundle-analyzer --save-dev
const {
BundleAnalyzerPlugin
} = require('webpack-bundle-analyzer');
module.exports = {
plugins: [
new BundleAnalyzerPlugin()
]
};
Bundle Analyzer отображает:
Часто обнаруживаются:
Tree shaking — удаление неиспользуемого кода.
Webpack использует:
export function a() {}
export function b() {}
export function c() {}
Импорт:
import { a } from './utils';
Webpack удалит b и c.
Поле sideEffects помогает оптимизатору.
{
"sideEffects": false
}
Webpack получает возможность безопасно удалять модули.
Некоторые модули имеют побочные эффекты:
import './styles.css';
Удаление такого импорта ломает приложение.
{
"sideEffects": [
"*.css"
]
}
Разделение кода на чанки.
module.exports = {
optimization: {
splitChunks: {
chunks: 'all'
}
}
};
Преимущества:
Выделение runtime-кода.
optimization: {
runtimeChunk: 'single'
}
Runtime меняется чаще остальных частей.
Отделение улучшает кэширование.
Webpack может генерировать стабильные идентификаторы модулей.
optimization: {
moduleIds: 'deterministic'
}
optimization: {
chunkIds: 'deterministic'
}
Это уменьшает churn хешей между сборками.
output: {
filename: '[name].[contenthash].js'
}
Хеш зависит от содержимого файла.
При изменении содержимого:
app.2ab45.js
становится:
app.77ce1.js
Браузер загружает новую версию.
optimization: {
realContentHash: true
}
Webpack вычисляет хеш после финальной генерации файла.
Это уменьшает ложные изменения хешей.
Scope Hoisting уменьшает накладные расходы модульной системы.
optimization: {
concatenateModules: true
}
(function(module){
module.exports = ...
})
Каждый модуль изолирован.
Webpack объединяет несколько модулей в одну область видимости.
Это:
optimization: {
removeAvailableModules: true
}
Удаляет дублирующиеся зависимости из дочерних чанков.
optimization: {
mergeDuplicateChunks: true
}
Webpack объединяет идентичные чанки.
optimization: {
flagIncludedChunks: true
}
Webpack отмечает дочерние чанки, уже содержащиеся в родительских.
optimization: {
usedExports: true
}
Webpack отмечает используемые exports.
Это фундамент tree shaking.
optimization: {
innerGraph: true
}
Более глубокий анализ зависимостей внутри модулей.
optimization: {
providedExports: true
}
Webpack анализирует, какие exports предоставляет модуль.
optimization: {
emitOnErrors: false
}
При ошибке сборки ассеты не будут записаны.
optimization: {
removeEmptyChunks: true
}
Удаляются пустые чанки.
optimization: {
avoidEntryIife: true
}
Webpack избегает лишнего IIFE вокруг entry.
Для HTML часто используется:
npm install html-minimizer-webpack-plugin --save-dev
const HtmlMinimizerPlugin = require(
'html-minimizer-webpack-plugin'
);
module.exports = {
optimization: {
minimizer: [
new HtmlMinimizerPlugin()
]
}
};
SVG можно:
Популярный инструмент:
npm install svgo --save-dev
Удаление неиспользуемых CSS-классов.
npm install purgecss-webpack-plugin --save-dev
UI-фреймворки часто генерируют огромный CSS:
styles.css → 4 MB
Используется лишь малая часть.
PurgeCSS:
Подмена констант на этапе сборки.
new webpack.DefinePlugin({
__DEV__: JSON.stringify(false)
})
if (__DEV__) {
console.log('debug');
}
После подстановки:
if (false) {
console.log('debug');
}
Terser удаляет блок полностью.
new webpack.EnvironmentPlugin([
'NODE_ENV'
]);
Автоматически подставляет env-переменные.
Типичный pipeline production-сборки:
mode: 'production'
Webpack автоматически включает:
mode: 'development'
Webpack отключает тяжёлые оптимизации ради скорости.
const TerserPlugin = require(
'terser-webpack-plugin'
);
const CssMinimizerPlugin = require(
'css-minimizer-webpack-plugin'
);
module.exports = {
mode: 'production',
devtool: 'source-map',
optimization: {
minimize: true,
minimizer: [
new TerserPlugin({
parallel: true
}),
new CssMinimizerPlugin()
],
splitChunks: {
chunks: 'all'
},
runtimeChunk: 'single',
moduleIds: 'deterministic',
chunkIds: 'deterministic'
},
output: {
filename: '[name].[contenthash].js',
clean: true
}
};
Некоторые библиотеки ломаются после mangle.
Особенно:
{
"sideEffects": false
}
может удалить важные импорты CSS.
Иногда .map больше самого бандла.
Причины:
Возможна ситуация:
lodash@4.17
lodash@4.16
В результате:
На крупных проектах наиболее затратны:
| Этап | Нагрузка |
|---|---|
| Terser | CPU |
| Source Maps | RAM + CPU |
| Image Optimization | CPU |
| Bundle Analyzer | RAM |
| PurgeCSS | CPU |
cache: {
type: 'filesystem'
}
parallel: true
devtool: false
для production-серверов без необходимости debugging.
externals: {
react: 'React'
}
В CI-пайплайнах постобработка обычно включает:
Часто внедряются лимиты:
performance: {
maxEntrypointSize: 300000,
maxAssetSize: 300000
}
Webpack выдаёт предупреждения при превышении.
Webpack может экспортировать статистику сборки.
webpack --json > stats.json
Файл содержит:
На основе stats.json строятся:
Типичная цепочка выглядит так:
TypeScript
↓
Babel
↓
Tree Shaking
↓
Split Chunks
↓
Terser
↓
CSS Minimizer
↓
Image Optimization
↓
Hashing
↓
Gzip/Brotli
↓
CDN Deployment