Vite + ant-design-vue 打包体积与开发体验优化实战

Vite + ant-design-vue 打包体积与开发体验优化实战

一份从「生产包 4MB 起步」到「砍掉一半、构建 4 分钟搞定」的完整优化手记。

涉及按需加载、CSS-in-JS 运行时裁剪、路由级 import 链治理、dev 服务器冷启动、构建提速、配置重构。


前言

接手一个使用 Vite 5 + ant-design-vue 3 的中后台前端项目,产物体积和开发体验都存在明显问题。

整个优化过程断断续续做了几天,走了不少弯路,最终沉淀出一套可复用的方法论。

下文按问题 → 排查 → 方案 → 验证的顺序展开,重点说清楚每一步的决策理由和踩过的坑。


目录

  1. 问题全景

  2. 阶段一:生产包全量打包治理

  3. 阶段二:CSS-in-JS 运行时裁剪

  4. 阶段三:dev 模式"打开页面慢"分析

  5. 阶段四:定位真正的慢页面(Edge 实测)

  6. 阶段五:路由级 import 链治理

  7. 阶段六:生产构建提速

  8. 阶段七:配置文件清理与重构

  9. 方法论沉淀

  10. 附录:常用工具脚本


一、问题全景

接手时产物体积与开发体验指标如下:

| 指标 | 数值 | 状态 |

| ---------------------- | -------- | -------------- |

|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.jsplugins数组里再 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=