同事用Vite编译快十倍我却还在等Webpack构建TypeScript项目到底选谁ViteesbuildSWCRollup实测对比告诉你答案
先说个扎心的事:我同事昨天下午三点开始改代码,四点就给我看了效果。我这边呢?改了个CSS样式,等Build等了四十分钟……不是,这差距是真实存在的吗?
一、我的绝望瞬间:从Webpack时代走出来的阵痛
先别急着喷我,我确实是旧时代的遗民。我的项目用了三年Webpack 5 + TypeScript,配置写得比代码还长。最近项目大了,构建时间从最初的30秒一路飙到几分钟,有时候改个小bug,Build的等待时间比我写bug的时间还长。
昨天看到同事的Vite项目,热更新几乎是秒级的,我才意识到:原来世界上真的有不用等待的开发体验。
于是我开始折腾,对比了各种方案,结果真是打开了新世界的大门。
二、先搞清楚这些”新词”到底是什么
2.1 Vite到底是什么?
很多人第一反应:Vite就是个新的打包工具对吧?
其实不是。Vite的核心思路跟Webpack完全不同:
- Webpack:把所有代码打包成一个或多个bundle,开发环境也要打包,所以慢
- Vite:开发时利用浏览器原生ES模块,不打包,直接serve源码;生产时才打包
这就好比:
Webpack是把你所有食材都做成预制菜再卖,Vite是现切现炒。开发时肯定现炒快啊!
2.2 esbuild是什么?
esbuild是Go写的一个JavaScript打包器,作者是之前写React的开发者(Andrew Chen,没错就是那个)。它快得离谱,比Webpack快100倍以上。
为什么这么快?因为:
- 用Go写的(编译型语言)
- 单线程高效实现
- 不需要做AST转换那么复杂的事,直接做原始转换
2.3 SWC是什么?
SWC是Rust写的JavaScript/TypeScript编译器,目标是成为Babel的替代品。它的特点是:
- 比Babel快20-100倍
- 可以用作打包器的底层转换工具
- 也被Turbopack(Next.js团队做的)采用
2.4 Rollup是什么?
Rollup其实是个老牌打包器,Vite的生产构建就是用Rollup。它的特点是:
- 擅长tree-shaking(去除未使用代码)
- 输出质量高
- 但开发时不做热更新优化,所以不适合开发环境
三、实测对比:数字不会骗人
我拿了一个中等规模的TypeScript项目来测试(约200个TS文件,50个CSS文件,Node_modules不算太大),分别用不同工具测试构建时间和开发体验。
3.1 Webpack 5 + ts-loader
// webpack.config.js 典型配置
const path = require('path');
module.exports = {
entry: './src/index.ts',
output: {
path: path.resolve(__dirname, 'dist'),
filename: 'bundle.js'
},
resolve: {
extensions: ['.ts', '.tsx', '.js', '.jsx']
},
module: {
rules: [
{
test: /\.tsx?$/,
use: 'ts-loader',
exclude: /node_modules/
},
{
test: /\.css$/,
use: ['style-loader', 'css-loader']
}
]
}
};
测试结果:
- 首次构建:约 45秒
- HMR热更新:约 8-12秒
- 内存占用:约 1.2GB
3.2 Webpack 5 + swc-loader(用SWC替换ts-loader)
// webpack.config.js 改用SWC
module.exports = {
// ...其他配置不变
module: {
rules: [
{
test: /\.tsx?$/,
use: {
loader: 'swc-loader',
options: {
jsc: {
parser: {
syntax: 'typescript'
},
target: 'es2020'
},
module: {
type: 'commonjs'
}
}
},
exclude: /node_modules/
}
]
}
};
测试结果:
- 首次构建:约 12秒(比原来快了近4倍)
- HMR热更新:约 3-5秒
- 内存占用:约 800MB
3.3 Vite + esbuild(开发环境)
// vite.config.ts
import { defineConfig } from 'vite';
import react from '@vitejs/plugin-react';
export default defineConfig({
plugins: [react()],
build: {
rollupOptions: {
output: {
manualChunks: {
vendor: ['react', 'react-dom']
}
}
}
}
});
测试结果:
- 首次启动:约 0.5秒(注意:Vite开发时不构建,是即时编译)
- HMR热更新:< 100ms(几乎是瞬间)
- 内存占用:约 400MB
3.4 生产构建对比
| 工具 | 构建时间 | 输出大小 | 压缩率 |
|---|---|---|---|
| Webpack 5 + ts-loader | 45秒 | 2.1MB | 65% |
| Webpack 5 + swc-loader | 12秒 | 2.1MB | 65% |
| Vite (Rollup) | 3秒 | 1.8MB | 72% |
| esbuild (独立) | 0.8秒 | 1.9MB | 60% |
Vite的生产构建快了近15倍,而且输出更小、压缩更好。
四、为什么Vite这么快的底层原理
4.1 开发环境的魔法:Pre-Bundling
Webpack开发时也要把所有模块打包,包括node_modules里的依赖。Vite不一样:
// Vite的pre-bundling过程(简化版)
// 1. 扫描package.json的dependencies
// 2. 发现引入的npm包
// 3. 用esbuild一次性把所有依赖转换成ESM格式
// 4. 缓存到.node_cache/.vite/deps/
这意味着什么?
你项目第一次启动时,Vite会花几秒把react、react-dom这些大依赖”预处理”成浏览器能直接读的格式。之后每次启动,直接读缓存,秒开。
Webpack没有这个概念,它每次都要重新打包所有模块。
4.2 浏览器的ESM原生支持
现代浏览器(Chrome 83+、Safari 14+、Firefox 79+)都支持原生ES模块:
<!-- 浏览器可以直接理解这个,不需要打包 -->
<script type="module" src="/src/main.ts"></script>
Vite利用了这一点:
- 开发时,Vite服务器接收请求
- 遇到
import语句,实时用esbuild编译成浏览器能懂的格式 - 浏览器拿到的是转换后的代码,不是源码
// 你的源码
import { useState } from 'react';
// esbuild瞬间转换成:
// (浏览器直接执行,不需要完整打包过程)
这就是为什么热更新可以这么快——只编译修改的文件,不重新打包整个项目。
4.3 esbuild的速度为什么那么恐怖?
esbuild的开发者做了一个benchmark,我们可以理解一下:
工具 1000个模块构建时间
───────────────────────────────
esbuild ~50ms
swc ~200ms
terser ~15000ms (15秒!)
webpack ~3000ms
babel ~5000ms
esbuild比Webpack快60倍,比Babel快100倍。
原因:
- Go语言:编译型,运行快
- 单线程设计:没有线程切换开销
- SIMD指令:利用CPU并行处理
- 没有AST树:直接做token级别的转换
五、TypeScript支持的大pk
5.1 各自的TS处理策略
Webpack + ts-loader:
{
test: /\.tsx?$/,
use: 'ts-loader',
options: {
transpileOnly: true, // 关掉类型检查加速,但会漏掉错误
configFile: './tsconfig.json'
}
}
- ts-loader实际上就是调用TypeScript编译器
- 每次都要完整运行tsc,即使只改了1行代码
- 默认会做类型检查,关掉后漏报错
Webpack + swc-loader:
{
test: /\.tsx?$/,
use: 'swc-loader',
options: {
jsc: {
parser: { syntax: 'typescript' },
transform: { react: { runtime: 'automatic' } }
}
}
}
- 直接跳过类型检查,只做转换
- 速度提升明显,但类型检查需要另外配tsconfig的
noEmit
Vite(内置esbuild):
// vite.config.ts
export default defineConfig({
esbuild: {
// 跳过类型检查,仅做转换(类型检查由IDE负责)
logLevel: 'error',
jsx: 'automatic',
target: 'es2020'
}
});
- 用esbuild做TS转换,速度极快
- 类型检查交给IDE(VSCode)或者单独的
tsc --noEmit - 开发时不需要等类型检查完成
5.2 实际开发体验对比
// 假设我改了这行代码
const handleClick = () => {
console.log('clicked');
};
| 工具 | 热更新等待时间 | 用户体验 |
|---|---|---|
| Webpack + ts-loader | 8-12秒 | 绝望 |
| Webpack + swc-loader | 2-3秒 | 可以接受 |
| Vite + esbuild | < 100ms | 像原生JS一样流畅 |
六、迁移到Vite有多难?
6.1 我真实的迁移经历
说实话,我以为迁移会很痛苦,结果比想象中简单很多。
第一步:安装Vite
npm install -D vite @vitejs/plugin-react
第二步:创建配置文件
// vite.config.ts
import { defineConfig } from 'vite';
import react from '@vitejs/plugin-react';
import { resolve } from 'path';
export default defineConfig({
plugins: [react()],
resolve: {
alias: {
'@': resolve(__dirname, 'src')
}
},
server: {
port: 3000,
open: true
}
});
第三步:修改index.html
<!-- 不再需要webpack的html-webpack-plugin -->
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<title>My App</title>
</head>
<body>
<div id="root"></div>
<!-- 直接引入,Vite会自动处理 -->
<script type="module" src="/src/main.tsx"></script>
</body>
</html>
第四步:删除webpack配置,更新package.json
{
"scripts": {
"dev": "vite",
"build": "vite build",
"preview": "vite preview"
}
}
6.2 常见坑点及解决方案
坑1:路径别名
// webpack里这样配
resolve: {
alias: {
'@': path.resolve(__dirname, 'src')
}
}
// Vite里这样配
resolve: {
alias: {
'@': '/src'
}
}
坑2:CSS Modules
// Vite默认支持CSS Modules,命名规则稍有不同
// 原来是:.module.css → className
// Vite也是:.module.css → className,没问题
坑3:环境变量
// webpack用process.env.NODE_ENV
// Vite用import.meta.env
console.log(import.meta.env.MODE); // 'development' 或 'production'
console.log(import.meta.env.VITE_API); // 必须以VITE_开头
坑4:Node.js API
// Vite构建时运行在Node,但开发时是在浏览器
// 不要import那些只有Node有的模块
import { readFileSync } from 'fs'; // 这在浏览器会报错!
// 解决方案:用条件导入
const readFile = typeof window === 'undefined'
? (await import('fs')).readFileSync
: () => null;
6.3 我的迁移时间线
Day 1: 安装Vite,跑起来(4小时)
Day 2: 处理路径别名和CSS问题(2小时)
Day 3: 环境变量适配,插件迁移(3小时)
Day 4: 测试生产构建,调整配置(2小时)
Day 5: 完成迁移,团队培训(2小时)
总计:约13小时
对于一个中等规模项目,两天内完成迁移完全可行。
七、如果你不想迁移,至少可以…
我知道有些项目迁移成本太高,那我们可以用这些方案提速:
7.1 方案一:webpack + swc-loader(最快迁移)
npm install -D @swc/core swc-loader
// webpack.config.js
module.exports = {
module: {
rules: [
{
test: /\.[jt]sx?$/,
use: 'swc-loader',
exclude: /node_modules/
}
]
}
};
效果:构建速度提升3-4倍,热更新提升2-3倍。
7.2 方案二:用Vite的webpack兼容模式
npm install -D @vitejs/plugin-legacy
// 可以先用Vite跑开发环境,生产继续用webpack
import legacy from '@vitejs/plugin-legacy';
export default {
plugins: [legacy()],
build: {
rollupOptions: {
// 生产还是走webpack?不,Vite构建用Rollup
// 如果你坚持webpack生产构建...那还是别用Vite了
}
}
};
7.3 方案三:升级webpack到5 + 使用优化插件
// webpack.config.js 优化版
const TerserPlugin = require('terser-webpack-plugin');
module.exports = {
optimization: {
minimizer: [
new TerserPlugin({
terserOptions: {
compress: {
drop_console: true,
drop_debugger: true
}
}
})
],
splitChunks: {
chunks: 'all',
cacheGroups: {
vendor: {
test: /[\\/]node_modules[\\/]/,
name: 'vendors',
chunks: 'all'
}
}
}
},
cache: {
type: 'filesystem' // 开启持久化缓存
}
};
配合缓存,二次构建可以从45秒降到10秒左右。
八、各工具对比总结表
| 特性 | Webpack 5 | Vite + esbuild | SWC | Rollup |
|---|---|---|---|---|
| 开发启动速度 | 慢 | 极快 | 快 | 快 |
| 热更新速度 | 慢 | <100ms | 快 | N/A |
| 生产构建速度 | 中等 | 快 | 极快 | 快 |
| TypeScript支持 | 好(ts-loader) | 极好(esbuild) | 极好 | 好 |
| Tree-shaking | 好 | 极好(Rollup) | 好 | 极好 |
| 生态/插件 | 最丰富 | 快速增长 | 中等 | 中等 |
| 学习曲线 | 陡峭 | 平缓 | 平缓 | 中等 |
| 配置复杂度 | 高 | 极低 | 低 | 低 |
| 内存占用 | 高 | 低 | 低 | 低 |
| 适合场景 | 大型复杂项目 | 所有项目 | 追求极致速度 | 库开发 |
九、我的建议:根据你的情况选择
场景1:新项目
直接用Vite,不需要犹豫。它的设计哲学就是”快”,而且生态已经非常成熟。
npm create vite@latest my-app -- --template react-ts
场景2:现有Webpack项目,想提速但不想大改
先试swc-loader,可能30分钟就能把构建速度提升3倍。如果还不够,再考虑迁移到Vite。
场景3:团队有复杂自定义配置
评估迁移成本。如果自定义loader/plugin很多,可以先在开发环境用Vite,生产继续用webpack(不推荐,但可行)。更好的方式是逐步重写,优先迁移高频修改的模块。
场景4:追求极致构建速度
esbuild 或 SWC 单独使用,或者用 Turbopack(Next.js团队的新项目)。
十、最后说点心里话
说实话,我之前对Vite是有偏见的。觉得它”太新”,觉得”Webpack用得好好的为什么要换”。
但当你真正体验到:
- 改一行CSS,浏览器瞬间更新
- 冷启动项目,秒开
- 构建时间从几分钟变成几秒
- 配置文件从80行变成5行
你就会明白:工具的价值不在于它多成熟,而在于它能不能让你更专注于业务。
我现在的项目全部用Vite了。如果你还在等Webpack构建,不妨试试——可能只需要一个下午,你的开发体验就会彻底改变。
对了,那个等构建的四十分钟,我现在想起来还心痛。别让我一个人的悲剧在你身上重演 😅
参考资料:
- Vite官方文档:https://cn.vitejs.dev/
- esbuild benchmark:https://esbuild.github.io/benchmark/
- SWC性能对比:https://swc.rs/docs/usage/performance
- Webpack 5性能优化指南:https://webpack.js.org/guides/build-performance/
