Ефективна конфігурація Webpack: від збірки до production-оптимізації

Збірка фронтенду сповільнюється, а бандл зростає з кожним новим компонентом — знайома біль? Ми налаштовуємо Webpack так, щоб компіляція пришвидшувалася, а фінальний код завантажувався швидше. Наша команда реалізує проєкт під ключ: від аудиту поточної конфігурації до впровадження code splitting і tree shaking, забезпечуючи стабільну роботу та подальшу підтримку.

Розробка та обслуговування будь-яких видів сайтів:

Інформаційні сайти або веб-програми
Сайти візитки, landing page, корпоративні сайти, онлайн каталоги, квіз, промо-сайти, блоги, ресурси новин, інформаційні портали, форуми, агрегатори
Сайти або веб-програми електронної комерції
Інтернет-магазини, B2B-портали, маркетплейси, онлайн-обмінники, кешбек-сайти, біржі, дропшиппінг-платформи, парсери товарів
Веб-програми для управління бізнес-процесами
CRM-системи, ERP-системи, корпоративні портали, системи управління виробництвом, парсери інформації
Сайти або веб-програми електронних послуг
Дошки оголошень, онлайн-школи, онлайн-кінотеатри, конструктори сайтів, портали надання електронних послуг, відеохостинги, тематичні портали

Це лише деякі з технічних типів сайтів, з якими ми працюємо, і кожен із них може мати свої специфічні особливості та функціональність, а також бути адаптованим під конкретні потреби та цілі клієнта.

Послуги, які ми пропонуємо
Показано 1 з 1Усі 2062 послуг
Ефективна конфігурація Webpack: від збірки до production-оптимізації
Середній
від 1 дня до 3 днів
Часті запитання

Ви помічали, що збірка фронтенду стає все повільнішою, а бандл зростає з кожним новим компонентом? На одному проекті з 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).

Процес роботи

  1. Аудит поточної збірки: заміряємо час, аналізуємо бандл за допомогою webpack-bundle-analyzer.
  2. Вибір стратегії: визначаємо, які оптимізації потрібні — code splitting, tree shaking, SWC.
  3. Конфігурація: налаштовуємо Webpack, loaders, plugins, dev server.
  4. Тестування: перевіряємо коректність збірки та поведінку в production.
  5. Деплой: впроваджуємо конфігурацію в 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 під ключ — ми оцінимо проект і запропонуємо оптимальне рішення. Отримайте консультацію інженера прямо зараз.

Наші компетенції:

Останні роботи

  • Розробка сайту компанії B2B ADVANCE
    Розробка сайту компанії B2B ADVANCE
    1542
  • Розробка веб-додатків для компанії FEEDME
    Розробка веб-додатків для компанії FEEDME
    1394
  • Розробка веб-сайту для компанії БЕЛФІНГРУП
    Розробка веб-сайту для компанії БЕЛФІНГРУП
    1081
  • Розробка інтернет магазину для компанії FURNORO
    Розробка інтернет магазину для компанії FURNORO
    1369
  • Розробка веб-додатків для компанії Enviok
    Розробка веб-додатків для компанії Enviok
    1142
  • Розробка веб-сайту для компанії ФІКСПЕР
    Розробка веб-сайту для компанії ФІКСПЕР
    1060