Webpack
Webpack is the most battle-tested JavaScript bundler. Learn its core concepts: entry, output, loaders, plugins, and how to configure it for real projects.
What is Webpack?
Webpack is a static module bundler. It builds a dependency graph from an entry point and packages everything into one or more bundles.
Entry (index.js)
โ App.jsx (depends on)
โ Button.jsx
โ styles.css
โ logo.svg
โ api.js
โ node_modules/axios
Output: dist/main.js + dist/styles.css
Core Concepts
Entry
The starting point of the dependency graph:
// webpack.config.js
module.exports = {
entry: "./src/index.js",
// Multiple entry points
entry: {
main: "./src/index.js",
admin: "./src/admin.js",
},
};
Output
Where to put the bundles:
const path = require("path");
module.exports = {
output: {
path: path.resolve(__dirname, "dist"),
filename: "[name].[contenthash].js", // hash for cache busting
clean: true, // clean dist before each build
},
};
Mode
module.exports = {
mode: "development", // fast builds, readable output, source maps
// mode: "production", // minified, tree-shaken, optimized
// mode: "none", // no defaults
};
Loaders
Loaders transform non-JavaScript files:
module.exports = {
module: {
rules: [
// JavaScript/TypeScript
{
test: /\.(js|jsx|ts|tsx)$/,
use: "babel-loader",
exclude: /node_modules/,
},
// CSS
{
test: /\.css$/,
use: [
"style-loader", // injects CSS into DOM
"css-loader", // resolves CSS imports
],
},
// SCSS
{
test: /\.scss$/,
use: ["style-loader", "css-loader", "sass-loader"],
},
// Images
{
test: /\.(png|jpg|gif|svg)$/,
type: "asset/resource",
generator: {
filename: "images/[hash][ext]",
},
},
// Fonts
{
test: /\.(woff|woff2|eot|ttf|otf)$/,
type: "asset/resource",
},
],
},
};
Plugins
Plugins do everything loaders can't:
const HtmlWebpackPlugin = require("html-webpack-plugin");
const MiniCssExtractPlugin = require("mini-css-extract-plugin");
module.exports = {
plugins: [
// Generate index.html from template
new HtmlWebpackPlugin({
template: "./src/index.html",
title: "My App",
}),
// Extract CSS to separate file (for production)
new MiniCssExtractPlugin({
filename: "[name].[contenthash].css",
}),
],
};
Full Example Config
A typical React project config:
const path = require("path");
const HtmlWebpackPlugin = require("html-webpack-plugin");
const MiniCssExtractPlugin = require("mini-css-extract-plugin");
const isDev = process.env.NODE_ENV !== "production";
module.exports = {
mode: isDev ? "development" : "production",
entry: "./src/index.jsx",
output: {
path: path.resolve(__dirname, "dist"),
filename: isDev ? "[name].js" : "[name].[contenthash].js",
publicPath: "/",
clean: true,
},
resolve: {
extensions: [".js", ".jsx", ".ts", ".tsx"], // try these extensions
alias: {
"@": path.resolve(__dirname, "src"), // @/components โ src/components
},
},
module: {
rules: [
{
test: /\.(js|jsx)$/,
exclude: /node_modules/,
use: {
loader: "babel-loader",
options: {
presets: ["@babel/preset-env", "@babel/preset-react"],
},
},
},
{
test: /\.css$/,
use: [
isDev ? "style-loader" : MiniCssExtractPlugin.loader,
{
loader: "css-loader",
options: { modules: true }, // CSS Modules
},
],
},
],
},
plugins: [
new HtmlWebpackPlugin({ template: "./public/index.html" }),
!isDev && new MiniCssExtractPlugin({
filename: "[name].[contenthash].css",
}),
].filter(Boolean),
devServer: {
port: 3000,
hot: true, // HMR
historyApiFallback: true, // SPA routing
open: true,
},
optimization: {
splitChunks: {
chunks: "all", // separate vendor chunk
},
},
devtool: isDev ? "eval-source-map" : "source-map",
};
Hot Module Replacement (HMR)
HMR updates modules in the browser without a full reload:
// webpack automatically handles HMR for CSS
// For JS modules, you can handle updates manually:
if (module.hot) {
module.hot.accept("./App", () => {
// re-render when App.js changes
const NextApp = require("./App").default;
ReactDOM.render(<NextApp />, document.getElementById("root"));
});
}
React Refresh (used by Create React App, Next.js) handles this automatically.
Webpack Bundle Analyzer
Visualize what's in your bundle:
const BundleAnalyzerPlugin = require("webpack-bundle-analyzer")
.BundleAnalyzerPlugin;
module.exports = {
plugins: [
process.env.ANALYZE && new BundleAnalyzerPlugin(),
].filter(Boolean),
};
Run with ANALYZE=true npm run build to open an interactive treemap.
Common Optimizations
module.exports = {
optimization: {
// Split vendor code (node_modules) into separate chunk
splitChunks: {
chunks: "all",
cacheGroups: {
vendor: {
test: /[\\/]node_modules[\\/]/,
name: "vendors",
chunks: "all",
},
},
},
// Use module IDs based on content hash (stable across builds)
moduleIds: "deterministic",
// Tree shaking
usedExports: true,
// Minify
minimize: true,
},
};
Key Takeaways
- Webpack 5 key concepts: entry, output, loaders, plugins, mode
- Loaders transform files (JS, CSS, images); plugins do everything else
mode: "production"automatically enables tree shaking and minificationsplitChunksseparates vendor code for better caching- HMR (Hot Module Replacement) speeds up development
- Use bundle analyzer to find what's taking up space
Ready to test your knowledge?
Take a quiz on what you just learned.