Vite打包

前言

Vite 凭借极快的冷启动和热更新体验迅速成为主流构建工具。但开发时基于 ESM 的按需编译与生产打包基于 Rollup 的机制截然不同,理解这两层关系是掌握 Vite 打包的关键。

一、开发 vs 生产:两套机制

Vite 在开发和打包时使用不同的策略:

阶段 引擎 原理
开发 esbuild 预构建依赖 + ESM 按需编译,毫秒级冷启动
生产 Rollup 全量打包,Tree-Shaking、代码分割、压缩

为什么不用 esbuild 打包?
esbuild 在代码分割和 CSS 处理上仍有局限,Rollup 生态成熟、插件丰富,是目前的最优解。

二、Rollup 打包流程

Vite 生产构建本质上是调用 Rollup 并传入内部插件链:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
// vite build 的简化流程
const { rollup } = require('rollup')

const bundle = await rollup({
input: 'index.html', // Vite 以 HTML 为入口
plugins: [
viteResolvePlugin(), // 路径解析
viteCSSPlugin(), // CSS 处理
viteAssetPlugin(), // 静态资源
viteHTMLPlugin(), // HTML 处理
// ... 用户自定义插件
]
})

await bundle.write({
dir: 'dist',
format: 'es', // 默认 ES Module
manualChunks: { /* 分包策略 */ }
})

入口是 index.html,Vite 会在构建时解析 HTML 中的 <script> 和 <link> 标签来收集依赖。

三、代码分割(分包策略)

不做分包会导致业务代码全打进一个大文件,首屏加载极慢。

默认分包

Vite 自动将 node_modules 中的依赖按以下规则分 chunk:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
// Vite 内置的默认分包逻辑(简化版)
function splitVendorChunkPlugin() {
return {
name: 'vite:split-vendor-chunk',
config(config) {
config.build = config.build || {}
config.build.rollupOptions = config.build.rollupOptions || {}
config.build.rollupOptions.output = {
manualChunks(id) {
if (id.includes('node_modules')) {
return 'vendor' // 所有 node_modules 打一起
}
}
}
}
}
}

自定义分包(推荐)

实际项目建议按模块大小和使用频率精细拆分:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
// vite.config.js
export default defineConfig({
build: {
rollupOptions: {
output: {
manualChunks: {
// 将 Vue 生态拆为独立 chunk
'vue-vendor': ['vue', 'vue-router', 'pinia'],
// UI 库单独打包(通常体积大)
'ui-vendor': ['ant-design-vue', '@ant-design/icons-vue'],
// 工具库
'util-vendor': ['lodash-es', 'dayjs', 'axios'],
// ECharts 体积极大,必须独立
'echarts-vendor': ['echarts'],
}
}
}
}
})

动态分包(推荐生产环境)

1
2
3
4
5
6
manualChunks(id) {
if (id.includes('node_modules')) {
// node_modules 的每个包独立打包,利用缓存
return id.toString().split('node_modules/')[1].split('/')[0]
}
}

分包追求的目标:低频变动的依赖拆成独立 chunk → 利用浏览器缓存 → 二次访问提速。

四、常用打包配置

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
// vite.config.js
import { defineConfig } from 'vite'
import vue from '@vitejs/plugin-vue'
import { visualizer } from 'rollup-plugin-visualizer'
import compression from 'vite-plugin-compression'

export default defineConfig({
plugins: [vue()],
build: {
// 输出目录
outDir: 'dist',
// 静态资源目录
assetsDir: 'assets',
// chunk 大小警告阈值(KB)
chunkSizeWarningLimit: 500,
// 生成 sourcemap(生产建议关闭或 hidden)
sourcemap: false,
// 开启 CSS 代码分割
cssCodeSplit: true,
// 压缩配置
minify: 'esbuild', // 'esbuild' | 'terser'
terserOptions: {
compress: {
drop_console: true, // 去除 console
drop_debugger: true, // 去除 debugger
}
},
rollupOptions: {
output: {
// 入口 chunk 命名
entryFileNames: 'js/[name]-[hash:8].js',
// 非入口 chunk 命名
chunkFileNames: 'js/[name]-[hash:8].js',
// 静态资源命名
assetFileNames: 'assets/[name]-[hash:8][extname]',
// 分包
manualChunks: {
'vue-vendor': ['vue', 'vue-router', 'pinia'],
}
}
}
}
})

五、打包体积分析

使用 rollup-plugin-visualizer

1
npm i -D rollup-plugin-visualizer
1
2
3
4
5
6
7
8
9
10
11
12
13
import { visualizer } from 'rollup-plugin-visualizer'

export default defineConfig({
plugins: [
vue(),
// 打包后生成 stats.html,可视化查看体积构成
visualizer({
open: true, // 自动打开浏览器
gzipSize: true, // 显示 gzip 后的大小
brotliSize: true, // 显示 brotli 大小
})
]
})

执行 npm run build 后自动打开可视化面板,一眼看出是哪个包拖垮了体积。

六、常见优化手段

1. 按需引入

1
2
3
4
5
// ❌ 全量引入,几百 KB
import { Button, Table, Form } from 'ant-design-vue'

// ✅ 按需加载配合 unplugin-vue-components 自动导入
// 无需手动 import,vite 自动处理

2. Gzip / Brotli 压缩

1
npm i -D vite-plugin-compression
1
2
3
4
5
6
7
8
9
10
import compression from 'vite-plugin-compression'

export default defineConfig({
plugins: [
// Gzip 压缩
compression({ algorithm: 'gzip', ext: '.gz' }),
// Brotli 压缩(压缩率更高)
compression({ algorithm: 'brotliCompress', ext: '.br' }),
]
})

3. 图片压缩

1
npm i -D vite-plugin-imagemin
1
2
3
4
5
6
7
8
9
10
11
12
13
14
import viteImagemin from 'vite-plugin-imagemin'

export default defineConfig({
plugins: [
viteImagemin({
gifsicle: { optimizationLevel: 3 },
mozjpeg: { quality: 80 },
pngquant: { quality: [0.8, 0.9] },
svgo: {
plugins: [{ name: 'removeViewBox', active: false }]
}
})
]
})

4. CDN 加速

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
// vite.config.js —— 配合 vite-plugin-cdn-import
import cdn from 'vite-plugin-cdn-import'

export default defineConfig({
plugins: [
cdn({
modules: [
{ name: 'vue', var: 'Vue', path: 'vue.global.prod.js' },
{ name: 'vue-router', var: 'VueRouter' },
{ name: 'pinia', var: 'Pinia' },
{ name: 'axios', var: 'axios' },
]
})
]
})

CDN 引入后这些依赖不打入 bundle,配合 externals 配置大幅缩减打包体积。

5. 优化总结清单

优化点 预期收益
按需引入 UI 库 减少 200KB+
Gzip + Brotli 压缩 70%+
图片压缩 减少 50-90%
分包策略 首屏加载减半
CDN 外链 核心包体积降为 0
移除 console/debugger 轻微体积优化
sourcemap 关闭 安全 + 体积

总结

  • Vite 开发用 esbuild(ESM 按需),打包用 Rollup(全量构建)
  • 分包策略是最重要的生产配置,决定首屏加载速度和缓存命中率
  • manualChunks 建议将 Vue/UI 库/ECharts 等大依赖独立拆出
  • 配合 rollup-plugin-visualizer 分析体积,针对性优化
  • 生产标配:分包 + Gzip + 按需引入 + 图片压缩

内容由 AI 生成,仅供参考。本文发布于 码上学习,转载请注明出处。