Webpack Configuration
Webpack Configuration Core Concepts Entry — starting point(s) of the dependency graph Output — where to emit bundled files and how to name them Loaders — transf…
Webpack Configuration
Core Concepts
Entry — starting point(s) of the dependency graph
Output — where to emit bundled files and how to name them
Loaders — transform non-JS files (CSS, images, TypeScript) into modules
Plugins — extend webpack capabilities (HTML generation, bundle analysis, env vars)
Mode — development (fast build, no minification) or production (minified, optimized)
Code splitting — split bundle into chunks loaded on demand (dynamic import, SplitChunksPlugin)
webpack.config.js
const path = require('path');
const HtmlWebpackPlugin = require('html-webpack-plugin');
const MiniCssExtractPlugin = require('mini-css-extract-plugin');
const { BundleAnalyzerPlugin } = require('webpack-bundle-analyzer');
const TerserPlugin = require('terser-webpack-plugin');
const isDev = process.env.NODE_ENV !== 'production';
module.exports = {
mode: isDev ? 'development' : 'production',
entry: { main: './src/index.tsx' },
output: {
path: path.resolve(__dirname, 'dist'),
filename: isDev ? '[name].js' : '[name].[contenthash:8].js',
chunkFilename: isDev ? '[name].chunk.js' : '[name].[contenthash:8].chunk.js',
clean: true, // clean dist before each build
publicPath: '/', // base path for all assets
},
resolve: {
extensions: ['.tsx', '.ts', '.jsx', '.js'],
alias: { '@': path.resolve(__dirname, 'src') },
},
module: {
rules: [
// TypeScript / JavaScript
{
test: /.[jt]sx?$/,
exclude: /node_modules/,
use: {
loader: 'babel-loader',
options: {
presets: [
'@babel/preset-env',
'@babel/preset-react',
'@babel/preset-typescript',
],
},
},
},
// CSS / SCSS
{
test: /.(css|scss)$/,
use: [
isDev ? 'style-loader' : MiniCssExtractPlugin.loader,
{ loader: 'css-loader', options: { modules: true } },
'sass-loader',
],
},
// Images / fonts
{
test: /.(png|jpg|gif|svg|woff2?)$/,
type: 'asset', // webpack 5 Asset Modules
parser: { dataUrlCondition: { maxSize: 8 * 1024 } }, // inline if < 8KB
},
],
},
plugins: [
new HtmlWebpackPlugin({ template: './public/index.html' }),
!isDev && new MiniCssExtractPlugin({ filename: '[name].[contenthash:8].css' }),
process.env.ANALYZE && new BundleAnalyzerPlugin(),
].filter(Boolean),
optimization: {
minimizer: [new TerserPlugin()],
splitChunks: {
chunks: 'all',
cacheGroups: {
vendor: {
test: /[\/]node_modules[\/]/,
name: 'vendors',
chunks: 'all',
},
},
},
runtimeChunk: 'single', // separate runtime chunk for better caching
},
devServer: {
port: 3000,
hot: true,
historyApiFallback: true, // SPA routing
proxy: { '/api': 'http://localhost:4000' },
},
devtool: isDev ? 'eval-source-map' : 'source-map',
};Performance Tips
Cache loaders — babel-loader with cacheDirectory: true, thread-loader for CPU-heavy transforms
DLLPlugin — pre-build vendor libs (React, lodash) separately; rarely re-compile them
Tree shaking — use ES modules (import/export, not require), enable sideEffects: false in package.json
Dynamic imports — const Modal = React.lazy(() => import('./Modal')) — loads chunk only when needed
Bundle analysis — webpack-bundle-analyzer to visualise what is large; look for duplicate deps, large libs