Skip to main content
Technology & EngineeringBuild Tools173 lines

Webpack

Webpack 5 setup, optimization, code splitting, and plugin configuration for JavaScript applications

Quick Summary31 lines
You are an expert in Webpack 5 for JavaScript project bundling, optimization, and build pipeline configuration.

## Key Points

- Use `contenthash` in filenames for long-term caching in production builds.
- Enable `filesystem` cache for drastically faster rebuilds during development.
- Set `sideEffects: false` in package.json to enable aggressive tree shaking.
- Use `splitChunks` to extract vendor code into a separate cacheable chunk.
- Prefer Webpack 5 asset modules (`type: 'asset'`) over `file-loader` and `url-loader`.
- Use `resolve.extensions` to avoid writing file extensions in imports.
- **Stale filesystem cache**: When updating loaders or plugins, increment the `cache.version` or clear `.cache/` to avoid stale build artifacts.
- **Over-splitting chunks**: Too many small chunks increase HTTP requests. Use `minSize` and `maxAsyncRequests` in `splitChunks` to control granularity.
- **Missing contenthash in dev**: Using `contenthash` in development mode slows down builds. Only apply it for production.
- **Tree shaking not working**: Ensure you are using ES module syntax (`import`/`export`), not CommonJS. Check `sideEffects` in package.json of dependencies.
- **Large source maps in production**: Use `source-map` for production (separate file) and `eval-cheap-module-source-map` for development (fast rebuild, inlined).

## Quick Example

```bash
npm install --save-dev webpack webpack-cli webpack-dev-server
npm install --save-dev html-webpack-plugin mini-css-extract-plugin css-loader
npm install --save-dev babel-loader @babel/core @babel/preset-env @babel/preset-react
```

```js
const LazyComponent = React.lazy(() =>
  import(/* webpackChunkName: "feature" */ './Feature')
);
```
skilldb get build-tools-skills/WebpackFull skill: 173 lines
Paste into your CLAUDE.md or agent config

Webpack — Build Tools

You are an expert in Webpack 5 for JavaScript project bundling, optimization, and build pipeline configuration.

Core Philosophy

Overview

Webpack is a highly configurable module bundler that processes JavaScript applications by building a dependency graph and emitting optimized bundles. Version 5 introduced Module Federation, persistent caching, improved tree shaking, and asset modules that replace older loaders for common file types.

Setup & Configuration

Installation

npm install --save-dev webpack webpack-cli webpack-dev-server
npm install --save-dev html-webpack-plugin mini-css-extract-plugin css-loader
npm install --save-dev babel-loader @babel/core @babel/preset-env @babel/preset-react

webpack.config.js

const path = require('path');
const HtmlWebpackPlugin = require('html-webpack-plugin');
const MiniCssExtractPlugin = require('mini-css-extract-plugin');

module.exports = (env, argv) => {
  const isProd = argv.mode === 'production';

  return {
    entry: './src/index.js',
    output: {
      path: path.resolve(__dirname, 'dist'),
      filename: isProd ? '[name].[contenthash].js' : '[name].js',
      clean: true,
    },
    devtool: isProd ? 'source-map' : 'eval-cheap-module-source-map',
    devServer: {
      port: 3000,
      hot: true,
      historyApiFallback: true,
      proxy: [{ context: ['/api'], target: 'http://localhost:8080' }],
    },
    module: {
      rules: [
        {
          test: /\.[jt]sx?$/,
          exclude: /node_modules/,
          use: 'babel-loader',
        },
        {
          test: /\.css$/,
          use: [isProd ? MiniCssExtractPlugin.loader : 'style-loader', 'css-loader'],
        },
        {
          test: /\.(png|svg|jpg|gif|woff2?)$/,
          type: 'asset',
          parser: { dataUrlCondition: { maxSize: 8 * 1024 } },
        },
      ],
    },
    plugins: [
      new HtmlWebpackPlugin({ template: './public/index.html' }),
      isProd && new MiniCssExtractPlugin({ filename: '[name].[contenthash].css' }),
    ].filter(Boolean),
    resolve: {
      extensions: ['.ts', '.tsx', '.js', '.jsx'],
      alias: { '@': path.resolve(__dirname, 'src') },
    },
    optimization: {
      splitChunks: {
        chunks: 'all',
        cacheGroups: {
          vendor: {
            test: /[\\/]node_modules[\\/]/,
            name: 'vendors',
            chunks: 'all',
          },
        },
      },
    },
    cache: {
      type: 'filesystem',
    },
  };
};

Core Patterns

Code Splitting with Dynamic Imports

const LazyComponent = React.lazy(() =>
  import(/* webpackChunkName: "feature" */ './Feature')
);

Module Federation

const { ModuleFederationPlugin } = require('webpack').container;

new ModuleFederationPlugin({
  name: 'host',
  remotes: {
    remoteApp: 'remoteApp@http://localhost:3001/remoteEntry.js',
  },
  shared: {
    react: { singleton: true, requiredVersion: '^18.0.0' },
    'react-dom': { singleton: true, requiredVersion: '^18.0.0' },
  },
});

Bundle Analysis

npm install --save-dev webpack-bundle-analyzer
const { BundleAnalyzerPlugin } = require('webpack-bundle-analyzer');
// Add to plugins array:
new BundleAnalyzerPlugin({ analyzerMode: 'static', openAnalyzer: false });

Persistent Caching

cache: {
  type: 'filesystem',
  buildDependencies: {
    config: [__filename],
  },
  version: '1.0',
},

Best Practices

  • Use contenthash in filenames for long-term caching in production builds.
  • Enable filesystem cache for drastically faster rebuilds during development.
  • Set sideEffects: false in package.json to enable aggressive tree shaking.
  • Use splitChunks to extract vendor code into a separate cacheable chunk.
  • Prefer Webpack 5 asset modules (type: 'asset') over file-loader and url-loader.
  • Use resolve.extensions to avoid writing file extensions in imports.

Common Pitfalls

  • Stale filesystem cache: When updating loaders or plugins, increment the cache.version or clear .cache/ to avoid stale build artifacts.
  • Over-splitting chunks: Too many small chunks increase HTTP requests. Use minSize and maxAsyncRequests in splitChunks to control granularity.
  • Missing contenthash in dev: Using contenthash in development mode slows down builds. Only apply it for production.
  • Tree shaking not working: Ensure you are using ES module syntax (import/export), not CommonJS. Check sideEffects in package.json of dependencies.
  • Large source maps in production: Use source-map for production (separate file) and eval-cheap-module-source-map for development (fast rebuild, inlined).

Anti-Patterns

Over-engineering for hypothetical scale. Building for millions of users when you have hundreds adds complexity without value. Solve today's problems first.

Ignoring the existing ecosystem. Reinventing functionality that mature libraries already provide well wastes time and introduces unnecessary risk.

Premature abstraction. Creating elaborate frameworks and utilities before you have enough concrete cases to know what the abstraction should look like produces the wrong abstraction.

Neglecting error handling at boundaries. Internal code can trust its inputs, but system boundaries (user input, APIs, file I/O) require defensive validation.

Skipping documentation for obvious code. What is obvious to you today will not be obvious to your colleague next month or to you next year.

Install this skill directly: skilldb add build-tools-skills

Get CLI access →