Вы замечали, что сборка фронтенда всё медленнее, а бандл растёт с каждым новым компонентом? На одном проекте с 200+ компонентами build время достигло 4 минут, а итоговый bundle потянул на 2.5 MB. Без правильной конфигурации Webpack это типичная ситуация. Мы каждый день исправляем такие сборки: анализируем, настраиваем loaders, внедряем code splitting и tree shaking, меняем Babel на SWC. В результате — сборка за 30 секунд и бандл 800 KB. Экономия на хостинге — до 30% за счёт сжатия Brotli. Стоимость настройки обычно составляет от 20 до 40 тысяч рублей в зависимости от сложности стека.
Проблемы, которые решает правильная настройка Webpack
Медленная компиляция и гигантский бандл бьют по всему — от скорости разработки до LCP и TTFB в production. Типичные боли:
- Долгая сборка (3–5+ минут) без SWC или esbuild.
- Раздутый бандл (3–5+ MB) без code splitting: каждый модуль тащит библиотеки целиком.
- N+1 запросы: без splitChunks на каждый роут грузится отдельный vendor.
- Кеширование не работает: нет contenthash, браузер перезапрашивает одни и те же файлы.
- Source maps пропадают в production — отладка становится адом.
Как мы настраиваем Webpack: стек и инструменты
Для новых проектов берём React 18, TypeScript, PostCSS + Tailwind. Компиляцию отдаём SWC — он на Rust и даёт прирост скорости в 20 раз против Babel. Вот сравнительная таблица:
| Параметр | Babel | SWC |
|---|---|---|
| Скорость компиляции | 1x | 20x |
| Поддержка TypeScript | Да | Да (с декораторами) |
| Количество плагинов | Множество | Достаточно для 95% задач |
| Готовность к production | Высокая | Высокая (используется в Vercel, Next.js) |
На одном проекте с 200+ компонентами мы уменьшили бандл с 2.5 MB до 800 KB за счёт code splitting и tree shaking. Время сборки сократилось с 4 минут до 30 секунд после перехода на SWC. Снижение стоимости хостинга составило 30% благодаря сжатию Brotli.
Сравнение до и после оптимизации
| Метрика | До | После |
|---|---|---|
| Время сборки | 4 мин | 30 сек |
| Размер бандла | 2.5 MB | 800 KB |
| Количество запросов | 15 | 6 |
| Экономия хостинга | — | до 30% |
Почему стоит использовать SWC вместо Babel?
SWC компилирует код в 10–20 раз быстрее, при этом поддерживает все необходимые трансформации: TypeScript, React JSX, декораторы. Настройка интеграции с Webpack проста — достаточно заменить babel-loader на swc-loader. Мы рекомендуем SWC для новых проектов и миграции старых. Единственный минус — меньше кастомных плагинов, но для стандартных задач их достаточно. Как говорит официальная документация: SWC is 20x faster than Babel on a single thread.
Как настроить code splitting для максимальной производительности?
Используем optimization.splitChunks с группировкой по вендорам и общим модулям. Например, выделяем React в отдельный vendor-чанк, а остальные библиотеки — в commons при повторном использовании. Динамические импорты с комментарием /* webpackChunkName: "products" */ дробят код по роутам. Включаем runtimeChunk: 'single', чтобы инвалидация кеша не затрагивала все чанки. В результате — параллельная загрузка маленьких фрагментов и высокий hit-rate кеша.
Как уменьшить размер бандла без потери функциональности?
Комбинация приёмов:
- Tree shaking: проверьте, что импорты не side-effect, и настройте
sideEffects: falseв package.json. - Минификация TerserPlugin с опцией
drop_console: true. - CSS минимизация CssMinimizerPlugin.
- Сжатие Brotli через CompressionPlugin (экономия до 30% объёма).
-
webpack-bundle-analyzerдля визуального контроля.
Ниже — базовая конфигурация, которую мы адаптируем под каждый проект.
Установка зависимостей
npm install -D webpack webpack-cli webpack-dev-server
npm install -D html-webpack-plugin mini-css-extract-plugin css-minimizer-webpack-plugin
npm install -D terser-webpack-plugin compression-webpack-plugin
npm install -D swc-loader @swc/core @swc/helpers
Основной конфигурационный файл
import path from 'path'
import webpack from 'webpack'
import HtmlWebpackPlugin from 'html-webpack-plugin'
import MiniCssExtractPlugin from 'mini-css-extract-plugin'
import CssMinimizerPlugin from 'css-minimizer-webpack-plugin'
import TerserPlugin from 'terser-webpack-plugin'
import CompressionPlugin from 'compression-webpack-plugin'
const isDev = process.env.NODE_ENV !== 'production'
const root = path.resolve(__dirname)
const config: webpack.Configuration = {
mode: isDev ? 'development' : 'production',
entry: { main: './src/index.tsx' },
output: {
path: path.resolve(root, 'dist'),
filename: isDev ? '[name].js' : '[name].[contenthash:8].js',
chunkFilename: isDev ? '[name].chunk.js' : '[name].[contenthash:8].chunk.js',
assetModuleFilename: 'assets/[hash][ext][query]',
publicPath: '/',
clean: true,
},
resolve: {
extensions: ['.ts', '.tsx', '.js', '.jsx'],
alias: {
'@': path.resolve(root, 'src'),
'@components': path.resolve(root, 'src/components'),
'@hooks': path.resolve(root, 'src/hooks'),
},
},
module: {
rules: [
{
test: /\.(ts|tsx|js|jsx)$/,
exclude: /node_modules/,
use: {
loader: 'swc-loader',
options: {
jsc: {
parser: { syntax: 'typescript', tsx: true },
transform: {
react: {
runtime: 'automatic',
development: isDev,
refresh: isDev,
},
},
target: 'es2020',
},
},
},
},
{
test: /\.css$/,
use: [
isDev ? 'style-loader' : MiniCssExtractPlugin.loader,
{
loader: 'css-loader',
options: {
modules: {
auto: /\.module\.css$/,
localIdentName: isDev ? '[local]--[hash:base64:5]' : '[hash:base64:8]',
},
importLoaders: 1,
},
},
'postcss-loader',
],
},
{
test: /\.(png|jpg|webp|gif|svg)$/,
type: 'asset',
parser: { dataUrlCondition: { maxSize: 4 * 1024 } },
},
{
test: /\.(woff2?|ttf|eot)$/,
type: 'asset/resource',
},
],
},
plugins: [
new HtmlWebpackPlugin({
template: './public/index.html',
favicon: './public/favicon.ico',
minify: !isDev,
}),
!isDev && new MiniCssExtractPlugin({
filename: 'css/[name].[contenthash:8].css',
chunkFilename: 'css/[name].[contenthash:8].chunk.css',
}),
new webpack.DefinePlugin({
'process.env.NODE_ENV': JSON.stringify(process.env.NODE_ENV),
'process.env.API_URL': JSON.stringify(process.env.API_URL),
}),
!isDev && new CompressionPlugin({
algorithm: 'brotliCompress',
test: /\.(js|css|html|svg)$/,
threshold: 10240,
}),
].filter(Boolean),
optimization: {
minimize: !isDev,
minimizer: [
new TerserPlugin({
terserOptions: {
compress: { drop_console: true },
format: { comments: false },
},
extractComments: false,
}),
new CssMinimizerPlugin(),
],
splitChunks: {
chunks: 'all',
cacheGroups: {
vendor: {
test: /[\\/]node_modules[\\/](react|react-dom|react-router-dom)[\\/]/,
name: 'vendor-react',
chunks: 'all',
priority: 20,
},
commons: {
test: /[\\/]node_modules[\\/]/,
name: 'vendor-commons',
chunks: 'all',
priority: 10,
minChunks: 2,
},
},
},
runtimeChunk: 'single',
moduleIds: isDev ? 'named' : 'deterministic',
chunkIds: isDev ? 'named' : 'deterministic',
},
devServer: {
port: 3000,
hot: true,
historyApiFallback: true,
compress: true,
proxy: [
{
context: ['/api'],
target: 'http://localhost:8000',
changeOrigin: true,
},
],
client: { overlay: { errors: true, warnings: false } },
},
devtool: isDev ? 'eval-cheap-module-source-map' : 'source-map',
performance: {
hints: isDev ? false : 'warning',
maxAssetSize: 250_000,
maxEntrypointSize: 500_000,
},
}
export default config
Также подключаем postcss.config.js с Tailwind, autoprefixer и cssnano, а для TypeScript — настраиваем tsconfig.json с путями (их обязательно дублировать в resolve.alias).
Процесс работы
- Аудит текущей сборки: замеряем время, анализируем бандл с помощью
webpack-bundle-analyzer. - Выбор стратегии: определяем, какие оптимизации нужны — code splitting, tree shaking, SWC.
- Конфигурация: настраиваем Webpack, loaders, plugins, dev server.
- Тестирование: проверяем корректность сборки и поведение в production.
- Деплой: внедряем конфигурацию в CI/CD, настраиваем кеширование.
Сроки: от 1 до 3 дней в зависимости от сложности стека. Стоимость рассчитывается индивидуально.
Что входит в работу (deliverables)
- Аудит существующей конфигурации с отчётом.
- Настройка SWC, code splitting, tree shaking, HMR.
- Оптимизация CSS (PostCSS, минификация).
- Интеграция с CI/CD (GitHub Actions, GitLab CI).
- Документация по конфигурации.
- Обучение команды (1 час).
Типичные ошибки при настройке Webpack
- Неправильная настройка resolve.alias — пути не работают.
- Забывают настроить splitChunks — в каждом чанке дублируются библиотеки.
- Не используют tree shaking — остаётся мёртвый код.
- Отключают source maps в production — сложно отлаживать ошибки.
- Не добавляют contenthash — браузер не кеширует обновления.
Заключение
Правильная конфигурация Webpack — это не разовая акция, а инвестиция в скорость разработки и пользовательский опыт. Мы уже настроили сборки для 50+ проектов, сократив бандлы в среднем на 40% и ускорив компиляцию в 20 раз. Свяжитесь с нами для аудита вашей текущей сборки. Закажите настройку Webpack под ключ — мы оценим проект и предложим оптимальное решение. Получите консультацию инженера прямо сейчас.







