最近在基于 yudao-ui-admin-vue3(芋道 Vue3 后台管理框架)的项目里做了一次打包优化。
芋道这个框架本身功能很全,但依赖也重。src 下 2000 多个文件,除了框架自带的 element-plus、vue-i18n,业务侧还加了 echarts、bpmn-js、form-create 表单设计器、富文本编辑器、甘特图、思维导图这些重型库。打包时间一直在 2 分钟以上,这次优化后降到了 1 分 8 秒。
核心就改了四个地方,记录一下。用芋道框架的同学可以直接抄。
先说结论
| 优化项 | 改动 | 效果 |
|---|---|---|
| Terser → esbuild | 去掉 minify: 'terser' | 压缩阶段快 20-100 倍 |
| 构建期 ESLint | build 时不注册 eslint 插件 | 省了约 50 秒 |
| 压缩大小报告 | reportCompressedSize: false | 省掉 gzip 计算 |
| chunk 拆分 | 大库单独拆 chunk | 并行压缩 |
一、最大的一刀:去掉 Terser
这是最核心的优化。
芋道模板的 vite.config.ts 里默认写了 minify: 'terser',带着 drop_console 和 drop_debugger 的 terserOptions。这个配置在项目小的时候没什么感觉,但文件一多就成了瓶颈。
Terser 是纯 JavaScript 实现的压缩工具,Vite 5 默认用的 esbuild 是 Go 写的,速度差了一个量级。
我一开始没注意到这个配置,先去折腾别的了。后来发现压缩阶段占了打包大头,才回头看到这一行。
改法很简单,把 minify: 'terser' 和 terserOptions 整段删掉就行:
// 芋道模板默认配置
build: {
minify: 'terser',
terserOptions: {
compress: {
drop_debugger: env.VITE_DROP_DEBUGGER === 'true',
drop_console: env.VITE_DROP_CONSOLE === 'true'
}
},
}
// 改成这样,不写 minify,走 esbuild 默认
build: {
// 删掉 minify 和 terserOptions
}如果你确实需要 drop_console,可以用 vite-plugin-drop-console 之类的插件在编译阶段处理,不用靠 Terser。
另外最新 Vite 8 已经默认用 Oxc Minifier(Rust 实现),官方说比 Terser 快 30-90 倍,压缩率只差 0.5-2%。后续升级 Vite 版本这个问题会自动解决。
二、构建时禁用 ESLint 插件
芋道模板用了 vite-plugin-eslint,配置了 lintOnStart: false。我一开始以为这个配置能让 build 时跳过 lint。
结果不是。
vite-plugin-eslint 的 linting 发生在 Vite 的 transform 钩子里,也就是每个文件编译时都会跑一次 ESLint。lintOnStart 只控制 dev server 启动时是否 lint,跟 build 时的 transform 完全没关系。
2000 多个文件,每个文件过一遍 ESLint,这个开销非常可观。
正确的做法是 build 时不注册这个插件。我改成了条件注册:
// build/vite/index.ts
export function createVitePlugins(isBuild = false) {
return [
Vue(),
VueJsx(),
// ... 其他插件
// 只在 dev 时注册 ESLint
...(!isBuild ? [EslintPlugin({
cache: false,
include: ['src/**/*.vue', 'src/**/*.ts', 'src/**/*.tsx'],
})] : []),
]
}// vite.config.ts
const isBuild = command === 'build'
plugins: createVitePlugins(isBuild),这样 dev 时正常 lint,build 时完全跳过。lint 这种事应该在 CI 或 commit 阶段做,不应该拖慢打包。
这一个改动单独省了将近 50 秒。
三、关闭压缩大小报告
Vite 默认会在打包完成后计算每个 chunk 的 gzip 大小,输出到控制台。小项目无所谓,但芋道项目 chunk 多、体积大,这个计算本身也要花好几秒。
加一行配置关掉:
build: {
reportCompressedSize: false,
}四、更精细的 chunk 拆分
芋道模板默认只拆了三个 chunk:
manualChunks: {
echarts: ['echarts'],
'form-create': ['@form-create/element-ui'],
'form-designer': ['@form-create/designer'],
}但芋道本身还带了一堆大库:element-plus、bpmn-js、wangeditor 等,业务侧再加 dhtmlx-gantt、markmap、video.js,全被打进 vendor chunk,压缩时单线程卡住。
拆细之后:
manualChunks: {
echarts: ['echarts'],
'form-create': ['@form-create/element-ui'],
'form-designer': ['@form-create/designer'],
'element-plus': ['element-plus', '@element-plus/icons-vue'],
bpmn: ['bpmn-js', 'bpmn-js-properties-panel', 'bpmn-js-token-simulation'],
wangeditor: ['@wangeditor-next/editor', '@wangeditor-next/editor-for-vue'],
gantt: ['dhtmlx-gantt'],
markmap: ['markmap-lib', 'markmap-view', 'markmap-common', 'markmap-toolbar'],
video: ['video.js'],
}多个小 chunk 可以并行压缩,比一个巨型 vendor 效率高很多。同时用户访问时按需加载,不会一次性下载一个巨大的 JS 文件。
具体拆哪些看你项目实际引入了什么,没用到的不用管。核心思路就是:体积大、独立性强的库单独拆出来。
最终效果
改完之后跑一次 pnpm build:local,从 2 分 4 秒降到了 1 分 8 秒。
对于芋道这种 2000 多文件的项目来说,这个时间已经可以接受了。如果后续想继续优化,可以考虑升级到 Vite 6+,用内置的 Oxc 压缩器。
用芋道框架的同学,第一刀先砍 Terser,效果最明显。
评论0
暂时没有评论