你改了一行代码,按下保存。
Vite:100 毫秒内浏览器刷新。
Webpack:要等一秒。
为什么差距这么大?
答案在这行哲学级设计选择里:
"文件变化时,要重新编译多少模块?"
- Vite:只编译这个文件。
- Webpack / Turbopack :编译这个文件和它影响到的所有模块。
这一个决策,让 Vite 快出一倍,也种下了"偶尔翻车"的种子。
⚙️ Vite 为什么这么快
Vite 的核心是极致的最小编译。
- 检测到改动 → 只用 esbuild 重编译这一个文件(约 20--30ms)。
- 找 HMR 边界(比如 React 组件)。
- 通过 WebSocket 通知浏览器:
import('/src/xxx?t=时间戳')
。 - React Fast Refresh 替换组件函数,保留 state 并重新渲染。
整个过程通常100ms 内完成,开发者几乎感受不到延迟。
⚡ 这是"即时反馈"体验的关键。
Vite 为什么会"翻车"
Vite 快,是因为它只替换组件函数,不会重新执行模块顶层代码。
但正是这点,导致某些情况出错或不一致。
1. 模块顶层常量不更新
tsx
export const THEME = 'dark';
const currentTheme = themeMap[THEME]; // 只计算一次
改成 'light'
后,组件渲染新主题,但 currentTheme
依然是旧值。
2. 顶层实例不重建
tsx
const store = new Store();
改了 Store 的逻辑,实例还在旧的内存里,不会重建。
3. 副作用重复或缺失
tsx
console.log('init');
window.initSomething();
模块被重复执行时,副作用代码可能被多次调用,产生混乱。
4. 循环依赖
A 导入 B,B 又导入 A。Vite 会放弃 HMR,触发整页刷新。
这些问题都源于:模块没重新执行 。
Vite 的成功率在实践中大约 90--95% 。
Webpack 的思路:稳中求全
Webpack 在 HMR 时,不仅编译变动的模块,还会编译所有受影响的依赖链,确保顶层逻辑重新执行。
优点:一致性高,不会出现"变量更新了但模块没重跑"的错乱。
缺点:慢。
- 依赖分析:50ms
- 多模块重编译:300ms
- 推送更新 + 执行:150ms
- 总计约 500ms
成功率约 97--99% ,但牺牲了灵敏度。
Webpack 的哲学是"宁慢勿错",保证行为一致。
Turbopack:两边都要的野心家
Next.js 团队的 Turbopack 想在Vite 的速度 和Webpack 的可靠性之间找平衡。
- 使用 Rust 编译管线,极快的增量编译。
- 增量图更新 + 响应式依赖追踪机制(动态重计算受影响的子图)。
- 成功率接近 Webpack,但速度明显更快。
实测数据:
工具 | 平均更新时间 | 成功率 | 特点 |
---|---|---|---|
Vite | ≈100ms | 90--95% | 极速反馈,偶尔翻车 |
Webpack | ≈500ms | 97--99% | 稳定保守,延迟明显 |
Turbopack | ≈200ms | 96--99% | 速度稳定兼顾,未来之选 |
Turbopack 的哲学是"用增量计算保障正确性 ",
目标是在大型项目中维持接近 Vite 的体验,又避免状态不一致。
如何写出不容易"翻车"的 Vite 代码
Vite 快速没问题,关键是你别坑自己。
1. 状态放组件,不放模块顶层
tsx
// ❌
const store = new Store();
// ✅
export function App() {
const [store] = useState(() => new Store());
}
2. 导出对象而不是常量
tsx
// ❌
export const MAX_COUNT = 10;
// ✅
export const config = { MAX_COUNT: 10 };
if (import.meta.hot) {
import.meta.hot.accept(newModule => Object.assign(config, newModule.config));
}
3. 避免模块顶层副作用
tsx
// ❌
window.initAnalytics();
// ✅
export function initAnalytics() {
window.initAnalytics();
}
4. 用函数返回动态值
tsx
// ❌
export const theme = themeConfig[THEME];
// ✅
export function getTheme() {
return themeConfig[THEME];
}
这些习惯能让 Vite 的 HMR 稳定性接近 Turbopack 水平。
结论
Vite 就像一辆赛车:快得离谱,但需要会开。
Webpack 像老式坦克:笨重,却从不出事。
Turbopack 则在造一辆装了防撞系统的超跑。
你想要速度、稳定,还是两者兼得?
选谁,其实就是选择开发体验的哲学。