Webpack Optimization
Advanced webpack techniques: code splitting, tree shaking, long-term caching, bundle analysis, and merging dev/prod configs.
Code Splitting & Dynamic Imports
// Dynamic import — webpack creates a separate chunk automatically
const { default: Chart } = await import('./Chart');
// React.lazy
const Dashboard = React.lazy(() => import('./pages/Dashboard'));
// Magic comments — control chunk behavior
import(
/* webpackChunkName: "user-dashboard" */
/* webpackPrefetch: true */ // <link rel="prefetch"> — load after idle
/* webpackPreload: true */ // <link rel="preload"> — load in parallel
'./pages/Dashboard'
);
// SplitChunksPlugin — automatic chunk splitting
optimization: {
splitChunks: {
chunks: 'all', // async + initial chunks
minSize: 20000, // min size to split (bytes)
maxSize: 244000, // try to split larger chunks
minChunks: 1, // min times chunk must be used
maxAsyncRequests: 30,
maxInitialRequests: 30,
cacheGroups: {
// Vendor chunk — node_modules
defaultVendors: {
test: /[\\/]node_modules[\\/]/,
priority: -10,
reuseExistingChunk: true,
name(module) {
const name = module.context.match(/[\\/]node_modules[\\/](.*?)(\/|$)/)[1];
return `vendor.${name.replace('@', '')}`;
},
},
default: {
minChunks: 2,
priority: -20,
reuseExistingChunk: true,
},
},
},
runtimeChunk: 'single', // extract webpack runtime for better caching
}Tree Shaking & Caching
// Tree shaking — works automatically in production mode with ES modules
// Requirements:
// 1. Use ES module syntax (import/export, NOT require/module.exports)
// 2. Mark package as side-effect-free in package.json:
// { "sideEffects": false }
// { "sideEffects": ["*.css", "./src/polyfills.js"] }
// Named imports — webpack can tree-shake unused exports
import { debounce } from 'lodash-es'; // tree-shakeable
// import _ from 'lodash'; // NOT tree-shakeable (CJS)
// Long-term caching with contenthash
output: {
filename: '[name].[contenthash:8].js', // hash changes only when content changes
chunkFilename: '[name].[contenthash:8].chunk.js',
},
// Persist cache between builds (webpack 5)
cache: {
type: 'filesystem', // 'memory' (default) | 'filesystem'
buildDependencies: {
config: [__filename], // invalidate cache when config changes
},
cacheDirectory: path.resolve(__dirname, '.webpack_cache'),
},
// Speed up builds with thread-loader (parallel processing)
{
test: /\.[jt]sx?$/,
use: [
{
loader: 'thread-loader',
options: { workers: require('os').cpus().length - 1 },
},
'babel-loader',
],
}webpack-merge — Dev/Prod Configs
// webpack.common.js — shared config
const path = require('path');
const HtmlWebpackPlugin = require('html-webpack-plugin');
module.exports = {
entry: './src/index.tsx',
resolve: { extensions: ['.tsx', '.ts', '.js'] },
plugins: [new HtmlWebpackPlugin({ template: './public/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',
devServer: { port: 3000, hot: true, historyApiFallback: true },
});
// webpack.prod.js
const { merge } = require('webpack-merge');
const common = require('./webpack.common.js');
const MiniCssExtractPlugin = require('mini-css-extract-plugin');
const TerserPlugin = require('terser-webpack-plugin');
module.exports = merge(common, {
mode: 'production',
devtool: 'source-map',
output: { filename: '[name].[contenthash:8].js', clean: true },
plugins: [new MiniCssExtractPlugin({ filename: '[name].[contenthash:8].css' })],
optimization: {
minimizer: [new TerserPlugin({ parallel: true })],
splitChunks: { chunks: 'all' },
},
});
// package.json scripts
// "dev": "webpack serve --config webpack.dev.js"
// "build": "webpack --config webpack.prod.js"
// "analyze": "ANALYZE=true webpack --config webpack.prod.js"Bundle Analysis & Performance
# Install bundle analyzer
npm install --save-dev webpack-bundle-analyzer
# Generate stats file
webpack --profile --json > stats.json
# Open bundle analyzer UI
npx webpack-bundle-analyzer stats.json dist
# Or use the plugin (set ANALYZE=true env var)
# const { BundleAnalyzerPlugin } = require('webpack-bundle-analyzer');
# new BundleAnalyzerPlugin({ analyzerMode: 'static' })
# Measure build speed
npm install --save-dev speed-measure-webpack-plugin
# Check individual asset sizes
npx bundlesize # define limits in package.json bundlesize field
# Lighthouse CI for performance regression
npx lhci autorunKeep your own version of these notes — editable, searchable, and organised by your stack.
Start free