Skip to content

Webpack Cheat Sheet

Webpack bundles modules by building a dependency graph from entry points, transforming files with loaders and applying plugins for optimization and environment-specific behavior.

How to use this Webpack cheat sheet

Every Webpack build starts with entry and output, then chains loaders (transform) and plugins (side effects). Mode toggles defaults: development favors fast rebuilds and source maps; production enables minification, tree shaking, and long-term caching via content hashes.

Resolve aliases shorten imports; splitChunks extracts vendor code; devServer proxies API calls during local work. Production builds benefit from deterministic module IDs, runtime chunk separation, and analyzing bundle size before shipping.

Quick Webpack example

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

module.exports = {
  entry: './src/index.js',
  output: {
    path: path.resolve(__dirname, 'dist'),
    filename: '[name].[contenthash].js',
    clean: true,
  },
  module: {
    rules: [
      { test: /\.js$/, use: 'babel-loader', exclude: /node_modules/ },
      { test: /\.css$/, use: ['style-loader', 'css-loader'] },
    ],
  },
  plugins: [new HtmlWebpackPlugin({ template: './public/index.html' })],
  devServer: { port: 3000, hot: true, historyApiFallback: true },
  mode: process.env.NODE_ENV === 'production' ? 'production' : 'development',
};

Entry & Output

Option Example Notes
entry entry: "./src/main.ts" Starting point(s) for the dependency graph
output.path path.resolve(__dirname, "dist") Absolute directory for emitted assets
output.filename "[name].[contenthash].js" Hash enables cache busting in production
output.clean clean: true Removes old assets before each build (Webpack 5+)
output.publicPath publicPath: "/assets/" Prefix for on-demand loaded chunks
output.assetModuleFilename "images/[hash][ext]" Pattern for imported files (Webpack 5 asset modules)
Multiple entries entry: { app: "./app.js", admin: "./admin.js" } Separate bundles per entry name
Library output library: { type: "module" } Expose bundle as ES module for federation or CDN

Common Loaders

Rule Example Purpose
Babel { test: /\.jsx?$/, use: "babel-loader" } Transpile modern JS/TS for target browsers
TypeScript use: "ts-loader" or babel-loader + preset Compile .ts/.tsx files
CSS use: ["style-loader", "css-loader"] Inject CSS in dev; extract in prod with MiniCssExtractPlugin
Sass use: ["css-loader", "sass-loader"] Compile SCSS to CSS
Assets { type: "asset/resource" } Emit file and return URL (Webpack 5)
Inline SVG { type: "asset/inline" } Embed small assets as data URLs
JSON { type: "json" } Import JSON as ES module (default in Webpack 5)
Rule order use: [{ loader: "css-loader" }, { loader: "postcss-loader" }] Loaders run right-to-left (bottom-up)

Plugins & Optimization

Plugin / Option Example Purpose
HtmlWebpackPlugin new HtmlWebpackPlugin({ template: "index.html" }) Inject script tags into HTML
DefinePlugin new DefinePlugin({ "process.env.API": JSON.stringify(url) }) Replace env vars at build time
MiniCssExtractPlugin new MiniCssExtractPlugin({ filename: "[name].[contenthash].css" }) Extract CSS to separate files in production
splitChunks optimization: { splitChunks: { chunks: "all" } } Vendor and async code splitting
runtimeChunk optimization: { runtimeChunk: "single" } Isolate webpack runtime for stable vendor hashes
TerserPlugin new TerserPlugin({ parallel: true }) Minify JS (default in production mode)
BundleAnalyzer new BundleAnalyzerPlugin() Visualize bundle composition
mode mode: "production" Enables minification, tree shaking, and built-in optimizations

Resolve & DevServer

Option Example Notes
alias resolve: { alias: { "@": path.resolve("src") } } Shorten import paths
extensions extensions: [".ts", ".tsx", ".js"] Try extensions when import omits suffix
modules modules: [path.resolve("src"), "node_modules"] Resolve modules from src first
devServer.port devServer: { port: 8080 } Local dev server port
devServer.proxy proxy: { "/api": "http://localhost:4000" } Forward API requests during dev
devServer.hot hot: true Hot Module Replacement without full reload
devServer.historyApiFallback historyApiFallback: true SPA fallback to index.html
devServer.static static: { directory: path.join(__dirname, "public") } Serve static files alongside bundled assets

Environment-specific configs

module.exports = (env, argv) => ({
  mode: argv.mode,
  devtool: argv.mode === 'production' ? 'source-map' : 'eval-cheap-module-source-map',
  optimization: {
    minimize: argv.mode === 'production',
    splitChunks: { chunks: 'all', cacheGroups: { vendor: { test: /node_modules/, name: 'vendors' } } },
  },
});

Export a function to branch on CLI mode and env flags.

Dynamic import code splitting

button.addEventListener('click', () => {
  import(/* webpackChunkName: "chart" */ './chart.js')
    .then(({ renderChart }) => renderChart(data));
});

Magic comments name chunks; Webpack emits separate async bundles.

Production cache headers pattern

output: {
  filename: '[name].[contenthash:8].js',
  chunkFilename: '[name].[contenthash:8].js',
},
optimization: {
  moduleIds: 'deterministic',
  runtimeChunk: 'single',
},

Content hashes plus runtime chunk keep vendor bundles cacheable across deploys.

Common mistakes

  • Forgetting to exclude node_modules from babel-loader, slowing builds dramatically.
  • Using style-loader in production instead of MiniCssExtractPlugin, blocking render.
  • Setting publicPath incorrectly so lazy-loaded chunks 404 in production.
  • Disabling splitChunks and shipping one giant bundle with poor cache efficiency.

Key takeaways

  • Entry defines the graph; output.filename with contenthash enables long-term caching.
  • Loaders transform; plugins orchestrate side effects and optimization.
  • splitChunks and runtimeChunk separate vendor code from app code.
  • devServer proxy and HMR keep local development fast without CORS hacks.

Pro Tip

Run webpack-bundle-analyzer before every major release—most bundle bloat comes from a handful of accidental full-library imports.