Webpack is the most popular JavaScript module bundler. This article explores its core concepts and configuration methods.

Core Concepts

Basic Architecture

Webpack Core Concepts:
┌─────────────────────────────────────────────────────┐
│                                                     │
│   Entry                                             │
│   └── Starting point for bundling                  │
│                                                     │
│   Output                                            │
│   └── Location and naming of bundled files         │
│                                                     │
│   Loaders                                           │
│   └── Transform non-JS files (CSS, images, etc.)   │
│                                                     │
│   Plugins                                           │
│   └── Extend functionality (compression, etc.)     │
│                                                     │
│   Mode                                              │
│   └── development / production / none              │
│                                                     │
└─────────────────────────────────────────────────────┘

Basic Configuration

// webpack.config.js
const path = require('path');

module.exports = {
  // Mode
  mode: 'development',

  // Entry
  entry: './src/index.js',

  // Output
  output: {
    path: path.resolve(__dirname, 'dist'),
    filename: 'bundle.js',
    clean: true  // Clean dist on each build
  },

  // Module rules
  module: {
    rules: []
  },

  // Plugins
  plugins: [],

  // Dev server
  devServer: {
    static: './dist',
    port: 3000,
    hot: true
  }
};

Loaders Configuration

Processing JavaScript

module.exports = {
  module: {
    rules: [
      {
        test: /\.js$/,
        exclude: /node_modules/,
        use: {
          loader: 'babel-loader',
          options: {
            presets: [
              ['@babel/preset-env', {
                targets: '> 0.25%, not dead',
                useBuiltIns: 'usage',
                corejs: 3
              }]
            ]
          }
        }
      }
    ]
  }
};

Processing TypeScript

module.exports = {
  resolve: {
    extensions: ['.ts', '.tsx', '.js', '.jsx']
  },
  module: {
    rules: [
      {
        test: /\.tsx?$/,
        use: 'ts-loader',
        exclude: /node_modules/
      }
    ]
  }
};

Processing CSS

const MiniCssExtractPlugin = require('mini-css-extract-plugin');

module.exports = {
  module: {
    rules: [
      // Development - style-loader injects into DOM
      {
        test: /\.css$/,
        use: ['style-loader', 'css-loader']
      },
      // Production - extract to separate file
      {
        test: /\.css$/,
        use: [MiniCssExtractPlugin.loader, 'css-loader']
      },
      // Sass/SCSS
      {
        test: /\.s[ac]ss$/,
        use: [
          'style-loader',
          'css-loader',
          'sass-loader'
        ]
      },
      // CSS Modules
      {
        test: /\.module\.css$/,
        use: [
          'style-loader',
          {
            loader: 'css-loader',
            options: {
              modules: {
                localIdentName: '[name]__[local]--[hash:base64:5]'
              }
            }
          }
        ]
      }
    ]
  },
  plugins: [
    new MiniCssExtractPlugin({
      filename: 'styles/[name].[contenthash].css'
    })
  ]
};

Processing Assets

module.exports = {
  module: {
    rules: [
      // Images
      {
        test: /\.(png|jpg|jpeg|gif|svg)$/i,
        type: 'asset',
        parser: {
          dataUrlCondition: {
            maxSize: 8 * 1024  // Under 8KB to base64
          }
        },
        generator: {
          filename: 'images/[name].[hash:8][ext]'
        }
      },
      // Fonts
      {
        test: /\.(woff|woff2|eot|ttf|otf)$/i,
        type: 'asset/resource',
        generator: {
          filename: 'fonts/[name].[hash:8][ext]'
        }
      }
    ]
  }
};

Common Plugins

HTML Generation

const HtmlWebpackPlugin = require('html-webpack-plugin');

module.exports = {
  plugins: [
    new HtmlWebpackPlugin({
      template: './src/index.html',
      filename: 'index.html',
      inject: 'body',
      minify: {
        removeComments: true,
        collapseWhitespace: true
      }
    })
  ]
};

Environment Variables

const webpack = require('webpack');

module.exports = {
  plugins: [
    new webpack.DefinePlugin({
      'process.env.NODE_ENV': JSON.stringify('production'),
      'process.env.API_URL': JSON.stringify('https://api.example.com'),
      __DEV__: JSON.stringify(false)
    })
  ]
};

Copy Static Assets

const CopyPlugin = require('copy-webpack-plugin');

module.exports = {
  plugins: [
    new CopyPlugin({
      patterns: [
        { from: 'public', to: '' },
        { from: 'src/assets', to: 'assets' }
      ]
    })
  ]
};

Code Splitting

Entry Splitting

module.exports = {
  entry: {
    main: './src/index.js',
    vendor: './src/vendor.js',
    admin: './src/admin/index.js'
  },
  output: {
    filename: '[name].[contenthash].js'
  }
};

Dynamic Imports

// Automatic code splitting
button.addEventListener('click', async () => {
  const module = await import(
    /* webpackChunkName: "heavy-module" */
    './heavy-module.js'
  );
  module.doSomething();
});

// Prefetch
import(
  /* webpackPrefetch: true */
  './analytics.js'
);

// Preload
import(
  /* webpackPreload: true */
  './critical-module.js'
);

SplitChunks Optimization

module.exports = {
  optimization: {
    splitChunks: {
      chunks: 'all',
      minSize: 20000,
      minChunks: 1,
      maxAsyncRequests: 30,
      maxInitialRequests: 30,
      cacheGroups: {
        // Third-party libraries
        vendors: {
          test: /[\\/]node_modules[\\/]/,
          name: 'vendors',
          chunks: 'all',
          priority: 10
        },
        // React related
        react: {
          test: /[\\/]node_modules[\\/](react|react-dom)[\\/]/,
          name: 'react',
          chunks: 'all',
          priority: 20
        },
        // Common code
        common: {
          minChunks: 2,
          name: 'common',
          chunks: 'all',
          priority: 5,
          reuseExistingChunk: true
        }
      }
    },
    runtimeChunk: 'single'
  }
};

Dev Server

DevServer Configuration

module.exports = {
  devServer: {
    static: {
      directory: path.join(__dirname, 'public')
    },
    port: 3000,
    hot: true,
    open: true,
    compress: true,
    historyApiFallback: true,

    // Proxy configuration
    proxy: [
      {
        context: ['/api'],
        target: 'http://localhost:8080',
        changeOrigin: true,
        pathRewrite: { '^/api': '' }
      }
    ],

    // Custom middleware
    setupMiddlewares: (middlewares, devServer) => {
      devServer.app.get('/health', (req, res) => {
        res.json({ status: 'ok' });
      });
      return middlewares;
    }
  }
};

Source Maps

module.exports = {
  // Development - fast rebuild, accurate line numbers
  devtool: 'eval-cheap-module-source-map',

  // Production - full mapping
  // devtool: 'source-map',

  // Production - hidden source
  // devtool: 'hidden-source-map',
};

Production Optimization

Compression Configuration

const TerserPlugin = require('terser-webpack-plugin');
const CssMinimizerPlugin = require('css-minimizer-webpack-plugin');

module.exports = {
  mode: 'production',
  optimization: {
    minimize: true,
    minimizer: [
      new TerserPlugin({
        terserOptions: {
          compress: {
            drop_console: true,
            drop_debugger: true
          },
          format: {
            comments: false
          }
        },
        extractComments: false
      }),
      new CssMinimizerPlugin()
    ]
  }
};

Tree Shaking

module.exports = {
  mode: 'production',
  optimization: {
    usedExports: true,
    sideEffects: true
  }
};

// package.json
{
  "sideEffects": [
    "*.css",
    "*.scss",
    "./src/polyfills.js"
  ]
}

Cache Optimization

module.exports = {
  output: {
    filename: '[name].[contenthash].js',
    chunkFilename: '[name].[contenthash].chunk.js'
  },
  optimization: {
    moduleIds: 'deterministic',
    runtimeChunk: 'single',
    splitChunks: {
      cacheGroups: {
        vendor: {
          test: /[\\/]node_modules[\\/]/,
          name: 'vendors',
          chunks: 'all'
        }
      }
    }
  }
};

Multi-Environment Config

Configuration Merging

// webpack.common.js
const path = require('path');
const HtmlWebpackPlugin = require('html-webpack-plugin');

module.exports = {
  entry: './src/index.js',
  output: {
    path: path.resolve(__dirname, 'dist'),
    clean: true
  },
  plugins: [
    new HtmlWebpackPlugin({
      template: './src/index.html'
    })
  ]
};

// webpack.dev.js
const { merge } = require('webpack-merge');
const common = require('./webpack.common.js');

module.exports = merge(common, {
  mode: 'development',
  devtool: 'eval-cheap-module-source-map',
  output: {
    filename: '[name].js'
  },
  devServer: {
    port: 3000,
    hot: true
  }
});

// webpack.prod.js
const { merge } = require('webpack-merge');
const common = require('./webpack.common.js');

module.exports = merge(common, {
  mode: 'production',
  devtool: 'source-map',
  output: {
    filename: '[name].[contenthash].js'
  }
});

Best Practices Summary

Webpack Optimization Strategies:
┌─────────────────────────────────────────────────────┐
│                                                     │
│   Build Speed                                       │
│   ├── Narrow loader scope                          │
│   ├── Use persistent caching                       │
│   ├── Multi-process parallel builds                │
│   └── Use alias and extensions wisely              │
│                                                     │
│   Output Optimization                               │
│   ├── Code splitting + lazy loading                │
│   ├── Tree shaking removes dead code               │
│   ├── Compress JS/CSS/images                       │
│   └── Use contenthash appropriately                │
│                                                     │
│   Developer Experience                              │
│   ├── Hot Module Replacement (HMR)                 │
│   ├── Source maps configuration                    │
│   └── Separate dev/prod environments              │
│                                                     │
└─────────────────────────────────────────────────────┘
ConceptPurpose
EntryDefine bundling entry point
OutputDefine output configuration
LoadersTransform non-JS resources
PluginsExtend build functionality
SplitChunksCode splitting optimization

Understanding Webpack is mastering the core of modern frontend engineering.