Configuration, loaders, plugins, code splitting, tree shaking, optimization, and module federation.
const path = require('path');
const HtmlWebpackPlugin = require('html-webpack-plugin');
const MiniCssExtractPlugin = require('mini-css-extract-plugin');
const TerserPlugin = require('terser-webpack-plugin');
const CssMinimizerPlugin = require('css-minimizer-webpack-plugin');
module.exports = (env, argv) => {
const isProduction = argv.mode === 'production';
return {
entry: {
main: './src/index.js',
vendor: ['react', 'react-dom'],
},
output: {
path: path.resolve(__dirname, 'dist'),
filename: isProduction ? '[name].[contenthash:8].js' : '[name].js',
chunkFilename: '[name].[contenthash:8].chunk.js',
clean: true,
publicPath: '/',
assetModuleFilename: 'assets/[hash][ext][query]',
},
resolve: {
extensions: ['.js', '.jsx', '.ts', '.tsx'],
alias: {
'@': path.resolve(__dirname, 'src'),
'@components': path.resolve(__dirname, 'src/components'),
},
},
module: {
rules: [
// JavaScript / TypeScript
{
test: /\.jsx?$/,
exclude: /node_modules/,
use: 'babel-loader',
},
// CSS
{
test: /\.css$/,
use: [
isProduction ? MiniCssExtractPlugin.loader : 'style-loader',
'css-loader',
'postcss-loader',
],
},
// SCSS
{
test: /\.scss$/,
use: [
isProduction ? MiniCssExtractPlugin.loader : 'style-loader',
'css-loader',
'postcss-loader',
'sass-loader',
],
},
// Images
{
test: /\.(png|jpg|jpeg|gif|svg|webp)$/i,
type: 'asset',
parser: { dataUrlCondition: { maxSize: 8 * 1024 } },
},
// Fonts
{
test: /\.(woff2?|eot|ttf|otf)$/i,
type: 'asset/resource',
},
],
},
plugins: [
new HtmlWebpackPlugin({
template: './public/index.html',
inject: true,
minify: isProduction ? { collapseWhitespace: true } : false,
}),
...(isProduction ? [
new MiniCssExtractPlugin({
filename: 'css/[name].[contenthash:8].css',
chunkFilename: 'css/[name].[contenthash:8].chunk.css',
}),
] : []),
],
optimization: {
minimize: isProduction,
minimizer: [new TerserPlugin(), new CssMinimizerPlugin()],
splitChunks: {
chunks: 'all',
cacheGroups: {
vendor: {
test: /[\\/]node_modules[\\/]/,
name: 'vendors',
chunks: 'all',
},
common: {
minChunks: 2,
name: 'common',
chunks: 'initial',
reuseExistingChunk: true,
},
},
},
runtimeChunk: 'single',
},
devServer: {
static: { directory: path.join(__dirname, 'public') },
port: 3000,
hot: true,
open: true,
historyApiFallback: true,
compress: true,
},
devtool: isProduction ? 'source-map' : 'eval-cheap-module-source-map',
performance: {
hints: isProduction ? 'warning' : false,
maxAssetSize: 244 * 1024,
maxEntrypointSize: 244 * 1024,
},
};
};| Concept | Description |
|---|---|
| Entry | Starting point for bundling (can be multiple) |
| Output | Where and how bundled files are emitted |
| Loaders | Transform files before adding to bundle |
| Plugins | Extend bundling capabilities |
| Mode | development or production optimization |
| Resolve | Module resolution (extensions, aliases) |
| Loader | Purpose | Install |
|---|---|---|
| babel-loader | Transpile JS/TS/JSX | @babel/core babel-loader |
| css-loader | Resolve CSS imports | css-loader |
| style-loader | Inject CSS into DOM | style-loader |
| sass-loader | Compile SCSS/SASS | sass-loader sass |
| postcss-loader | Process CSS (autoprefixer) | postcss-loader postcss |
| file-loader | Emit files (v4) | file-loader |
| url-loader | Inline files as data URIs | url-loader |
// ── Dynamic Imports (Lazy Loading) ──
// Route-based code splitting
const Home = React.lazy(() => import('./pages/Home'));
const Dashboard = React.lazy(() => import('./pages/Dashboard'));
function App() {
return (
<Suspense fallback={<div>Loading...</div>}>
<Routes>
<Route path="/" element={<Home />} />
<Route path="/dashboard" element={<Dashboard />} />
</Routes>
</Suspense>
);
}
// ── Named chunk for vendor splitting
import(/* webpackChunkName: "lodash" */ 'lodash').then(_) => {
console.log(_.map([1, 2, 3], n => n * 2));
});
// ── Prefetching
const AdminPanel = React.lazy(
() => import(/* webpackPrefetch: true */ './pages/Admin')
);// ── Production Optimization (webpack.config.js) ──
module.exports = {
optimization: {
splitChunks: {
chunks: 'all',
maxSize: 244 * 1024, // Split large chunks
minSize: 20 * 1024,
cacheGroups: {
// React & ReactDOM separate
react: {
test: /[\\/]node_modules[\\/](react|react-dom)[\\/]/,
name: 'react-vendor',
chunks: 'all',
},
// All other vendors
vendor: {
test: /[\\/]node_modules[\\/]/,
name: 'vendor',
chunks: 'all',
priority: -10,
},
// Common code shared between 2+ chunks
common: {
minChunks: 2,
name: 'common',
chunks: 'initial',
reuseExistingChunk: true,
priority: -20,
},
},
},
runtimeChunk: {
name: 'runtime',
},
minimize: true,
minimizer: [
new TerserPlugin({
terserOptions: {
compress: { drop_console: true },
format: { comments: false },
},
extractComments: false,
}),
],
},
performance: {
hints: 'warning',
maxEntrypointSize: 250 * 1024,
maxAssetSize: 250 * 1024,
},
};| Plugin | Purpose |
|---|---|
| HtmlWebpackPlugin | Generate HTML with script tags |
| MiniCssExtractPlugin | Extract CSS to files |
| DefinePlugin | Define environment variables |
| CleanWebpackPlugin | Clean dist before build |
| BundleAnalyzerPlugin | Visualize bundle size |
| CopyWebpackPlugin | Copy static assets |
| ForkTsCheckerWebpackPlugin | TypeScript type checking |
| CompressionPlugin | Gzip/Brotli compression |
| WorkboxWebpackPlugin | Service worker generation |
| Option | Speed | Quality | Use Case |
|---|---|---|---|
| eval | Fastest | Lines only | Development |
| eval-source-map | Fast | Original source | Development |
| source-map | Slowest | Best quality | Production |
| cheap-module-source-map | Moderate | Mapped | Dev (large projects) |
Loaders transform source files before they are added to the bundle (e.g., babel-loader transpiles JS, sass-loader compiles SCSS). They run per-file in the module resolution pipeline.Pluginsperform broader actions on the entire bundle or build process (e.g., HtmlWebpackPlugin generates HTML, MiniCssExtractPlugin extracts CSS). Plugins hook into Webpack's build lifecycle events.
Tree shaking eliminates dead code (unused exports) from the bundle. Webpack detects which exports are used via ES module import/export syntax (not CommonJS require). The TerserPlugin then removes unused code during minification. For tree shaking to work: (1) Use ES modules, (2) set mode: "production", (3) mark side-effect-free packages in package.json with "sideEffects": false.