Fossils🌐 Web PlatformWebpack and Bundlers Explained
ðŸĶ–DinosaurWebpackViteBuild ToolsInterview

Webpack and Bundlers Explained

Build tools are the plumbing of frontend engineering. Understanding them separates developers who configure from those who copy-paste configs.

Webpack and Bundlers Explained

Interview Question: "Explain how webpack works and how it compares to Vite."

How Webpack Works

"Webpack is a module bundler that builds a dependency graph starting from one or more entry points, applies transformations through loaders, applies optimizations through plugins, and outputs one or more bundles."

The Dependency Graph

entry: src/index.js
        │
        ├── import './App.jsx'
        │     ├── import './Header.jsx'
        │     ├── import './styles.css'     ← needs css-loader
        │     └── import './logo.svg'       ← needs file-loader
        ├── import 'react'
        └── import 'react-dom'
 
Output: dist/bundle.js (everything resolved and concatenated)

"Webpack starts at the entry point, follows every import/require, and builds a complete graph of every module your application needs. Then it bundles everything into output files, replacing module syntax with its own runtime."

Loaders vs Plugins

module.exports = {
  module: {
    rules: [
      { test: /\.tsx?$/, use: "ts-loader" },
      { test: /\.css$/,  use: ["style-loader", "css-loader"] },
      { test: /\.svg$/,  use: ["@svgr/webpack"] },
    ],
  },
  plugins: [
    new HtmlWebpackPlugin({ template: "./src/index.html" }),
    new MiniCssExtractPlugin(),
    new BundleAnalyzerPlugin(),
  ],
};

"Loaders transform individual files — they're per-module transforms. They run bottom-to-top in the array (css-loader parses CSS, then style-loader injects it). Plugins operate on the entire compilation — they hook into webpack's lifecycle events to do things loaders can't: generate HTML, extract CSS into files, analyze bundle size."

Code Splitting

// Route-based splitting with dynamic imports
const Dashboard = React.lazy(() => import("./pages/Dashboard"));
const Settings = React.lazy(() => import("./pages/Settings"));
 
// Webpack creates separate chunks:
// main.js       — shared code
// dashboard.js  — loaded when user navigates to /dashboard
// settings.js   — loaded when user navigates to /settings

Webpack's splitting strategies:

  • Entry points — multiple entry configs create separate bundles
  • Dynamic imports — import() creates a new chunk automatically
  • SplitChunksPlugin — extracts shared dependencies (e.g., React used by all routes goes into vendors.js)

Tree Shaking

// math.js
export function add(a, b) { return a + b; }
export function multiply(a, b) { return a * b; }
export function complexCalculation() { /* 500 lines */ }
 
// app.js
import { add } from "./math";
console.log(add(1, 2));
// multiply and complexCalculation are eliminated from the bundle

"Tree shaking relies on ES module static analysis — webpack can see at build time which exports are used and eliminate dead code. It doesn't work with CommonJS (require) because those are dynamic. This is why import/export matters."

Hot Module Replacement (HMR)

"HMR patches modules in the running application without a full page reload. Webpack's dev server maintains a WebSocket connection to the browser. When a file changes, it sends a JSON manifest of what changed, the browser requests the updated modules, and they're hot-swapped in memory."

How Vite Works (and Why It's Faster)

Dev Mode: Native ESM

Browser requests: /src/App.tsx
     │
     ▾
Vite dev server:
  1. Transforms App.tsx with esbuild (10-100x faster than Babel)
  2. Serves it as a native ES module
  3. Browser handles the import graph natively
     │
     ▾
Browser sees: import './Header.tsx'
  → Requests /src/Header.tsx from Vite
  → Vite transforms on-demand

"Vite doesn't bundle in development. The browser loads ES modules natively, and Vite transforms files on-demand with esbuild. Startup is near-instant because Vite only processes files the browser actually requests, not the entire dependency graph."

Why Vite Dev Is Faster Than Webpack Dev

WebpackVite
StartupBundles everything upfrontServes files on-demand
TranspilerBabel/ts-loader (JS, slow)esbuild (Go, 10-100x faster)
HMRRebuilds affected chunkInvalidates single module
Cold start 10K modules30-60 seconds1-3 seconds

Production: Rollup Under the Hood

"Vite uses Rollup for production builds — not esbuild — because Rollup has more mature code splitting, tree shaking, and plugin ecosystem. This means dev and prod use different bundlers, which can occasionally cause behavior differences."

When to Choose Which

ScenarioRecommendation
New project, greenfieldVite — faster DX, simpler config
Large legacy codebaseWebpack — more mature, battle-tested migration paths
Library publishingRollup or Vite (library mode)
Need fine-grained control over bundlingWebpack — more configurable
Monorepo with custom requirementsTurborepo + Vite or webpack (depends on needs)
SSR frameworkNext.js (Turbopack/webpack), Nuxt (Vite)

Bundle Optimization Strategies

1. Analyze First

# Webpack
npx webpack-bundle-analyzer dist/stats.json
 
# Vite
npx vite-bundle-visualizer

"Never optimize blind. Bundle analysis reveals the actual bottlenecks — usually it's one massive dependency, not your code."

2. Common Optimizations

// Dynamic import for heavy libraries
const { marked } = await import("marked");
 
// Replace heavy libraries with lighter alternatives
// moment.js (300KB) → date-fns (tree-shakeable) or Temporal API
// lodash (70KB) → lodash-es (tree-shakeable) or native methods
 
// Externalize large dependencies in library builds
// Don't bundle React into your component library

3. Compression

// Vite config for compression
import viteCompression from "vite-plugin-compression";
 
export default defineConfig({
  plugins: [
    viteCompression({ algorithm: "brotliCompress" }),
  ],
});

What Interviewers Look For

  • Conceptual understanding — dependency graph, module resolution, not just config memorization
  • Loaders vs plugins — knowing the difference and when each applies
  • Code splitting strategies — route-based, component-based, vendor extraction
  • Tree shaking prerequisites — ES modules, side effects, "sideEffects": false in package.json
  • Vite's architecture — why native ESM is faster in dev, why Rollup for prod

Common Mistakes

  • Thinking Vite "doesn't bundle" — it doesn't bundle in dev, but uses Rollup for production
  • Confusing loaders and plugins in webpack
  • Not knowing tree shaking requires ES modules
  • Ignoring sideEffects in package.json — webpack can't tree-shake without it
  • Over-splitting — too many tiny chunks cause waterfall requests that are slower than one medium bundle
  • Assuming Vite is always better — webpack has more plugins and handles edge cases Vite can't

Follow-Up Questions

"What is Turbopack and where does it fit?"

"Turbopack is Vercel's Rust-based bundler designed for Next.js. It aims to be webpack-compatible but orders of magnitude faster by using incremental computation (only recomputes what changed). It's the successor to webpack within the Next.js ecosystem, though it's still maturing."

"How does tree shaking actually work?"

"It relies on static analysis of ES module import/export statements. The bundler marks all imports, then walks the dependency graph to find which exports are actually used. Unused exports are removed during dead code elimination. The sideEffects field in package.json tells the bundler whether unused imports can be safely removed entirely — some modules have side effects on import (polyfills, CSS)."

"What's the difference between chunk and bundle?"

"A bundle is the final output file. A chunk is an intermediate grouping of modules. An entry chunk is the initial bundle, async chunks are lazy-loaded bundles from dynamic imports, and vendor chunks are extracted shared dependencies. Multiple chunks may end up in a single bundle depending on configuration."

Red Flags

  • Cannot explain what a dependency graph is
  • Confusing loaders and plugins
  • Saying "Vite is just faster webpack" without understanding the architectural difference
  • Not knowing what tree shaking requires (ESM, sideEffects)
  • Never having used bundle analysis tools