Webpack 5
Core Concepts
What is Webpack?
Webpack is a static module bundler that builds a dependency graph of your application and combines every module your project needs into one or more bundles. It transforms, bundles, or packages resources and assets like JavaScript, images, fonts, and CSS.
Key Terms
- Entry: The starting point(s) webpack uses to build its dependency graph
- Output: Where webpack places bundled code
- Loaders: Transform files into modules as they're added to dependency graph
- Plugins: Perform wider range of tasks like bundle optimization
- Mode: Development, production, or none - enables built-in optimizations
- Chunks: Units of code splitting
Basic Setup
Theory
The basic setup defines how webpack should transform your application. The entry
point is where webpack starts building its dependency graph, while output
defines where to emit the bundles.
const path = require('path');
module.exports = {
mode: 'development',
entry: './src/index.js',
output: {
path: path.resolve(__dirname, 'dist'),
filename: '[name].[contenthash].js',
clean: true
}
};
Module Federation
Theory
Module Federation allows multiple independent builds to form a single application. It enables loading separate builds at runtime while sharing dependencies.
Key uses:
- Micro-frontends architecture
- Code sharing between applications
- Dynamic remote loading
// Host Application
module.exports = {
plugins: [
new ModuleFederationPlugin({
name: 'host',
remotes: {
app1: 'app1@http://localhost:3001/remoteEntry.js'
},
shared: ['react', 'react-dom']
})
]
};
Loaders
Theory
Loaders transform files into valid modules. They enable webpack to process more than just JavaScript files, converting all types of files into modules that can be included in your application.
Common Use Cases:
- Transform ES6+ to ES5
- Transform TypeScript to JavaScript
- Load CSS/SASS into JavaScript
- Handle images and fonts
module.exports = {
module: {
rules: [
{
test: /\.js$/,
use: 'babel-loader' // Transforms modern JS to browser-compatible JS
},
{
test: /\.css$/,
use: [
'style-loader', // Injects styles into DOM
'css-loader' // Interprets CSS imports
]
}
]
}
};
Plugins
Theory
Plugins are the backbone of webpack, performing actions and custom functionality on compilations or chunks. They can modify how bundles are created.
Common Use Cases:
- Bundle optimization
- Asset management
- Environment variable injection
- HTML file creation
const HtmlWebpackPlugin = require('html-webpack-plugin');
const MiniCssExtractPlugin = require('mini-css-extract-plugin');
module.exports = {
plugins: [
new HtmlWebpackPlugin({
template: './src/index.html' // Generates HTML files with bundle references
}),
new MiniCssExtractPlugin({
filename: '[name].[contenthash].css' // Extracts CSS into separate files
})
]
};
Development Server
Theory
The webpack dev server provides a development server with live reloading functionality. It serves webpack bundles and makes development more efficient.
Key Features:
- Hot Module Replacement (HMR)
- Live reloading
- HTTPS support
- Proxy configuration
- Development-only features
module.exports = {
devServer: {
static: './dist',
hot: true, // Enable HMR
port: 3000,
historyApiFallback: true, // For SPA routing
proxy: {
'/api': 'http://localhost:8080' // API proxy for development
}
}
};
Optimization
Theory
Webpack provides various optimization techniques to reduce bundle size and improve load times.
Key Optimization Types:
- Code Splitting: Divides code into chunks for better caching
- Tree Shaking: Removes unused code
- Minification: Reduces file size
- Caching: Improves build performance
module.exports = {
optimization: {
splitChunks: {
chunks: 'all', // Split code into chunks
cacheGroups: {
vendor: {
test: /[\\/]node_modules[\\/]/,
name: 'vendors'
}
}
},
minimize: true,
minimizer: [
new TerserPlugin(), // Minifies JavaScript
new CssMinimizerPlugin() // Minifies CSS
]
}
};
Asset Modules
Theory
Asset Modules allow using asset files (fonts, icons, etc.) without configuring additional loaders. Webpack 5 introduced this as a replacement for several loaders.
Types of Asset Modules:
- asset/resource: Emits separate file
- asset/inline: Inlines asset as data URI
- asset/source: Imports source code
- asset: Automatically chooses between resource and inline
module.exports = {
module: {
rules: [
{
test: /\.png$/,
type: 'asset/resource' // Emits file to output directory
},
{
test: /\.svg$/,
type: 'asset/inline' // Inlines as data URI
},
{
test: /\.txt$/,
type: 'asset/source' // Imports as string
}
]
}
};
Production vs Development
Theory
Different configurations are needed for development and production environments.
Development Focus:
- Source maps for debugging
- Hot Module Replacement
- Dev server features
- Detailed error messages
Production Focus:
- Minification
- Tree shaking
- Optimized assets
- Performance optimizations
// Production-specific configuration
module.exports = {
mode: 'production',
devtool: 'source-map',
optimization: {
minimize: true,
minimizer: [
new TerserPlugin({
terserOptions: {
compress: {
drop_console: true // Removes console.log in production
}
}
})
]
}
};
Cache Busting
Theory
Cache busting ensures browsers load the latest version of your files instead of cached versions.
Strategies:
- Content hashing
- Version numbers
- Query strings
module.exports = {
output: {
filename: '[name].[contenthash].js', // Content-based hashing
chunkFilename: '[id].[contenthash].js'
}
};
Environment Variables
Theory
Environment variables allow different behavior between development, staging, and production environments.
Use Cases:
- API endpoints
- Feature flags
- Debug settings
- Environment-specific configurations
const webpack = require('webpack');
require('dotenv').config();
module.exports = {
plugins: [
new webpack.DefinePlugin({
'process.env': JSON.stringify(process.env)
})
]
};