第一部分:基础概念篇
1.1 Rollup
Rollup是一个专注于ES模块的JavaScript打包工具,由Rich Harris创建于2015年。它的核心理念是利用ES模块的静态结构进行Tree Shaking,生成更简洁、更高效的代码。
Rollup的核心特点:
- 📦 专注ES模块:原生支持ESM,打包产物干净利落
- ✂️ 强大的Tree Shaking:自动移除未使用的代码
- 🔌 丰富的插件生态:6年多的积累,npm年下载量上亿次
- 🎯 适合库开发:Vue、React等主流框架都在用Rollup打包
// rollup.config.js 基础示例
import resolve from '@rollup/plugin-node-resolve'
import commonjs from '@rollup/plugin-commonjs'
import { terser } from 'rollup-plugin-terser'
export default {
input: 'src/main.js',
output: {
file: 'dist/bundle.js',
format: 'esm' // 输出格式:esm、cjs、umd等
},
plugins: [
resolve(), // 解析node_modules
commonjs(), // 转换CommonJS
terser() // 代码压缩
]
}
1.2 Vite
Vite(法语"快速"的意思)是尤雨溪团队于2020年发布的新一代前端构建工具。它的最大特点是利用浏览器原生ESM支持,实现开发环境no-bundle。
Vite的核心特点:
- ⚡ 极速冷启动:毫秒级启动,与项目规模无关
- 🔥 即时热更新:HMR速度快且稳定
- 🛠️ 开箱即用:内置TypeScript、JSX、CSS预处理器
- 🤝 双引擎架构:开发用esbuild,生产用Rollup
// vite.config.js 基础示例
import { defineConfig } from 'vite'
import vue from '@vitejs/plugin-vue'
export default defineConfig({
plugins: [vue()],
build: {
outDir: 'dist',
rollupOptions: {
// 这里可以配置Rollup选项
input: 'index.html'
}
}
})
1.3 两者的核心区别
| 维度 | Rollup | Vite |
|---|---|---|
| 定位 | 打包工具 | 构建工具(包含开发服务器) |
| 核心优势 | Tree Shaking、产物纯净 | 开发体验、启动速度 |
| 适用场景 | 库/工具开发 | 应用开发 |
| HMR支持 | ❌ 不支持 | ✅ 支持(基于ESM) |
| 配置复杂度 | 中等 | 低(开箱即用) |
| 生态 | 成熟稳定 | 快速发展中 |
一句话总结:
- Vite是构建工具(包含开发服务器和打包功能)
- Rollup是打包工具(专注于打包优化)
- Vite的生产打包功能正是建立在Rollup之上的
1.4 esbuild
esbuild 是一个用 Go语言 编写的下一代前端构建工具,由Evan Wallace(前Figma CTO)于2020年创建。它的核心特点就是一个字:快!快到什么程度呢?
性能对比(打包Three.js)
| 工具 | 语言 | 耗时 | 相对速度 |
|---|---|---|---|
| Webpack 5 | JavaScript | 23.5s | 1倍(基准) |
| Rollup 3 | JavaScript | 18.2s | 1.3倍 |
| Parcel 2 | JavaScript+Rust | 14.1s | 1.7倍 |
| esbuild | Go | 0.3s | 78倍 🚀 |
关键数据:esbuild比Webpack快 78倍!这就是Vite选择它作为开发环境引擎的根本原因。
esbuild局限性
| 限制项 | 说明 | 影响程度 |
|---|---|---|
| 代码分割 | 不支持动态导入的精细控制 | ⭐⭐⭐ |
| ES5降级 | 不能生成ES5代码 | ⭐⭐⭐ |
| TS语法限制 | 不支持const enum等 | ⭐⭐ |
| HMR支持 | 无内置HMR方案 | ⭐⭐ |
| 产物操作 | 无法像Rollup那样精细控制输出 | ⭐⭐ |
第二部分:双引擎架构深度解析
2.1 Vite的双引擎设计哲学
Vite最精妙的设计在于:开发环境与生产环境采用不同的工具链,各取所长。
2.2 esbuild在Vite中的三重角色
角色一:依赖预构建(Bundler)
当Vite启动时,它会扫描项目依赖,用esbuild将数百个分散的依赖模块打包成单个ESM文件。
// 预构建前
import { ref } from 'vue' // vue有上百个文件
// 预构建后
// node_modules/.vite/vue.js - 单个ESM文件
为什么要预构建?
- 解决CommonJS兼容性:很多依赖是CommonJS格式
- 减少HTTP请求:避免浏览器发送上百个请求
- 统一ESM格式:确保所有依赖都能被浏览器识别
角色二:单文件编译(Transformer)
Vite使用esbuild将TS、JSX等文件转换为JS,替代了传统的Babel或TSC。
性能对比(编译50MB纯代码文件):
- Babel:约40秒
- TSC:约60秒
- SWC:约2秒
- esbuild:约0.3秒 ⚡
局限性:esbuild不做类型检查,只抹除类型。这就是为什么vite build之前要执行tsc。
角色三:代码压缩(Minifier)
从Vite 2.6开始,默认使用esbuild进行生产环境的JS和CSS压缩。
压缩性能对比(echarts 3.2MB):
- Terser:8798ms
- esbuild:361ms(快24倍)
2.3 Rollup在Vite中的核心地位
为什么生产环境不用esbuild?
esbuild虽然快,但有四个致命缺陷:
| 缺陷 | 说明 | 影响 |
|---|---|---|
| 不支持ES5降级 | 无法输出ES5代码 | 低端浏览器无法运行 |
| 语法限制 | 不支持const enum等 | 某些TS语法会报错 |
| 无产物操作接口 | 没有renderChunk等钩子 | 无法精细控制输出 |
| 拆包策略固定 | 不支持自定义Code Splitting | 优化灵活性不足 |
而Rollup恰恰在这些方面表现出色,经过6年多的迭代,产物质量和稳定性都经得起考验。
Rollup在Vite中的三大优化
-
CSS代码分割:异步模块中的CSS自动抽取成独立文件,提高缓存复用率
-
自动预加载:为入口chunk的依赖自动生成
<link rel="modulepreload"><head> <script type="module" src="/assets/index.123abc.js"></script> <link rel="modulepreload" href="/assets/vendor.456def.js"> </head> -
异步Chunk加载优化:请求A的同时自动预加载公共依赖C,节省网络开销。
2.4 对比
Rollup和Webpack对比
- 设计理念与功能
-
Webpack
- 全能型的模块打包工具:支持 JavaScript、CSS、HTML、图片等各种静态资源
- 丰富的Loader机制:可以转换非 JavaScript 资源
- 代码分割 Code Splitting:路由懒加载代码块,提升页面加载速度
- 热模块替换 HMR:开发过程中实时刷新
- 配合Plugin系统实现复杂的构建流程定制
-
Rollup
- Rollup专注于JavaScript模块的打包和优化,专注于ES6模块规范
- 严格静态分析,出色的tree-shaking能力
- 输出的bundle倾向于更小、更纯净
- 适用场景
-
Webpack
- 大型SPA或企业级Web应用等需要处理多种资源和复杂的构建流程
- 需要做代码分割和按需加载的场景
- 有大量第三方库依赖和复杂业务逻辑的项目
-
Rollup
- 开发和发布独立的JavaScript库或组件,特别是那些遵循ES6模块规范的库
- 项目主要关注打包后代码大小和纯净性,而非处理大量非JS资源
- 如何选择
-
选择Webpack
- 当项目同时包含多个资源类型
- 当项目需要实现复杂的代码分割和动态加载策略
- 当项目规模较大,需要高度定制化构建流程时
-
选择Rollup
- 当项目主要是编写一个独立的、面向外部发布的JavaScript库时
- 当需要最大程度地优化代码大小,去除无用模块时
- 当项目不涉及过多的非JS资源,只需要专注JS模块打包优化时
使用Rollup打包库本身,使用Webpack来整合应用的所有资源并进行优化
Vite与webpack对比
- webpack打包项目:缓慢的服务器启动、缓慢的更新

当使用webpack打包项目时,webpack会根据配置文件中的入口文件entry,分析项目中所有的依赖关系,然后打包成一个文件bundle.js并交给浏览器去加载渲染。
- Vite打包项目:更快的服务器启动和更新速度

在<script type="module">中,浏览器遇到内部的import引用时,会自动发起http请求,去加载对应的模块。使用vite运行项目时,首先会用esbuild进行预构建,将所有模块转换为es module,不需要对整个项目进行编译打包,而是在浏览器需要加载某个模块时,拦截浏览器发出的HTTP请求,根据请求进行按需编译,然后返回给浏览器。
第三部分:性能优化策略
3.1 开发环境优化
依赖预构建优化
// vite.config.js
export default {
optimizeDeps: {
// 强制包含某些依赖
include: [
'lodash-es',
'axios > follow-redirects' // 嵌套依赖
],
// 排除不需要预构建的包
exclude: ['your-large-lib'],
// esbuild配置
esbuildOptions: {
target: 'es2020',
supported: {
'top-level-await': true
}
}
}
}
预热常用文件
export default {
server: {
warmup: {
// 启动时提前转换这些文件,避免请求瀑布
clientFiles: [
'./src/main.ts',
'./src/App.vue',
'./src/router/index.ts'
]
}
}
}
3.2 生产环境优化
代码分割策略
export default {
build: {
rollupOptions: {
output: {
// 手动分块
manualChunks: {
// 框架代码单独打包
'vendor': ['vue', 'vue-router', 'pinia'],
// UI库单独打包
'ui': ['element-plus', '@vueuse/components'],
// 工具库单独打包
'utils': ['lodash-es', 'dayjs', 'axios']
},
// 文件命名规则
entryFileNames: 'assets/[name]-[hash].js',
chunkFileNames: 'assets/[name]-[hash].js',
assetFileNames: 'assets/[name]-[hash].[ext]'
}
},
// 块大小警告阈值
chunkSizeWarningLimit: 1000,
// 压缩配置
minify: 'terser', // 或 'esbuild'
terserOptions: {
compress: {
drop_console: true, // 移除console
drop_debugger: true
}
}
}
}
CSS优化
export default {
css: {
// CSS模块化配置
modules: {
localsConvention: 'camelCase',
scopeBehaviour: 'local',
generateScopedName: '[name]__[local]__[hash:5]'
},
// 预处理器配置
preprocessorOptions: {
scss: {
additionalData: `@import "@/styles/variables.scss";`
}
},
// PostCSS配置
postcss: {
plugins: [
require('autoprefixer'),
require('cssnano')({ preset: 'default' })
]
}
}
}
3.3 构建分析
// vite.config.js
import { visualizer } from 'rollup-plugin-visualizer'
export default {
plugins: [
visualizer({
filename: 'dist/stats.html',
open: true, // 构建后自动打开
gzipSize: true,
brotliSize: true
})
]
}