Vite + ant-design-vue 打包体积与开发体验优化实战
Vite + ant-design-vue 打包体积与开发体验优化实战
一份从「生产包 4MB 起步」到「砍掉一半、构建 4 分钟搞定」的完整优化手记。
涉及按需加载、CSS-in-JS 运行时裁剪、路由级 import 链治理、dev 服务器冷启动、构建提速、配置重构。
前言
接手一个使用 Vite 5 + ant-design-vue 3 的中后台前端项目,产物体积和开发体验都存在明显问题。
整个优化过程断断续续做了几天,走了不少弯路,最终沉淀出一套可复用的方法论。
下文按问题 → 排查 → 方案 → 验证的顺序展开,重点说清楚每一步的决策理由和踩过的坑。
目录
问题全景
阶段一:生产包全量打包治理
阶段二:CSS-in-JS 运行时裁剪
阶段三:dev 模式"打开页面慢"分析
阶段四:定位真正的慢页面(Edge 实测)
阶段五:路由级 import 链治理
阶段六:生产构建提速
阶段七:配置文件清理与重构
方法论沉淀
附录:常用工具脚本
一、问题全景
接手时产物体积与开发体验指标如下:
| 指标 | 数值 | 状态 |
| ---------------------- | -------- | -------------- |
|antd-iconschunk | 1.46 MB | 🐢 巨大 |
|ant-design-vuechunk | 2.66 MB | 🐢 巨大 |
| 生产构建总耗时 | 20m 2s | 🐢 极慢 |
| dev 模式首次打开新业务页 | 10-30s | 🐢 慢到无法忍受 |
| dev 模式切换页面 | 几秒到几十秒不等 | 🐢 不可接受 |
| dev 模式频繁触发"重新加载" | 是 | 🐢 浏览器 HMR 反复刷 |
业务规模不算小(OA管理系统,多个业务模块 + 报表 + 表单 + 富文本),但产物中显然有大量可优化空间。
二、阶段一:生产包全量打包治理
2.1 现象
产物体积分析报告中:
antd-icons-xxx.js 1.46 MB ant-design-vue-xxx.js 2.66 MB项目已经用了 unplugin-vue-components + ant-design-vue resolver 做按需引入,理论上不应该全量打包。
2.2 排查:grep 找不到源头
第一反应是源码里有全量 import,于是全局搜索:
grep-r"from 'ant-design-vue'"srcgrep-r"import \*"src结果:没有任何显式的全量 import。
没有import * from '@ant-design/icons-vue',也没有 barrel 具名导入残留。
2.3 突破口:模块依赖图探针
常规搜索不行,决定写一个 Rollup 插件钩子去看真实构建的模块依赖图。
// debug-tools/probe-antd-imports.cjsconstantdFullEntryRegex=/ant-design-vue\/(lib|dist|es\/index|src\/index)/;constantdIconsRegex=/@ant-design\/icons-vue\/(lib|dist|es\/index|src\/index)/;exportfunctionprobeAntdFullImports(){return{name:'probe-antd-full-imports',moduleParsed(moduleInfo){if(antdFullEntryRegex.test(moduleInfo.id)||antdIconsRegex.test(moduleInfo.id)){console.log('🚨 全量入口:',moduleInfo.id);console.log(' 来自:',...moduleInfo.importedIds);}},};}把这个插件加到vite.config.js的plugins数组里再 build 一遍。
结果一查一个准:
🚨 全量入口: ant-design-vue/lib 来自: src/api/xxx.js 来自: src/utils/yyy.js 🚨 全量入口: ant-design-vue/lib/message 来自: src/api/zzz.js根因:有 5 个业务文件从ant-design-vue/lib(CJS 全量入口)或ant-design-vue/lib/xxx(lib 子路径)导入,绕过了按需 resolver。
lib/路径是 ant-design-vue 的CommonJS 全量入口(不是 ESM 的es/),一旦从这里导入,rollup 的 tree-shake 完全失效。
2.4 修复
把所有ant-design-vue/lib/xxx改成ant-design-vue/es/xxx(es 是 ESM 入口,unplugin-vue-components 的 resolver 只认这一套):
// ❌ 改前import{message}from'ant-design-vue/lib';importmessagefrom'ant-design-vue/lib/message';// ✅ 改后import{message}from'ant-design-vue';// 或者importmessagefrom'ant-design-vue/es/message';2.5 验证
再次 build:
| Chunk | 改前 | 改后 |
| ---------------- | ------- | ------- |
|antd-icons| 1.46 MB | 0.10 MB |
|ant-design-vue| 2.66 MB | 1.10 MB |
antd-icons 砍掉 1.36MB,ant-design-vue 砍掉 1.56MB,与预期一致。
三、阶段二:CSS-in-JS 运行时裁剪
3.1 现象
产物里 ant-design-vue 体积仍有 1.1MB,分析ant-design-vue-xxx.js看到:里面除了组件 JS,还塞了每个组件的 CSS-in-JS 运行时。
ant-design-vue v3 用 cssinjs(@ant-design/cssinjs)做样式管理,每个组件运行时都会调用useStyleRegister注入 CSS:
// ant-design-vue/es/button/index.js 简化版importuseStyleRegisterfrom'../_util/cssinjs/useStyleRegister';constuseButtonStyle=()=>{useStyleRegister({...},()=>genStyle());// 运行时生成 CSS};业务侧早就引入了统一的ant-design-vue/dist/reset.css+ 自己抽取的custom-variables.less做主题定制,运行时 cssinjs 是冗余的。
3.2 方案 A:直接关掉 CSS-in-JS 注入
写一个 Vite 插件的load钩子,把每个组件的style/index.js(cssinjs 入口)替换为空 stub:
// build/vite-plugins/strip-antdv-style-js.jsconstSTYLE_INDEX_REGEX=