Webpack
01 / 03

Webpack Configuration

Webpack Configuration

Core Concepts

  • Entry — starting point(s) of the dependency graph

  • Output — where to emit bundled files and how to name them

  • Loaders — transform non-JS files (CSS, images, TypeScript) into modules

  • Plugins — extend webpack capabilities (HTML generation, bundle analysis, env vars)

  • Mode — development (fast build, no minification) or production (minified, optimized)

  • Code splitting — split bundle into chunks loaded on demand (dynamic import, SplitChunksPlugin)

webpack.config.js

const path = require('path');
const HtmlWebpackPlugin = require('html-webpack-plugin');
const MiniCssExtractPlugin = require('mini-css-extract-plugin');
const { BundleAnalyzerPlugin } = require('webpack-bundle-analyzer');
const TerserPlugin = require('terser-webpack-plugin');

const isDev = process.env.NODE_ENV !== 'production';

module.exports = {
  mode: isDev ? 'development' : 'production',

  entry: { main: './src/index.tsx' },

  output: {
    path: path.resolve(__dirname, 'dist'),
    filename: isDev ? '[name].js' : '[name].[contenthash:8].js',
    chunkFilename: isDev ? '[name].chunk.js' : '[name].[contenthash:8].chunk.js',
    clean: true,              // clean dist before each build
    publicPath: '/',          // base path for all assets
  },

  resolve: {
    extensions: ['.tsx', '.ts', '.jsx', '.js'],
    alias: { '@': path.resolve(__dirname, 'src') },
  },

  module: {
    rules: [
      // TypeScript / JavaScript
      {
        test: /.[jt]sx?$/,
        exclude: /node_modules/,
        use: {
          loader: 'babel-loader',
          options: {
            presets: [
              '@babel/preset-env',
              '@babel/preset-react',
              '@babel/preset-typescript',
            ],
          },
        },
      },
      // CSS / SCSS
      {
        test: /.(css|scss)$/,
        use: [
          isDev ? 'style-loader' : MiniCssExtractPlugin.loader,
          { loader: 'css-loader', options: { modules: true } },
          'sass-loader',
        ],
      },
      // Images / fonts
      {
        test: /.(png|jpg|gif|svg|woff2?)$/,
        type: 'asset',          // webpack 5 Asset Modules
        parser: { dataUrlCondition: { maxSize: 8 * 1024 } },  // inline if < 8KB
      },
    ],
  },

  plugins: [
    new HtmlWebpackPlugin({ template: './public/index.html' }),
    !isDev && new MiniCssExtractPlugin({ filename: '[name].[contenthash:8].css' }),
    process.env.ANALYZE && new BundleAnalyzerPlugin(),
  ].filter(Boolean),

  optimization: {
    minimizer: [new TerserPlugin()],
    splitChunks: {
      chunks: 'all',
      cacheGroups: {
        vendor: {
          test: /[\/]node_modules[\/]/,
          name: 'vendors',
          chunks: 'all',
        },
      },
    },
    runtimeChunk: 'single',   // separate runtime chunk for better caching
  },

  devServer: {
    port: 3000,
    hot: true,
    historyApiFallback: true,  // SPA routing
    proxy: { '/api': 'http://localhost:4000' },
  },

  devtool: isDev ? 'eval-source-map' : 'source-map',
};

Performance Tips

  • Cache loaders — babel-loader with cacheDirectory: true, thread-loader for CPU-heavy transforms

  • DLLPlugin — pre-build vendor libs (React, lodash) separately; rarely re-compile them

  • Tree shaking — use ES modules (import/export, not require), enable sideEffects: false in package.json

  • Dynamic imports — const Modal = React.lazy(() => import('./Modal')) — loads chunk only when needed

  • Bundle analysis — webpack-bundle-analyzer to visualise what is large; look for duplicate deps, large libs

Keep your own version of these notes — editable, searchable, and organised by your stack.

Start free