# Webpack Core Concepts and Configuration Guide
Deep dive into Webpack bundling principles, core configuration, plugin system and optimization
Webpack is the most popular JavaScript module bundler. This article explores its core concepts and configuration methods.
Core Concepts
Basic Architecture
Webpack Core Concepts:
┌─────────────────────────────────────────────────────┐
│ │
│ Entry │
│ └── Starting point for bundling │
│ │
│ Output │
│ └── Location and naming of bundled files │
│ │
│ Loaders │
│ └── Transform non-JS files (CSS, images, etc.) │
│ │
│ Plugins │
│ └── Extend functionality (compression, etc.) │
│ │
│ Mode │
│ └── development / production / none │
│ │
└─────────────────────────────────────────────────────┘
Basic Configuration
// webpack.config.js
const path = require('path');
module.exports = {
// Mode
mode: 'development',
// Entry
entry: './src/index.js',
// Output
output: {
path: path.resolve(__dirname, 'dist'),
filename: 'bundle.js',
clean: true // Clean dist on each build
},
// Module rules
module: {
rules: []
},
// Plugins
plugins: [],
// Dev server
devServer: {
static: './dist',
port: 3000,
hot: true
}
};
Loaders Configuration
Processing JavaScript
module.exports = {
module: {
rules: [
{
test: /\.js$/,
exclude: /node_modules/,
use: {
loader: 'babel-loader',
options: {
presets: [
['@babel/preset-env', {
targets: '> 0.25%, not dead',
useBuiltIns: 'usage',
corejs: 3
}]
]
}
}
}
]
}
};
Processing TypeScript
module.exports = {
resolve: {
extensions: ['.ts', '.tsx', '.js', '.jsx']
},
module: {
rules: [
{
test: /\.tsx?$/,
use: 'ts-loader',
exclude: /node_modules/
}
]
}
};
Processing CSS
const MiniCssExtractPlugin = require('mini-css-extract-plugin');
module.exports = {
module: {
rules: [
// Development - style-loader injects into DOM
{
test: /\.css$/,
use: ['style-loader', 'css-loader']
},
// Production - extract to separate file
{
test: /\.css$/,
use: [MiniCssExtractPlugin.loader, 'css-loader']
},
// Sass/SCSS
{
test: /\.s[ac]ss$/,
use: [
'style-loader',
'css-loader',
'sass-loader'
]
},
// CSS Modules
{
test: /\.module\.css$/,
use: [
'style-loader',
{
loader: 'css-loader',
options: {
modules: {
localIdentName: '[name]__[local]--[hash:base64:5]'
}
}
}
]
}
]
},
plugins: [
new MiniCssExtractPlugin({
filename: 'styles/[name].[contenthash].css'
})
]
};
Processing Assets
module.exports = {
module: {
rules: [
// Images
{
test: /\.(png|jpg|jpeg|gif|svg)$/i,
type: 'asset',
parser: {
dataUrlCondition: {
maxSize: 8 * 1024 // Under 8KB to base64
}
},
generator: {
filename: 'images/[name].[hash:8][ext]'
}
},
// Fonts
{
test: /\.(woff|woff2|eot|ttf|otf)$/i,
type: 'asset/resource',
generator: {
filename: 'fonts/[name].[hash:8][ext]'
}
}
]
}
};
Common Plugins
HTML Generation
const HtmlWebpackPlugin = require('html-webpack-plugin');
module.exports = {
plugins: [
new HtmlWebpackPlugin({
template: './src/index.html',
filename: 'index.html',
inject: 'body',
minify: {
removeComments: true,
collapseWhitespace: true
}
})
]
};
Environment Variables
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'),
__DEV__: JSON.stringify(false)
})
]
};
Copy Static Assets
const CopyPlugin = require('copy-webpack-plugin');
module.exports = {
plugins: [
new CopyPlugin({
patterns: [
{ from: 'public', to: '' },
{ from: 'src/assets', to: 'assets' }
]
})
]
};
Code Splitting
Entry Splitting
module.exports = {
entry: {
main: './src/index.js',
vendor: './src/vendor.js',
admin: './src/admin/index.js'
},
output: {
filename: '[name].[contenthash].js'
}
};
Dynamic Imports
// Automatic code splitting
button.addEventListener('click', async () => {
const module = await import(
/* webpackChunkName: "heavy-module" */
'./heavy-module.js'
);
module.doSomething();
});
// Prefetch
import(
/* webpackPrefetch: true */
'./analytics.js'
);
// Preload
import(
/* webpackPreload: true */
'./critical-module.js'
);
SplitChunks Optimization
module.exports = {
optimization: {
splitChunks: {
chunks: 'all',
minSize: 20000,
minChunks: 1,
maxAsyncRequests: 30,
maxInitialRequests: 30,
cacheGroups: {
// Third-party libraries
vendors: {
test: /[\\/]node_modules[\\/]/,
name: 'vendors',
chunks: 'all',
priority: 10
},
// React related
react: {
test: /[\\/]node_modules[\\/](react|react-dom)[\\/]/,
name: 'react',
chunks: 'all',
priority: 20
},
// Common code
common: {
minChunks: 2,
name: 'common',
chunks: 'all',
priority: 5,
reuseExistingChunk: true
}
}
},
runtimeChunk: 'single'
}
};
Dev Server
DevServer Configuration
module.exports = {
devServer: {
static: {
directory: path.join(__dirname, 'public')
},
port: 3000,
hot: true,
open: true,
compress: true,
historyApiFallback: true,
// Proxy configuration
proxy: [
{
context: ['/api'],
target: 'http://localhost:8080',
changeOrigin: true,
pathRewrite: { '^/api': '' }
}
],
// Custom middleware
setupMiddlewares: (middlewares, devServer) => {
devServer.app.get('/health', (req, res) => {
res.json({ status: 'ok' });
});
return middlewares;
}
}
};
Source Maps
module.exports = {
// Development - fast rebuild, accurate line numbers
devtool: 'eval-cheap-module-source-map',
// Production - full mapping
// devtool: 'source-map',
// Production - hidden source
// devtool: 'hidden-source-map',
};
Production Optimization
Compression Configuration
const TerserPlugin = require('terser-webpack-plugin');
const CssMinimizerPlugin = require('css-minimizer-webpack-plugin');
module.exports = {
mode: 'production',
optimization: {
minimize: true,
minimizer: [
new TerserPlugin({
terserOptions: {
compress: {
drop_console: true,
drop_debugger: true
},
format: {
comments: false
}
},
extractComments: false
}),
new CssMinimizerPlugin()
]
}
};
Tree Shaking
module.exports = {
mode: 'production',
optimization: {
usedExports: true,
sideEffects: true
}
};
// package.json
{
"sideEffects": [
"*.css",
"*.scss",
"./src/polyfills.js"
]
}
Cache Optimization
module.exports = {
output: {
filename: '[name].[contenthash].js',
chunkFilename: '[name].[contenthash].chunk.js'
},
optimization: {
moduleIds: 'deterministic',
runtimeChunk: 'single',
splitChunks: {
cacheGroups: {
vendor: {
test: /[\\/]node_modules[\\/]/,
name: 'vendors',
chunks: 'all'
}
}
}
}
};
Multi-Environment Config
Configuration Merging
// webpack.common.js
const path = require('path');
const HtmlWebpackPlugin = require('html-webpack-plugin');
module.exports = {
entry: './src/index.js',
output: {
path: path.resolve(__dirname, 'dist'),
clean: true
},
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-cheap-module-source-map',
output: {
filename: '[name].js'
},
devServer: {
port: 3000,
hot: true
}
});
// webpack.prod.js
const { merge } = require('webpack-merge');
const common = require('./webpack.common.js');
module.exports = merge(common, {
mode: 'production',
devtool: 'source-map',
output: {
filename: '[name].[contenthash].js'
}
});
Best Practices Summary
Webpack Optimization Strategies:
┌─────────────────────────────────────────────────────┐
│ │
│ Build Speed │
│ ├── Narrow loader scope │
│ ├── Use persistent caching │
│ ├── Multi-process parallel builds │
│ └── Use alias and extensions wisely │
│ │
│ Output Optimization │
│ ├── Code splitting + lazy loading │
│ ├── Tree shaking removes dead code │
│ ├── Compress JS/CSS/images │
│ └── Use contenthash appropriately │
│ │
│ Developer Experience │
│ ├── Hot Module Replacement (HMR) │
│ ├── Source maps configuration │
│ └── Separate dev/prod environments │
│ │
└─────────────────────────────────────────────────────┘
| Concept | Purpose |
|---|---|
| Entry | Define bundling entry point |
| Output | Define output configuration |
| Loaders | Transform non-JS resources |
| Plugins | Extend build functionality |
| SplitChunks | Code splitting optimization |
Understanding Webpack is mastering the core of modern frontend engineering.