⚡ 为什么 Vite 能取代 Webpack

核心结论(TL;DR)

Vite 撬动 Webpack 的支点,是一次教科书级的第一性原理操作:它没有去”把打包做得更快”,而是重新质疑了一个被默认了十年的前提——“开发时为什么要打包?” 当浏览器原生支持了 ES-Modules,这个前提就不再成立。Vite 用 no-bundle dev(原生 ESM 按需编译)+ esbuild 预构建 + Rollup 生产打包 的组合,把开发服务器冷启动从”O(n) 几十秒”降到”O(1) 几百毫秒”。它取胜的核心不是功能,而是开发体验(DX)本身已成为第一竞争力。但要承认:它早期存在 dev/prod 双引擎不一致 的隐忧,且超大型/深度定制场景 Webpack 仍有优势——而 Rolldown(Rust 统一引擎)正是来收口这个问题的。


一、问题背景:争议是什么

Webpack 统治了整整十年,它的生态护城河深不见底:所有脚手架、教程、插件都基于它。按常理,这种被网络效应锁定的霸主不可能被快速取代

但 2020 年 Vite(尤雨溪)发布后,只用了两三年,就成了新项目的默认选择:Vue 全面转向、SvelteKit/Astro/Nuxt/Solid 采用、Vitest 兴起、连 React 生态也大量迁移。

争议在于:一个生态锁定如此之深的霸主,凭什么被这么快撬动? 上一篇我们论证过”打破生态锁定不能靠渐进改良,只能靠范式革命”。Vite 正是那场范式革命——而它的武器,是一个简单到近乎”作弊”的发问。


二、关键原因拆解

原因 1:第一性原理 —— “开发时为什么要打包?”

这是整个故事的灵魂。Webpack 慢的根本原因不是实现,而是范式:

Webpack 的范式枷锁(bundle-based dev)

Webpack 即使在开发模式下,也必须先把整个应用的依赖图打包成 bundle,服务器才能启动。这意味着:

  • 冷启动时间 ∝ 项目模块总数 = O(n)
  • 项目越大,启动越慢(大项目几十秒到几分钟)
  • 你改一行代码想看效果,却要等一个”全量构建”的副产物

人们诟病了十年,但默认了”开发时必须打包”这个前提,只在前提之内优化(缓存、多进程、DLL……)。

Vite 做的事是:跳出前提,直接问”这个前提还成立吗?”

答案是:不成立了。 因为现代浏览器原生支持了 ES-Modules(<script type="module">)。既然浏览器自己就能处理 import,开发时根本不需要把模块打包在一起——可以让浏览器直接请求模块,服务器按需编译被请求的那个模块

Webpack(bundle-based dev):
  启动 = 打包全部 n 个模块 → 才能服务  ……… O(n),随项目增大而恶化

Vite(no-bundle dev):
  启动 = 起一个 ESM dev server(几乎瞬间) ……… O(1)
  浏览器请求 main.js → import './App' → Vite 实时编译这一个文件返回
  (只编译"屏幕上真正用到的"模块,而非全部)

这是从 O(n) 到 O(1) 的复杂度跃迁,不是常数级优化。质变来自重新提问,而非更努力地回答旧问题。

原因 2:esbuild 预构建 —— 用 Go 解决 ESM 的两个工程问题

纯 no-bundle 有两个现实障碍,Vite 用 esbuild(Go 编写) 巧妙化解:

  1. 第三方依赖的模块数量爆炸:像 lodash-es 这种包有几百个内部模块,如果都用原生 ESM 按需请求,浏览器会发起几百个 HTTP 请求,反而变慢。Vite 用 esbuild 把这类依赖预打包成单个 ESM 模块(依赖预构建,pre-bundling),只此一次。
  2. CommonJS / UMD 包不是 ESM:很多老包不是 ESM,浏览器不认。esbuild 在预构建时把它们转成 ESM

esbuild 用 Go 写,比 Babel(JS 写)快 10–100 倍,所以这步”预构建”几乎无感。

关键设计:区分"业务代码"和"依赖"

Vite 的洞察是:业务代码经常变(需要按需即时编译),而依赖几乎不变(适合一次性预打包并强缓存)。它用两种策略分治:

  • 依赖 → esbuild 预构建 + HTTP 强缓存(max-age 长缓存)
  • 业务代码 → 原生 ESM 按需编译(改哪个编译哪个) 这个”按变化频率分治”的设计,是它又快又稳的关键。

原因 3:HMR 的速度也是 O(1)

Webpack 的 HMR 在大项目里会变慢,因为它要在依赖图里计算受影响的模块边界。Vite 的 HMR 基于原生 ESM:改一个文件,只让浏览器重新请求那一个模块(及其 HMR 边界),与项目规模基本无关——改完即见,几乎无延迟

维度WebpackVite
冷启动复杂度O(n)(打包全量)O(1)(起 ESM server)
启动时间(大项目)几十秒~几分钟几百毫秒~几秒
HMR 速度随规模变慢基本恒定,即时
依赖处理打包进 bundleesbuild 预构建 + 缓存
编译范围全量按需(只编译用到的)

原因 4:DX 已成为第一竞争力 —— “秒级反馈”是不可逆的体验升级

这是 Vite 能快速扩散的社会学原因。在 工程化时代,框架的胜负已分,开发体验(DX)成了新战场

“等构建”是对心流(flow)的持续打断。一旦开发者体验过 Vite 的”保存即见效”,再回到 Webpack 的”等几十秒”会生理性难受。这种体验落差口口相传,扩散速度极快——DX 的改善是单向阀,体验过更好的就回不去了。

二阶效应:DX 决定了工具的传播速度

性能数据是抽象的,但”等待的痛苦”是切身的。Vite 把一个抽象的工程指标(冷启动时间)转化成了每个开发者每天切身感受几十次的体验差。这让它的传播不靠论文、不靠论证,而靠身体记忆——这是最强的病毒式扩散动力。

原因 5:生态策略 —— 从 Vue 背书到框架无关

Vite 没有重蹈”绑死一个框架”的覆辙,而是走了一条聪明的扩张路径:

尤雨溪 + Vue 背书(可信的起点)
   → 设计成框架无关(plugin 体系,React/Svelte/Solid 都能用)
   → 各大元框架采用:SvelteKit / Astro / Nuxt3 / Qwik / Remix(后期)
   → Vitest(测试)复用 Vite 管线,扩展到测试领域
   → 成为"新一代前端基础设施"的默认底座

它复用了 Rollup 作为生产构建器(成熟、ESM 优先、tree-shaking 优秀),复用 esbuild 做转译,站在巨人的肩膀上而非重造轮子。这让它既快又稳,生态接入成本低。


三、反方 / 常见误解

Vite 不是没有代价的银弹

误解 1:“Vite 全面比 Webpack 快/好。” 不准确。Vite 快的是开发模式。生产构建走 Rollup,对超大型项目不一定比优化过的 Webpack 快。而 Webpack 的 Module Federation(微前端)、对非标准/复杂资源管线的处理、海量成熟 plugin,在深度定制场景仍有优势。

误解 2:“no-bundle 没有缺点。” 早期有真实痛点:dev 与 prod 的不一致。Vite 开发用原生 ESM + esbuild,生产用 Rollup——两套引擎,行为可能有微妙差异(“dev 正常 prod 出错”);首次加载未预构建的大量小模块时,瀑布式请求也可能慢。这是它的”双引擎不一致”原罪。

误解 3:“esbuild 那么快,为什么生产不用 esbuild?” 因为 esbuild 的代码分割和 tree-shaking 成熟度当时不如 Rollup,生产构建对产物质量要求更高,所以 Vite 选择”dev 用 esbuild 求快,prod 用 Rollup 求稳”。这恰恰是上面”双引擎”问题的根源。

误解 4:“Vite 已经终局了。” 没有。dev/prod 双引擎的不一致是悬而未决的架构问题。Rolldown(用 Rust 重写、兼容 Rollup API 的统一打包器)正是 Vite 团队为了用同一个引擎统一 dev 和 prod而做的下一步——这说明 Vite 自己也认为当前架构是过渡态。范式革命仍在继续。


四、本质洞察 / 元规律

撬动霸主的支点,不是"更努力地优化",而是"重新质疑被默认的前提"

规律 1:范式革命来自第一性原理,而非渐进优化。 所有人都在”如何让打包更快”的框架内努力(缓存、并行、增量),Vite 跳出来问”为什么要打包”。当一个底层条件变了(浏览器原生支持 ESM),旧前提的失效就打开了 O(n)→O(1) 的质变空间。最强的优化,是发现某个步骤根本不必存在。 这与 pnpm 重新质疑”为什么要复制 node_modules” 是同一种思维。

规律 2:外部条件的变化,是范式革命的真正触发器。 Vite 不是凭空天才,它是踩在了”浏览器普及原生 ESM”这个外部条件成熟的拐点上。同样的想法在 2015 年(浏览器不支持 ESM)无法实现。好点子需要等待使能条件(enabling condition)成熟——时机和洞察同等重要。这呼应了 React 踩中范式拐点 的规律。

规律 3:体验是单向阀,DX 改善具有不可逆的扩散力。 当一项改进直接作用于”每天感受几十次的切身体验”(而非抽象指标),它的传播就不靠论证,靠身体记忆。把工程指标翻译成体感差异,是打破生态锁定的最快路径——这是 Vite 能在三年内撬动十年霸主的社会学密码。

Webpack 的隐含前提:"开发时必须打包"  ← 被默认了十年
                    │
        浏览器原生支持 ESM(外部条件成熟)
                    │
   Vite 第一性原理发问:"这个前提还成立吗?" → 不成立
                    │
        no-bundle dev:O(n) ──► O(1) 的范式跃迁
                    │
   DX 体感差(单向阀)→ 病毒式扩散 → 三年撬动十年霸主

五、结论

Vite 取代 Webpack(在新项目的默认地位上),核心是一次第一性原理驱动的范式革命:它不去优化打包,而是借助”浏览器原生 ESM”这个外部条件的成熟,取消了”开发时打包”这个步骤本身,实现了 O(n)→O(1) 的冷启动跃迁;再用 esbuild 预构建和 Rollup 生产构建补齐工程缺口;最终靠 DX 的不可逆体感差完成病毒式扩散。

但它远未终局:dev/prod 双引擎不一致是其架构原罪,Webpack 在超大型/深度定制场景仍有不可替代性,Rolldown(Rust 统一引擎)正在收口。最普适的洞察是:打败一个被生态锁定的霸主,武器从来不是”更努力”,而是”一个被重新提出的问题”。 当外部条件变化时,那些被默认的前提,就是下一场革命的支点。


🔗 相关:Vite | Webpack | Rollup | ES-Modules | Babel | Turbopack | 2018-2023 工程化时代 🔗 深度专题:为什么Webpack统治了十年 | 为什么pnpm解决了依赖问题 | 未来5到10年前端发展方向