Webpack Explained: Bundling JavaScript for the Browser

Introduction

Browsers used to load one script tag at a time, and every file was global — a recipe for name collisions and slow pages. Modern JavaScript uses modules (the JavaScript modules concept), but browsers historically couldn't resolve hundreds of module files efficiently, and they certainly couldn't import CSS or images. Webpack solved this by bundling: it starts from an entry point, follows every import, and produces a small number of optimised files a browser can load.

Entry, output, and the dependency graph

Webpack's core idea is the dependency graph: starting from your entry file, it recursively follows every import and require, building a complete map of what your application needs:

// webpack.config.js
module.exports = {
  entry: "./src/index.js",
  output: {
    filename: "bundle.js",
    path: __dirname + "/dist",
  },
};

Everything reachable from the entry ends up in the output; everything unreachable is left out (tree-shaking, in modern terms). That graph is also why Webpack can do code splitting — separating rarely-used code (like an admin panel) into a chunk loaded only when needed, so the first page load stays fast.

Loaders: teaching Webpack new file types

Out of the box, Webpack understands JavaScript. Everything else needs a loader — a small plugin that teaches it to transform a file type:

module: {
  rules: [
    { test: /\.css$/, use: ["style-loader", "css-loader"] },
    { test: /\.(png|jpg)$/, type: "asset/resource" },
  ],
},

With loaders, import "./styles.css" and import logo from "./logo.png" become ordinary code: CSS gets injected or extracted, images get hashed filenames for caching, and TypeScript or Sass gets compiled on the way in. This "everything is a module" philosophy is Webpack's real legacy — it taught the ecosystem to treat assets as part of the dependency graph, not as separate concerns.

The honest trade

Webpack is powerful and famously configuration-heavy: real-world configs run to hundreds of lines, and debugging a broken build can be genuinely hard. That complexity is exactly why Vite (the Vite post) took over new projects — it skips bundling during development entirely. But Webpack still runs a huge share of production sites, and understanding entry, loaders, and the dependency graph explains how nearly every build tool since has worked. Learn the concepts here, and every bundler after it makes sense faster.

Takeaway

Webpack builds a dependency graph from an entry point, loaders teach it every file type, and the output is a small set of optimised files. Configuration-heavy, yes — but the bundling model it established underpins the entire modern frontend.

Comments

Popular posts from this blog

Swift Explained: Apple's Language for iPhone, Mac, and More

Flutter Explained: One Codebase, Every Screen

Go Explained: Simple Code That Runs Fast