Ви помічали, що збірка фронтенду стає все повільнішою, а бандл зростає з кожним новим компонентом? На одному проекті з 200+ компонентами build час сягав 4 хвилин, а підсумковий bundle важив 2.5 MB. Без правильної конфігурації Webpack це типова ситуація. Ми щодня виправляємо такі збірки: аналізуємо, налаштовуємо loaders, впроваджуємо code splitting і tree shaking, змінюємо Babel на SWC. У результаті — збірка за 30 секунд і бандл 800 KB. Економія на хостингу — до 30% за рахунок стиснення Brotli.
Проблеми, які вирішує правильне налаштування 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 під ключ — ми оцінимо проект і запропонуємо оптимальне рішення. Отримайте консультацію інженера прямо зараз.







