frontend / build tools / 01_vite_vs_webpack_vs_turbopack.md

Vite vs Webpack vs Turbopack vs Parcel

6 min read source

Vite vs Webpack vs Turbopack vs Parcel

TL;DR

Four bundlers, four philosophies. Webpack is the incumbent — flexible, plugin-rich, complex. Vite (2020) flipped the dev story: serve native ESM in dev with esbuild pre-bundling, only bundle for production with Rollup. Turbopack (Vercel/Next.js) is a Rust-native successor to Webpack with similar architecture but much faster. Parcel is the zero-config zero-effort option. For a new project today: Vite unless you’re committed to Next.js (Turbopack) or have a heavy Webpack-only plugin ecosystem.

Interview Q&A

Q: What did Vite actually change?

A: The dev-time story. Old Webpack model: bundle everything → start dev server → HMR re-bundles on change. As apps grew, cold starts crept past 60 seconds.

Vite’s insight: modern browsers support native ESM. In dev, serve files individually, let the browser request each module. Pre-bundle node_modules with esbuild (one-time, cached); ship source files unbundled. Cold start drops to under a second even on large apps.

For production, Vite uses Rollup — proven tree shaking, smaller output, mature ecosystem.

Webpack dev:  source → bundler → bundle.js → browser
Vite dev:     source → server → individual ESM files → browser
Vite prod:    source → Rollup → optimized bundle

Dev/prod use different tools — initially controversial, now seen as the right separation.

Q: When is Webpack still the right choice?

A:

  • Existing project with a Webpack config that works. Don’t migrate for the sake of it.
  • React Native — Metro is Webpack-derived.
  • Plugin you need only exists for Webpack. Most modern plugins port to Vite, but legacy ones may not.
  • Module Federation — Webpack’s flagship feature for micro-frontends; Vite has plugins but Webpack’s is most mature.

For everything else, the perf and DX gap is too big to ignore.

Q: What is Turbopack and how does it compare?

A: Vercel’s Rust-native successor to Webpack — designed by the original Webpack author. Same architectural model (bundle for dev + prod) but written in Rust with aggressive caching for incremental builds.

Webpack Turbopack Vite (dev)
Language JS Rust JS + esbuild (Go)
Dev cold start seconds → minutes seconds < 1 second
HMR speed slow on big apps fast very fast
Bundles for dev yes yes no — serves ESM
Default in nothing (configure yourself) Next.js 15+ (next dev --turbo) Vite, SvelteKit, Astro, Remix Vite
Maturity very mature stabilizing (production-ready 2024) mature

Turbopack’s bet: bundling-for-dev with enough caching can match unbundled ESM. For Next.js, it’s the default; outside Next.js, Vite is the more popular choice.

Q: What’s Parcel for?

A: Zero-config. Point Parcel at an entry HTML, it figures out the rest:

npx parcel index.html

It auto-detects: TS, JSX, CSS modules, PostCSS, images, fonts. Just works. Great for small projects, demos, prototypes.

Trade-off: less configurability. For complex apps with custom plugin needs, you outgrow Parcel. For “I want to bundle this thing without thinking,” it’s the smallest setup.

Q: How do you choose for a new app?

A: Decision tree:

Are you using Next.js?
  → Turbopack (the default in Next 15+)

Is this React Native?
  → Metro (no choice)

Is this a demo / prototype / tiny app?
  → Parcel

Is this a normal app / SPA / library?
  → Vite

Do you have existing Webpack config + team familiarity + plugin lock-in?
  → Stay on Webpack

For 90% of new web frontend projects in 2026: Vite. It’s the modern default, with the largest ecosystem of plugins and integrations.

Q: What about Rollup directly?

A: Rollup is the bundler under Vite’s production mode. As a standalone tool, it’s the right choice for:

  • Library authoring — clean output (ESM + CJS), tree-shakeable, easy to publish.
  • Server-side bundles — Node-focused outputs.

For app development, you almost always want Vite (which uses Rollup under the hood) rather than Rollup directly.

Q: Vite’s config — minimal example for React + TS.

A:

// vite.config.ts
import { defineConfig } from "vite";
import react from "@vitejs/plugin-react";
import tsconfigPaths from "vite-tsconfig-paths";

export default defineConfig({
  plugins: [react(), tsconfigPaths()],
  build: {
    target: "es2022",
    sourcemap: true,
    rollupOptions: {
      output: {
        manualChunks: {
          react: ["react", "react-dom"],
        },
      },
    },
  },
  server: {
    port: 3000,
    proxy: { "/api": "http://localhost:8000" },
  },
});

Compare to a typical Webpack config (often 200+ lines with babel-loader, css-loader, MiniCssExtractPlugin, etc.) — Vite ships sensible defaults so config stays small.

Q: HMR — what’s different between them?

A:

HMR speed Granularity
Webpack slow on big apps (re-bundle) module-level
Turbopack fast module-level, incremental
Vite very fast module-level, browser-driven (only the changed file re-fetches)

Vite’s HMR is the gold standard — edit a React component, browser fetches just that file, React Fast Refresh swaps the component without losing state. Sub-100ms cycle in most cases.

Q: Production build differences.

A: All four produce bundled output for production. Practical differences:

  • Webpack: most config knobs, mature splitChunks tuning, biggest plugin ecosystem.
  • Vite (Rollup): smaller output by default, cleaner code-split chunks, automatic modulepreload links emitted.
  • Turbopack: aggressive caching across builds, good for incremental CI; comparable output size.
  • Parcel: good defaults, less tunable.

Bundle size differences between tools are usually < 10% for the same app; the bigger lever is your code (deps, splitting strategy).

Gotchas / edge cases

  • Vite dev != Vite prod — dev serves ESM, prod uses Rollup. Bugs that only appear in vite build (like CSS extraction order, dynamic imports with side effects) are real and require testing the prod build.
  • Webpack 5 → Vite migration — most plugins have Vite equivalents; Webpack-specific tools (HardSourcePlugin, etc.) are no longer needed in Vite’s dev model.
  • commonjs() plugin in Vite — needed for CJS-only deps that don’t ship ESM. Most major libs now ship ESM, but the long tail still requires it.
  • Turbopack feature parity — still catching up; some Webpack plugins/loaders don’t have Turbopack equivalents.
  • Vite’s optimizeDeps — controls which deps get pre-bundled by esbuild. Sometimes needs manual tuning for monorepo packages or for deps that break pre-bundling.
  • Parcel’s automatic transforms can surprise — you don’t always know what’s running.

What a senior is expected to say

  • “Vite for new apps — fast dev via native ESM, Rollup for prod. Turbopack if you’re on Next.js. Webpack for existing projects with no pain point, or React Native.”
  • “Vite’s split is real: dev serves ESM (esbuild pre-bundling for node_modules); prod uses Rollup. Test both — bugs hide in prod-only behavior.”
  • “HMR speed is the everyday DX win — Vite’s per-file fetch is what made the whole industry rethink dev servers.”
  • “Bundle size differences between tools are < 10% in practice. The lever that matters is your code — splitting, tree shaking, dep choice.”
  • “Module Federation is Webpack-specific (Vite has a plugin); for micro-frontends with that pattern, Webpack still wins.”

Cross-references

Further reading