跳到主要内容

Vite 插件与构建分析

📦 Vite 插件与 Rollup 插件 API 兼容。理解构建产物分析能让你准确切入优化点。

Vite 插件框架

// 自定义插件示例
import type { Plugin } from 'vite'

function myPlugin(): Plugin {
return {
name: 'my-plugin',

// 构建开始
buildStart() {
console.log('构建开始')
},

// 转换单个模块
transform(code, id) {
if (!id.endsWith('.vue')) return
return code.replace(/debug:/g, 'console.log:')
},

// 路径解析
resolveId(id) {
if (id === 'virtual:my-module') {
return '\0virtual:my-module'
}
},

// 加载虚拟模块
load(id) {
if (id === '\0virtual:my-module') {
return `export const data = ${JSON.stringify(fetchData())}`
}
},

// 修改 HTML
transformIndexHtml(html) {
return html.replace('<title>App</title>', '<title>My App</title>')
}
}
}

常用内置配置

// vite.config.ts
export default defineConfig({
build: {
// 指定入口
rollupOptions: {
input: {
main: 'index.html',
admin: 'admin.html'
},
output: {
// 手动分包
manualChunks: {
vendor: ['react', 'react-dom'],
utils: ['lodash', 'date-fns']
},
// 输出文件命名
chunkFileNames: 'assets/[name]-[hash].js',
assetFileNames: 'assets/[name]-[hash][extname]'
}
},
// 超过指定大小报警
chunkSizeWarningLimit: 500,
}
})

构建产物分析

rollup-plugin-visualizer

import { visualizer } from 'rollup-plugin-visualizer'

export default defineConfig({
plugins: [
visualizer({
open: true, // 构建后自动打开
gzipSize: true, // 显示 gzip 大小
brotliSize: true, // 显示 brotli 大小
filename: 'dist/stats.html'
})
]
})

分析要点

问题表现解决方式
依赖过大单个 chunk > 500KB按需加载或 CDN
重复依赖同一库被多个 chunk 包含manualChunks 合并
未使用代码bundle 包含未导入模块Tree Shaking 检查
图片过大原始图片 > 100KB将大图移到 CDN

Tree Shaking 调试

// 检查是否有副作用
package.json:
{
"sideEffects": false // 告知构建工具所有模块都无副作用
// "sideEffects": ["*.css", "src/polyfills.ts"]
}

// 常见破坏 Tree Shaking 的情况:
// 1. 使用 require() 而非 ES Module
// 2. 模块内有副作用但没有声明
// 3. Babel 将 import 转化为 require

常见插件

插件用途
@vitejs/plugin-reactReact + HMR
vite-plugin-pwaPWA + Service Worker
vite-tsconfig-pathstsconfig 路径别名
unplugin-auto-import自动导入 API
unplugin-vue-componentsVue 组件自动导入

常见误区

  • manualChunks 分包前没有分析实际包大小,導致过度分包反而增加请求数
  • 插件顺序错误导致冲突,注意 vite-only 插件和 rollup 插件的阶段区分
  • 构建分析没有包含 gzip 压缩大小,导致错误估算实际加载大小