Skip to content

Webpack Cheatsheet

Webpack - Static Module Bundler

Webpack is a static module bundler for modern JavaScript applications. When webpack processes your application, it internally builds a dependency graph from one or more entry points and then combines every module your project needs into one or more bundles.

Table of Contents

Installation

Global Installation

# Install webpack globally
npm install -g webpack webpack-cli

# Check version
webpack --version
# Initialize npm project
npm init -y

# Install webpack locally
npm install --save-dev webpack webpack-cli

# Install webpack dev server
npm install --save-dev webpack-dev-server

# Install common loaders and plugins
npm install --save-dev html-webpack-plugin css-loader style-loader file-loader url-loader

Package.json Scripts

{
  "scripts": {
    "build": "webpack --mode production",
    "dev": "webpack --mode development",
    "start": "webpack serve --mode development",
    "watch": "webpack --mode development --watch"
  }
}

Basic Configuration

Minimal webpack.config.js

const path = require('path');

module.exports = {
  entry: './src/index.js',
  output: {
    filename: 'bundle.js',
    path: path.resolve(__dirname, 'dist')
  }
};

Complete Basic Configuration

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

module.exports = {
  entry: './src/index.js',
  output: {
    filename: 'bundle.[contenthash].js',
    path: path.resolve(__dirname, 'dist'),
    clean: true
  },
  module: {
    rules: [
      {
        test: /\.css$/i,
        use: ['style-loader', 'css-loader']
      },
      {
        test: /\.(png|svg|jpg|jpeg|gif)$/i,
        type: 'asset/resource'
      }
    ]
  },
  plugins: [
    new HtmlWebpackPlugin({
      template: './src/index.html'
    })
  ]
};

TypeScript Configuration

const path = require('path');

module.exports = {
  entry: './src/index.ts',
  module: {
    rules: [
      {
        test: /\.tsx?$/,
        use: 'ts-loader',
        exclude: /node_modules/
      }
    ]
  },
  resolve: {
    extensions: ['.tsx', '.ts', '.js']
  },
  output: {
    filename: 'bundle.js',
    path: path.resolve(__dirname, 'dist')
  }
};

Entry Points

Single Entry Point

module.exports = {
  entry: './src/index.js'
};

Multiple Entry Points

module.exports = {
  entry: {
    main: './src/index.js',
    vendor: './src/vendor.js'
  }
};

Dynamic Entry Points

module.exports = {
  entry: () => {
    return {
      main: './src/index.js',
      admin: './src/admin.js'
    };
  }
};

Entry with Dependencies

module.exports = {
  entry: {
    main: {
      import: './src/index.js',
      dependOn: 'shared'
    },
    admin: {
      import: './src/admin.js',
      dependOn: 'shared'
    },
    shared: 'lodash'
  }
};

Output

Basic Output Configuration

const path = require('path');

module.exports = {
  output: {
    filename: 'bundle.js',
    path: path.resolve(__dirname, 'dist')
  }
};

Multiple Entry Output

module.exports = {
  entry: {
    main: './src/index.js',
    admin: './src/admin.js'
  },
  output: {
    filename: '[name].bundle.js',
    path: path.resolve(__dirname, 'dist')
  }
};

Output with Hashing

module.exports = {
  output: {
    filename: '[name].[contenthash].js',
    path: path.resolve(__dirname, 'dist'),
    clean: true
  }
};

Public Path Configuration

module.exports = {
  output: {
    filename: 'bundle.js',
    path: path.resolve(__dirname, 'dist'),
    publicPath: '/assets/'
  }
};

Library Output

module.exports = {
  output: {
    filename: 'my-library.js',
    path: path.resolve(__dirname, 'dist'),
    library: {
      name: 'MyLibrary',
      type: 'umd'
    }
  }
};

Loaders

CSS Loaders

module.exports = {
  module: {
    rules: [
      {
        test: /\.css$/i,
        use: ['style-loader', 'css-loader']
      },
      {
        test: /\.s[ac]ss$/i,
        use: ['style-loader', 'css-loader', 'sass-loader']
      },
      {
        test: /\.less$/i,
        use: ['style-loader', 'css-loader', 'less-loader']
      }
    ]
  }
};

JavaScript Loaders

module.exports = {
  module: {
    rules: [
      {
        test: /\.m?js$/,
        exclude: /node_modules/,
        use: {
          loader: 'babel-loader',
          options: {
            presets: ['@babel/preset-env']
          }
        }
      },
      {
        test: /\.tsx?$/,
        use: 'ts-loader',
        exclude: /node_modules/
      }
    ]
  }
};

File Loaders

module.exports = {
  module: {
    rules: [
      {
        test: /\.(png|svg|jpg|jpeg|gif)$/i,
        type: 'asset/resource'
      },
      {
        test: /\.(woff|woff2|eot|ttf|otf)$/i,
        type: 'asset/resource'
      },
      {
        test: /\.(csv|tsv)$/i,
        use: ['csv-loader']
      },
      {
        test: /\.xml$/i,
        use: ['xml-loader']
      }
    ]
  }
};

Asset Modules

module.exports = {
  module: {
    rules: [
      {
        test: /\.png/,
        type: 'asset/resource'
      },
      {
        test: /\.html/,
        type: 'asset/resource'
      },
      {
        test: /\.txt/,
        type: 'asset/source'
      },
      {
        test: /\.jpg/,
        type: 'asset',
        parser: {
          dataUrlCondition: {
            maxSize: 4 * 1024 // 4kb
          }
        }
      }
    ]
  }
};

Loader Options

module.exports = {
  module: {
    rules: [
      {
        test: /\.css$/i,
        use: [
          'style-loader',
          {
            loader: 'css-loader',
            options: {
              modules: true,
              sourceMap: true
            }
          }
        ]
      }
    ]
  }
};

Plugins

HTML Webpack Plugin

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

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

Extract CSS Plugin

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

module.exports = {
  module: {
    rules: [
      {
        test: /\.css$/i,
        use: [MiniCssExtractPlugin.loader, 'css-loader']
      }
    ]
  },
  plugins: [
    new MiniCssExtractPlugin({
      filename: '[name].[contenthash].css'
    })
  ]
};

Define Plugin

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')
    })
  ]
};

Copy Webpack Plugin

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

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

Bundle Analyzer Plugin

const BundleAnalyzerPlugin = require('webpack-bundle-analyzer').BundleAnalyzerPlugin;

module.exports = {
  plugins: [
    new BundleAnalyzerPlugin({
      analyzerMode: 'static',
      openAnalyzer: false
    })
  ]
};

Clean Webpack Plugin

const { CleanWebpackPlugin } = require('clean-webpack-plugin');

module.exports = {
  plugins: [
    new CleanWebpackPlugin()
  ]
};

Mode

Development Mode

module.exports = {
  mode: 'development',
  devtool: 'eval-source-map'
};

Production Mode

module.exports = {
  mode: 'production',
  devtool: 'source-map'
};

Mode-specific Configuration

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

  return {
    mode: argv.mode,
    devtool: isProduction ? 'source-map' : 'eval-source-map',
    optimization: {
      minimize: isProduction
    }
  };
};

Development Server

Basic Dev Server

module.exports = {
  devServer: {
    static: './dist',
    port: 3000,
    open: true
  }
};

Advanced Dev Server Configuration

module.exports = {
  devServer: {
    static: {
      directory: path.join(__dirname, 'dist')
    },
    compress: true,
    port: 3000,
    hot: true,
    open: true,
    historyApiFallback: true,
    proxy: {
      '/api': {
        target: 'http://localhost:8080',
        changeOrigin: true,
        pathRewrite: {
          '^/api': ''
        }
      }
    }
  }
};

HTTPS Dev Server

module.exports = {
  devServer: {
    https: true,
    // or with custom certificates
    https: {
      key: fs.readFileSync('/path/to/server.key'),
      cert: fs.readFileSync('/path/to/server.crt'),
      ca: fs.readFileSync('/path/to/ca.pem')
    }
  }
};

Code Splitting

Entry Point Splitting

module.exports = {
  entry: {
    main: './src/index.js',
    vendor: './src/vendor.js'
  }
};

Dynamic Imports

// In your JavaScript code
import('./math.js').then(math => {
  console.log(math.add(16, 26));
});

// Or with async/await
async function loadMath() {
  const math = await import('./math.js');
  return math.add(16, 26);
}

SplitChunks Plugin

module.exports = {
  optimization: {
    splitChunks: {
      chunks: 'all',
      cacheGroups: {
        vendor: {
          test: /[\\/]node_modules[\\/]/,
          name: 'vendors',
          chunks: 'all'
        },
        common: {
          name: 'common',
          minChunks: 2,
          chunks: 'all',
          enforce: true
        }
      }
    }
  }
};

Advanced Code Splitting

module.exports = {
  optimization: {
    splitChunks: {
      chunks: 'all',
      minSize: 20000,
      maxSize: 244000,
      cacheGroups: {
        default: {
          minChunks: 2,
          priority: -20,
          reuseExistingChunk: true
        },
        vendor: {
          test: /[\\/]node_modules[\\/]/,
          priority: -10,
          reuseExistingChunk: true
        },
        react: {
          test: /[\\/]node_modules[\\/](react|react-dom)[\\/]/,
          name: 'react',
          chunks: 'all'
        }
      }
    }
  }
};

Optimization

Minification

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

module.exports = {
  optimization: {
    minimize: true,
    minimizer: [
      new TerserPlugin({
        terserOptions: {
          compress: {
            drop_console: true
          }
        }
      })
    ]
  }
};

CSS Optimization

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

module.exports = {
  optimization: {
    minimizer: [
      new CssMinimizerPlugin()
    ]
  }
};

Tree Shaking

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

Runtime Chunk

module.exports = {
  optimization: {
    runtimeChunk: 'single'
  }
};

Module Concatenation

module.exports = {
  optimization: {
    concatenateModules: true
  }
};

Module Resolution

Resolve Configuration

const path = require('path');

module.exports = {
  resolve: {
    extensions: ['.js', '.jsx', '.ts', '.tsx', '.json'],
    alias: {
      '@': path.resolve(__dirname, 'src'),
      'components': path.resolve(__dirname, 'src/components'),
      'utils': path.resolve(__dirname, 'src/utils')
    },
    modules: [
      'node_modules',
      path.resolve(__dirname, 'src')
    ]
  }
};

Resolve Fallback

module.exports = {
  resolve: {
    fallback: {
      "fs": false,
      "path": require.resolve("path-browserify"),
      "crypto": require.resolve("crypto-browserify")
    }
  }
};

Hot Module Replacement

Enable HMR

const webpack = require('webpack');

module.exports = {
  devServer: {
    hot: true
  },
  plugins: [
    new webpack.HotModuleReplacementPlugin()
  ]
};

HMR in Code

// In your JavaScript modules
if (module.hot) {
  module.hot.accept('./library.js', function() {
    console.log('Accepting the updated library module!');
    // Re-render or update your app
  });
}

React Hot Reload

const ReactRefreshWebpackPlugin = require('@pmmmwh/react-refresh-webpack-plugin');

module.exports = {
  module: {
    rules: [
      {
        test: /\.[jt]sx?$/,
        exclude: /node_modules/,
        use: [
          {
            loader: 'babel-loader',
            options: {
              plugins: ['react-refresh/babel']
            }
          }
        ]
      }
    ]
  },
  plugins: [
    new ReactRefreshWebpackPlugin()
  ]
};

Environment Variables

DefinePlugin for Environment Variables

const webpack = require('webpack');

module.exports = {
  plugins: [
    new webpack.DefinePlugin({
      'process.env.NODE_ENV': JSON.stringify(process.env.NODE_ENV),
      'process.env.API_URL': JSON.stringify(process.env.API_URL || 'http://localhost:3000')
    })
  ]
};

Environment-specific Configuration

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

  return {
    mode: argv.mode,
    plugins: [
      new webpack.DefinePlugin({
        'process.env.NODE_ENV': JSON.stringify(argv.mode),
        'process.env.API_URL': JSON.stringify(
          isProduction ? 'https://api.production.com' : 'http://localhost:3000'
        )
      })
    ]
  };
};

DotEnv Plugin

const Dotenv = require('dotenv-webpack');

module.exports = {
  plugins: [
    new Dotenv({
      path: './.env',
      safe: true,
      systemvars: true
    })
  ]
};

Production Build

Production Configuration

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

module.exports = {
  mode: 'production',
  entry: './src/index.js',
  output: {
    filename: '[name].[contenthash].js',
    path: path.resolve(__dirname, 'dist'),
    clean: true
  },
  module: {
    rules: [
      {
        test: /\.js$/,
        exclude: /node_modules/,
        use: {
          loader: 'babel-loader',
          options: {
            presets: ['@babel/preset-env']
          }
        }
      },
      {
        test: /\.css$/,
        use: [MiniCssExtractPlugin.loader, 'css-loader']
      }
    ]
  },
  plugins: [
    new HtmlWebpackPlugin({
      template: './src/index.html',
      minify: {
        removeComments: true,
        collapseWhitespace: true,
        removeRedundantAttributes: true,
        useShortDoctype: true,
        removeEmptyAttributes: true,
        removeStyleLinkTypeAttributes: true,
        keepClosingSlash: true,
        minifyJS: true,
        minifyCSS: true,
        minifyURLs: true
      }
    }),
    new MiniCssExtractPlugin({
      filename: '[name].[contenthash].css'
    })
  ],
  optimization: {
    minimize: true,
    minimizer: [
      new TerserPlugin({
        terserOptions: {
          compress: {
            drop_console: true
          }
        }
      }),
      new CssMinimizerPlugin()
    ],
    splitChunks: {
      chunks: 'all',
      cacheGroups: {
        vendor: {
          test: /[\\/]node_modules[\\/]/,
          name: 'vendors',
          chunks: 'all'
        }
      }
    },
    runtimeChunk: 'single'
  }
};

Build Scripts

{
  "scripts": {
    "build": "webpack --mode production",
    "build:analyze": "webpack --mode production --env analyze",
    "build:stats": "webpack --mode production --json > stats.json"
  }
}

Advanced Configuration

Multi-page Application

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

module.exports = {
  entry: {
    home: './src/home.js',
    about: './src/about.js',
    contact: './src/contact.js'
  },
  plugins: [
    new HtmlWebpackPlugin({
      filename: 'home.html',
      template: './src/home.html',
      chunks: ['home']
    }),
    new HtmlWebpackPlugin({
      filename: 'about.html',
      template: './src/about.html',
      chunks: ['about']
    }),
    new HtmlWebpackPlugin({
      filename: 'contact.html',
      template: './src/contact.html',
      chunks: ['contact']
    })
  ]
};

Micro-frontends Configuration

const ModuleFederationPlugin = require('@module-federation/webpack');

module.exports = {
  plugins: [
    new ModuleFederationPlugin({
      name: 'shell',
      remotes: {
        mfe1: 'mfe1@http://localhost:3001/remoteEntry.js',
        mfe2: 'mfe2@http://localhost:3002/remoteEntry.js'
      }
    })
  ]
};

Progressive Web App

const WorkboxPlugin = require('workbox-webpack-plugin');

module.exports = {
  plugins: [
    new WorkboxPlugin.GenerateSW({
      clientsClaim: true,
      skipWaiting: true
    })
  ]
};

Custom Loaders

// custom-loader.js
module.exports = function(source) {
  // Transform the source
  return `export default ${JSON.stringify(source)}`;
};

// webpack.config.js
module.exports = {
  module: {
    rules: [
      {
        test: /\.custom$/,
        use: path.resolve(__dirname, 'custom-loader.js')
      }
    ]
  }
};

Custom Plugins

class MyCustomPlugin {
  apply(compiler) {
    compiler.hooks.emit.tapAsync('MyCustomPlugin', (compilation, callback) => {
      console.log('This is an example plugin!');
      callback();
    });
  }
}

module.exports = {
  plugins: [
    new MyCustomPlugin()
  ]
};

Performance

Performance Budgets

module.exports = {
  performance: {
    maxAssetSize: 250000,
    maxEntrypointSize: 250000,
    hints: 'warning'
  }
};

Lazy Loading

// Dynamic imports for lazy loading
const LazyComponent = React.lazy(() => import('./LazyComponent'));

// Webpack magic comments
import(
  /* webpackChunkName: "my-chunk-name" */
  /* webpackMode: "lazy" */
  './modules/my-module.js'
);

Prefetching and Preloading

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

// Preload
import(
  /* webpackPreload: true */
  './modules/ChartingLibrary.js'
);

Bundle Analysis

# Generate stats file
webpack --profile --json > stats.json

# Analyze with webpack-bundle-analyzer
npx webpack-bundle-analyzer stats.json

# Use webpack-bundle-analyzer plugin
npm install --save-dev webpack-bundle-analyzer

Troubleshooting

Common Issues and Solutions

Module Not Found

// Check resolve configuration
module.exports = {
  resolve: {
    extensions: ['.js', '.jsx', '.ts', '.tsx'],
    alias: {
      '@': path.resolve(__dirname, 'src')
    }
  }
};

Memory Issues

# Increase Node.js memory limit
node --max-old-space-size=4096 node_modules/.bin/webpack

# Or in package.json
{
  "scripts": {
    "build": "node --max-old-space-size=4096 node_modules/.bin/webpack"
  }
}

Slow Build Times

module.exports = {
  // Use cache
  cache: {
    type: 'filesystem'
  },

  // Exclude node_modules from babel-loader
  module: {
    rules: [
      {
        test: /\.js$/,
        exclude: /node_modules/,
        use: 'babel-loader'
      }
    ]
  },

  // Use thread-loader for expensive loaders
  module: {
    rules: [
      {
        test: /\.js$/,
        use: [
          'thread-loader',
          'babel-loader'
        ]
      }
    ]
  }
};

Source Map Issues

module.exports = {
  // Different source map options
  devtool: 'eval-source-map', // Development
  devtool: 'source-map', // Production
  devtool: 'cheap-module-source-map', // Faster builds
  devtool: false // No source maps
};

Debugging Configuration

module.exports = {
  stats: {
    colors: true,
    modules: false,
    children: false,
    chunks: false,
    chunkModules: false
  }
};

Best Practices

Configuration Organization

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

module.exports = {
  entry: './src/index.js',
  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-source-map',
  devServer: {
    static: './dist'
  }
});

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

module.exports = merge(common, {
  mode: 'production',
  devtool: 'source-map'
});

Performance Optimization

  • Use production mode for optimizations
  • Enable tree shaking to remove dead code
  • Split chunks to improve caching
  • Use content hashing for long-term caching
  • Minimize bundle size with proper loaders and plugins

Development Experience

  • Use HMR for faster development
  • Configure source maps for debugging
  • Set up dev server with proxy for API calls
  • Use webpack-bundle-analyzer to understand bundle composition

Code Organization

  • Separate configuration for different environments
  • Use aliases for cleaner imports
  • Organize loaders by file type
  • Group related plugins together

Summary

Webpack is a powerful and flexible module bundler that can handle complex build requirements for modern web applications. Key features include:

  • Module Bundling: Combines modules into optimized bundles
  • Loaders: Transform files during the build process
  • Plugins: Extend webpack functionality
  • Code Splitting: Split code into smaller chunks for better performance
  • Hot Module Replacement: Update modules without full page reload
  • Tree Shaking: Remove unused code from bundles
  • Asset Management: Handle various file types and assets

By mastering webpack configuration and following best practices, you can create efficient build processes that improve both development experience and application performance.