Explain the webpack build process
Webpack starts from entry points, builds a dependency graph by resolving every import, transforms non-JS files through loaders, applies plugins across the lifecycle, then bundles modules into optimized output chunks. Key concepts: entry, output, loaders, plugins, mode, code splitting.
Webpack is a module bundler: it takes your scattered source files and dependencies and produces optimized bundles the browser can load.
The process
1. Entry. Webpack starts from one or more entry points (src/index.js). This is the root of the dependency graph.
2. Build the dependency graph. From each entry, webpack resolves every import/require recursively — following the graph of what depends on what. Every file becomes a "module."
3. Loaders transform non-JS. Webpack only understands JS/JSON natively. Loaders transform everything else into modules it can include:
babel-loader— modern JS → compatible JS.css-loader/style-loader— CSS into the graph.ts-loader, asset loaders for images/fonts, etc.
Loaders run per-file, can be chained (right to left).
4. Plugins hook into the lifecycle. Plugins do broader work across the whole build — things loaders can't:
HtmlWebpackPlugin— generates the HTML with script tags injected.MiniCssExtractPlugin— extracts CSS into separate files.DefinePlugin— injects environment variables.- Plugins for minification, bundle analysis, etc.
5. Optimization (driven by mode). mode: "production" enables minification, tree shaking (dead-code elimination), scope hoisting, and more; mode: "development" favors fast rebuilds and good source maps.
6. Code splitting & chunks. Webpack splits output into chunks — via multiple entries, import() dynamic imports, or splitChunks (e.g. a shared vendor chunk). This keeps the initial bundle small.
7. Output. Webpack emits the final bundled files to the output directory — typically with content hashes in filenames for cache busting.
The mental model
entry → resolve imports → dependency graph
→ loaders transform each module
→ plugins act across the build
→ optimize (minify, tree-shake) per mode
→ split into chunks → emit to outputThe honest note
Mention that Vite/esbuild/Rollup are now common alternatives — Vite uses native ESM + esbuild in dev for near-instant startup, Rollup for the prod build. Webpack is still everywhere, but a senior knows the landscape moved.
The framing
"Webpack builds a dependency graph starting from the entry points, resolving every import recursively. Since it only understands JS, loaders transform everything else — CSS, TS, images — into modules; plugins hook into the build lifecycle for broader tasks like HTML generation and minification. mode drives optimization — production turns on minification and tree shaking. It splits the output into chunks via code splitting and dynamic imports, then emits content-hashed bundles. Worth noting Vite and esbuild have largely displaced it for new projects with much faster dev startup."
Follow-up questions
- •What's the difference between a loader and a plugin?
- •How does code splitting work in webpack?
- •What does mode: production turn on?
- •Why have Vite/esbuild become popular alternatives?
Common mistakes
- •Confusing loaders (per-file transforms) with plugins (lifecycle-wide).
- •Not knowing webpack only natively understands JS/JSON.
- •Forgetting code splitting and the role of dynamic imports.
- •Not being aware of the modern alternatives.
Performance considerations
- •Webpack's job is producing optimized output — tree shaking, minification, code splitting, content hashing all shrink and cache the bundle. Dev rebuild speed is its weak point, which is why esbuild-based tools won there.
Edge cases
- •Circular dependencies in the graph.
- •Large vendor bundles without splitChunks.
- •Source map configuration trade-offs (build speed vs accuracy).
- •Loader ordering (they apply right-to-left).
Real-world examples
- •Create React App and older Next.js using webpack under the hood.
- •splitChunks producing a shared vendor bundle cached across page loads.