2020+ 新一代工具(Vite / esbuild / SWC)
初步认识
为什么会出现新一代工具?
上一阶段(Webpack / Rollup / Parcel)虽然极大提升了前端开发,但随着项目复杂化,痛点越来越突出:
- 启动慢
- Webpack 打包方式是“全量打包”:改一行代码,往往要重新构建整个依赖树。
- 大型项目动辄几十秒甚至几分钟的冷启动,开发体验差。
- 热更新卡顿
- HMR(热模块替换)本意是提升效率,但在大型项目中,热更新也可能要几秒,严重割裂“即时反馈”的体验。
- JavaScript 本身的进化
- 浏览器原生支持 ES Modules(ESM)越来越好,本地开发时不一定非要“打包”。
- 但 Webpack 那套依赖转换方式还停留在“打包优先”的思路。
于是,新的工具开始尝试 回到本源:
👉 “开发阶段,不打包,直接利用浏览器能力;生产阶段,再做优化打包。”
新一代工具的核心理念
可以归纳为三点:
- 开发与生产分离
- 开发:尽量直接、快速、原生(用 ESM,避免复杂打包)。
- 生产:才进行优化(Tree-shaking、压缩、代码拆分)。
- 极致性能
- 用 Go / Rust 写构建工具(如 esbuild、SWC),速度提升几十倍。
- Webpack 的 JS 实现,速度天花板有限。
- 面向现代浏览器
- 不再假设 IE11 一定存在。
- 利用浏览器原生功能(ESM、HTTP/2 多路复用、原生 import)。
代表工具解析
1. Vite(尤雨溪团队,2020)
- 思路:
- 开发环境:不打包,直接用浏览器的 ES Modules。修改代码 → 浏览器直接重新请求该模块 → 秒级反馈。
- 生产环境:借助 Rollup 打包优化。
- 特点:
- 极快冷启动(不需要打包整个项目)。
- 局部更新快(改一个模块,就只重新加载那部分)。
- 天然支持 Vue、React 等现代框架。
- 影响力:
- 已经取代 Webpack,成为 Vue 官方推荐工具。
- React 社区也大量采用(Vite + SWC)。
2. esbuild(Evan Wallace,2020)
- 背景:
- 作者是 Figma 联合创始人之一。Figma 本身是对性能要求极高的应用。
- esbuild 用 Go 语言写,性能比 Webpack 提升 10~100 倍。
- 特点:
- 超高速打包和压缩。
- 支持 Tree-shaking、代码分割。
- 许多工具(包括 Vite)内部都调用 esbuild 来处理依赖。
- 定位:
- 更像是“底层引擎”,不直接和开发者交互,而是被集成到其他工具中。
3. SWC(Speedy Web Compiler,Rust 实现)
- 定位:
- 类似 Babel + Terser(JS 压缩)的替代品。
- Rust 编写,速度极快。
- 应用:
- Next.js 已经全面替换 Babel,使用 SWC 来编译和压缩代码。
- 未来也可能成为更多工具的默认“编译引擎”。
对比总结:旧 vs 新
| 维度 | Webpack / Rollup | Vite / esbuild / SWC |
|---|---|---|
| 核心思路 | 打包优先,开发和生产一致 | 开发不打包,生产再优化 |
| 技术栈 | JS 实现 | Go / Rust 实现 |
| 性能 | 冷启动慢,热更新延迟 | 冷启动秒开,热更新即时 |
| 面向环境 | 兼容各种浏览器(包括旧版) | 偏向现代浏览器(ESM 原生支持) |
| 定位 | 全功能打包器 | 新一代编译/构建引擎 |
整体演进的必然性
- 早期(Grunt / Gulp):任务自动化,减少手工。
- 打包时代(Webpack):为了解决模块化和兼容性问题。
- 新一代(Vite / esbuild / SWC):回到本源,充分利用浏览器与现代语言的性能优势。
总结:
👉 “新一代工具的本质,是在现代浏览器环境下,把开发体验做到极致(快、简洁、直接),同时在生产环境仍保留传统优化手段。”
Vite时期 的开发环境 vs 生产环境
问题背景:Webpack 的局限
Webpack 时代(2015+),虽然区分了 Dev / Prod 两个模式,但存在两个痛点:
- 开发环境慢
- Webpack 开发时也要“打包”(即便不开压缩、不开优化),仍然要把所有依赖走一遍 Loader、构建 Bundle。
- 项目几百个模块时,冷启动慢、改代码再热更新也慢。
- 生产环境和开发环境差距大
- Dev 下是“一个 DevServer 提供 HMR 的 Bundle”,
- Prod 下是“优化压缩后的多 Bundle 文件”。
- 两个模式产物差别大,导致“线上 bug 无法在本地复现”的情况时有发生。
👉 所以当时人们就在思考:能不能让开发环境和生产环境快,又更接近?
**注意:**什么是让开发环境和生产环境更接近?这里的接近指的开发时代码和浏览器运行代码的接近,在Webpack时浏览器运行的就是打包后的代码,与开发时代码有很大差异。
Vite 的核心创新
Vite(2020+)的设计可以总结为一句话:
开发时不打包,生产时再优化。
Vite 的两套模式
1. 开发环境(Dev)
目标:极致快的开发体验
核心原理:
- 原生 ESM 支持
现代浏览器(Chrome/Edge/Firefox/Safari)已经能原生识别import。
👉 开发时,Vite 不再打包,而是直接把源码交给浏览器:
// 你写的
import { add } from './utils/math.js'
👉 浏览器自己去请求 /src/utils/math.js,Vite 只做 按需的转换(Transform):
- `.ts → .js`
- `.vue → JS + CSS`
- `.scss → CSS`
- 图片/字体 → URL
- 即时启动:冷启动时不再“全量打包”,而是只在请求到某个模块时才进行转换。
- HMR 极速更新:修改一个 Vue 组件,只需重新编译那一个文件,毫秒级反馈。
对比 Webpack:
Webpack DevServer:启动 → 打包所有文件 → 浏览器请求的其实是一个大的 bundle。
Vite DevServer:启动 → 几乎零等待 → 浏览器请求哪个文件才编译哪个文件。
2. 生产环境(Build)
目标:最优产物,适合上线
核心原理:
- Rollup 打包:Vite 生产构建仍然使用 Rollup,原因是:
- 线上不能让用户发 300 个 HTTP 请求去拿 300 个模块 → 要合并、拆分成更合理的 chunk。
- 要进行 Tree-shaking、压缩、代码分割 等优化。
- 资源优化:
- JS 压缩(Terser/Esbuild)
- CSS 提取和压缩
- 图片/字体文件 hash 命名,结合浏览器缓存
- 兼容性:有些老浏览器不能跑原生 ESM,需要打包成兼容的产物。
对比总结(Webpack vs Vite)
| 维度 | Webpack Dev | Vite Dev | Webpack Prod | Vite Prod |
|---|---|---|---|---|
| 启动速度 | 慢,需要打包 | 快,直接走原生 ESM | 中等偏慢 | Rollup 优化产物 |
| HMR | 秒级,依赖全局构建 | 毫秒级,局部转换 | 不支持 | 不支持 |
| 调试体验 | Bundle 代码,不完全等同源码 | 源码即模块,调试友好 | 优化后代码难调试 | 优化后代码难调试 |
| 产物优化 | Dev 模式无优化 | Dev 不需要产物 | 体积优化(Tree-shaking、压缩) | 同样优化,但更高效 |
总结:
👉 Webpack 的 Dev 还是“打包”,Vite 的 Dev 是“原生模块直出”。
👉 Vite 的 Prod 依旧要打包,但借助 Rollup,优化得更极致。
工程化意义
Vite 带来了一个“前端构建的分工明确”思想:
- 开发体验用 ESM → 快速反馈
- 上线体验用 Rollup → 最优产物
它让“开发 vs 上线”这两个环境的差异 合理化,既兼顾了开发效率,又兼顾了生产性能。
打包是否还必要?
前置思考
前面讲到随着浏览器原生支持 ES Modules(ESM)越来越好,开发时可以不打包,且开发时访问前端项目也很流畅,现代浏览器可以按需加载模块,运行也很流畅,可见在本地运行时性能上并没有问题,抛开兼容性不谈,既然已经能够流畅运行,打包是否还必要?
开发时“流畅”,为什么?
- 现代浏览器能识别 ESM,遇到
import就会发起请求,按需加载依赖。 - HTTP/2/3 多路复用,大量小文件请求开销降低。
- 在开发机(本地环境)通常只有一个人访问,网络条件接近 局域网级别,延迟很低。
👉 所以你感觉性能很好,毫无压力。
生产环境的问题
一旦项目上线,面对的环境就完全不同:
(1)请求数量和延迟问题
- 一个真实项目可能有几百、几千个模块(尤其是 Vue/React + 各种依赖)。
- 浏览器会为每个
import发起一次请求:- 即使 HTTP/2 支持并发,TLS 握手、Header 传输、服务器响应延迟等依然存在。
- 在移动网络(4G/5G、弱网环境)里,几百个请求会严重拖慢首屏加载。
例子:
- 本地开发:300 个模块,0ms 延迟 → 几乎瞬间。
- 生产环境:300 个请求 × 50ms 延迟 = 15 秒光是 RTT(往返延迟),首屏卡死。
(2)缓存优化
- 如果不打包,300 个文件每次都要单独请求、单独协商缓存。
- 打包后:
- 核心代码打成
app.js,第三方库打成vendor.js。 - 只有变更的 chunk 会重新下载 → 缓存利用率高。
- 核心代码打成
(3)Tree Shaking / Dead Code Elimination
- 打包工具能静态分析 import/export,只保留用到的代码。
- 如果直接让浏览器加载
lodash-es,那就是完整包(几百 KB)。 - 但通过打包 → 最终可能只保留
cloneDeep,大小降到几十 KB。
(4)非 JS 资源处理
- 浏览器不认识
.vue、.ts、.scss、图片 import。 - 必须通过打包工具把它们转换成 JS/CSS/HTML。
- 没有打包,这些文件压根没法跑在生产环境。
(5)安全 & 部署问题
- 打包过程还能自动插入 polyfill,屏蔽不同浏览器的差异。
- 输出产物经过压缩、混淆,能保护源码逻辑,不会直接暴露业务代码。
- 静态资源加 hash,防止 CDN 缓存不一致。
按需加载能否成为打包的必要理由
前置思考
如果仔细阅读上面内容,仔细思考就会发现,其中依然有些矛盾点,令人困惑:现代浏览器能识别 ESM,遇到 import 就会发起请求,按需加载依赖”,本地不打包的时候不就已经做到了按需加载吗?那么我们在上面为什么还把上线后“如果不打包,300 个文件每次都要单独请求、单独协商缓存”作为需要打包的理由?明明不打包现代浏览器也按需加载。
首先我们的疑惑是正确的:不打包时,现代浏览器 ESM 本身就是按需加载。
那为什么我还说“300 个文件会有问题”?关键在于:
- 本地开发:所有文件都在你的硬盘里,Vite Dev Server 直接用 HTTP 把文件吐给浏览器 → 网络延迟几乎为零。
- 线上生产:
- 每个
import都是一次 HTTP 请求 → 请求头、握手、TLS、服务器响应时间,都会累计。 - 虽然 HTTP/2 可以多路复用,但并不是“零开销”。几百个请求依然比 2~3 个请求慢得多。
- 每个
👉 结论:
- 不打包:按需没错,但请求太多,首屏加载慢。
- 打包:把 300 个模块打成 2~3 个大文件 → 大幅减少请求次数。
所以并不是“按需”错了,而是“请求数 + 网络环境”导致上线体验很差。
非 JS 资源处理能否成为打包的必要理由?
前置思考
对于非JS资源处理,前面我们说“浏览器不认识 .vue、.ts、.scss、图片 import。 必须通过打包工具把它们转换成 JS/CSS/HTML”,但同时前面又说,现代浏览器可以不打包,也能运行,那么“对非JS资源处理”也不能成为一定要打包的理由吧?
这里要区分两个层次:
(1)现代浏览器原生 ESM 确实只支持 JS 模块
.vue、.ts、.scss→ 浏览器不认识,不能直接运行。- 你在本地开发能跑起来,是因为 Vite/Webpack Dev Server 在背后帮你做了 “即时转换(On-the-fly transform)”:
.ts→ Babel/tsc 转成 JS。.scss→ Sass 编译成 CSS,再注入。.vue→ Vue 编译器拆成 JS + CSS。
- 这些都不是浏览器原生完成的,而是 Node.js 构建工具临时帮你做的。
(2)所以不打包也能跑 → 但前提是 dev server 做了伪打包
比如 Vite:
- 开发时:它把
.vue转换成 JS,直接发给浏览器(虽然没打包,但已经“编译”了)。 - 生产时:必须提前把这些转换过的内容,合并、压缩、分 chunk,输出静态产物,才能上线。
👉 结论:
- 不打包时你看到的“也能跑” → 其实背后有 实时编译,只是没有合并、优化。
- 真正裸奔的浏览器(关掉 Vite/webpack-dev-server),你把
.vue或.ts丢给它,它完全跑不起来。
总结
- 按需加载问题:
- 本地 OK(几乎零延迟)。
- 线上不 OK(请求数太多,延迟叠加)。
- → 打包能减少请求数。
- 非 JS 资源问题:
- 浏览器只能原生理解 JS 模块。
.ts/.vue/.scss等都要先转译成 JS/CSS/HTML → 这个动作即使不打包,也必须做。- → 打包不仅转译,还进一步合并优化,才能真正上线。
- 开发时:追求“快”,ESM 原生支持 + Vite → 不打包,随改随生效。
- 生产时:追求“稳 + 省” → 打包,解决请求数量、性能优化、缓存、兼容、非 JS 资源转换。
👉 所以,现代前端的最佳实践是:开发时不打包,生产时必须打包。