成本应用资源优化记录
📊 优化成果
| 优化项 | 优化前 | 优化后 | 减少 |
|---|---|---|---|
| 字体资源 | 75MB (ttf) | 176KB (woff2) | -99.8% ✅ |
| 图片资源 | 2.06MB (png) | 170KB (webp) | -91.7% ✅ |
| dist-cost 体积 | 93MB | 47MB | -49.5% ✅ |
关键收获:
- ✅ 资源体积大幅减少,加载更快
- ✅ 保持原有构建时间(约 2 分钟)
- ✅ 零业务代码改动
- ✅ Module Federation 架构完全兼容
一、字体优化 (99.8% 减少)
1.1 问题分析
bash
# 原始字体文件
public/fonts/
├── jiancheng500.ttf 38MB
├── jiancheng700.ttf 27MB
└── youshebiaotihei.ttf 10MB
# 总计: 75MB (每次都要加载)
# 问题:
# 1. ttf 格式未压缩
# 2. 包含完整字符集 (几万个汉字)
# 3. 成本应用实际只用了几百个字1.2 解决方案
工具选择: fonttools (Python)
bash
# 1. 安装工具
pip install fonttools brotli
# 2. 转换为 woff2 格式 (自动压缩)
pyftsubset jiancheng500.ttf \
--output-file=jiancheng500.woff2 \
--flavor=woff2 \
--unicodes=U+4E00-9FA5 # 常用汉字范围
# 结果:
# jiancheng500.ttf 38MB → 62KB (-99.8%)
# jiancheng700.ttf 27MB → 56KB (-99.8%)
# youshebiaotihei.ttf 10MB → 58KB (-99.4%)1.3 代码修改
禁用主应用的大字体:
scss
// src/assets/font/font.scss
@font-face {
font-family: "PingFang SC";
// src: url('/fonts/PingFang-Heavy.ttf'); // ❌ 18MB 禁用!
}成本应用使用压缩字体:
css
/* src/apps/cost/public/fonts/fonts.css */
@font-face {
font-family: "jiancheng";
src: url("./jiancheng500.woff2") format("woff2");
font-weight: 500;
font-display: swap; /* 字体加载时显示备用字体 */
}
@font-face {
font-family: "jiancheng";
src: url("./jiancheng700.woff2") format("woff2");
font-weight: 700;
font-display: swap;
}在 index.html 中引入:
html
<!-- src/apps/cost/index.html -->
<link rel="stylesheet" href="/fonts/fonts.css" />二、图片优化 (91.7% 减少)
2.1 问题分析
bash
# 优化前
src/apps/cost/assets/images/
├── bg.png 1.23MB # 背景图
├── circle.png 421KB # 圆形图表
├── indicator.png 386KB # 指示器
└── null-data.png 42KB # 空数据图
# 总计: 2.06MB
# 问题:
# PNG 格式未压缩,且在高分屏下清晰度过剩2.2 解决方案
工具: Sharp (Node.js)
javascript
// scripts/optimize-images-sharp.js
const sharp = require("sharp");
async function optimizeImage(input, output) {
await sharp(input)
.webp({
quality: 90, // 保证 90% 清晰度
effort: 6, // 压缩级别
})
.toFile(output);
}
// 批量转换
optimizeImage("bg.png", "bg.webp"); // 1.23MB → 116KB
optimizeImage("circle.png", "circle.webp"); // 421KB → 24KB
optimizeImage("indicator.png", "indicator.webp"); // 386KB → 7KB2.3 Vue 组件更新
方案 1: CSS image-set (推荐用于背景图)
vue
<!-- src/apps/cost/views/costHeat/board/index.vue -->
<template>
<div class="board-container"></div>
</template>
<style scoped>
.board-container {
background-image: image-set(
url("@cost/assets/images/bg.webp") type("image/webp"),
url("@cost/assets/images/bg.png") type("image/png")
);
/* WebP 优先,不支持时回退到 PNG */
}
</style>方案 2: HTML picture 标签 (推荐用于 img)
vue
<!-- src/apps/cost/views/costHeat/board/components/pieChart.vue -->
<template>
<picture>
<source srcset="@cost/assets/images/circle.webp" type="image/webp" />
<img src="@cost/assets/images/circle.png" alt="圆形图表" />
</picture>
</template>2.4 Vite 别名配置
typescript
// vite.config.cost.ts
export default defineConfig({
resolve: {
alias: {
"@": path.resolve(__dirname, "src"),
"@cost": path.resolve(__dirname, "src/apps/cost"), // ✅ 新增
},
},
});三、优化效果验证
3.1 构建验证
bash
# 清理旧产物
rm -rf dist-cost
# 重新构建
pnpm run build:cost
# 检查产物体积
du -sh dist-cost/
# 结果: 47M (原 93M)
# 检查字体文件
ls -lh dist-cost/fonts/
# jiancheng500.woff2 62KB
# jiancheng700.woff2 56KB
# youshebiaotihei.woff2 58KB
# 检查图片文件
find dist-cost/assets -name "*.webp"
# bg-xxx.webp 116KB
# circle-xxx.webp 24KB
# indicator-xxx.webp 7KB3.2 运行时验证
bash
# 启动开发服务器
pnpm run dev:cost
# 浏览器打开 http://localhost:5011
# 1. 打开 DevTools → Network
# 2. 刷新页面
# 3. 检查:
# ✅ 字体文件显示 woff2 (62KB, 56KB, 58KB)
# ✅ 图片文件显示 webp (116KB, 24KB, 7KB)
# ✅ 页面正常显示,字体清晰四、为什么构建速度没变化?
4.1 构建时间分析
bash
# 构建耗时分布
pnpm run build:cost
# Transform: 1分40秒 (84%) ← 处理 4500+ 模块
# Bundle: 15秒 (11%) ← Rollup 打包
# Copy: 3秒 → 0.1秒 (2%) ← 复制资源 ✅ 唯一优化的部分
# 总计: 2分07秒
# 结论: 字体/图片优化只影响 Copy 阶段 (从 3秒→0.1秒)
# 对总构建时间影响很小 (<2%)4.2 真正的耗时在哪?
bash
# Transform 阶段处理的模块:
# 1. 成本应用代码: 171 个文件
# 2. 主应用共享代码: 2392 个文件 (因为用了 @/ 别名)
# 3. node_modules: 2124 个模块
# 总计: 4687 个模块需要转换
# 为什么这么多?
# 因为成本应用是 Module Federation 架构:
# - 必须能访问主应用的 @/api、@/components、@/store 等
# - 这些模块无法排除,是架构设计决定的4.3 尝试过的优化方案
方案 1: Vite 插件过滤 (失败)
typescript
// ❌ 尝试排除 CRM/HR/Finance 等模块
excludePatterns: [
"src/views/crm",
"src/views/hr",
// ...
];
// 结果:
// - 这些模块本来就没被引用
// - Vite 的 tree-shaking 已经自动排除
// - 模块数几乎没减少 (4684 → 4546)方案 2: 精简 API 目录 (有副作用)
typescript
// ❌ 尝试排除 tmsBase/ismBase 等 API
excludePatterns: ["src/api/tmsBase", "src/api/ismBase"];
// 结果:
// - 构建失败! layout 依赖 setHasReadApi
// - 成本应用依赖 initDict (crmBase)
// - 回滚最终结论: 2 分钟构建时间对于 4500+ 模块来说已经很快了,继续优化需要架构级改造(不值得)。
五、实施清单
✅ 已完成
- [x] 字体文件转换为 woff2
- [x] 图片文件转换为 webp
- [x] 更新 Vue 组件图片引用
- [x] 配置 @cost 别名
- [x] 禁用主应用大字体
- [x] 验证构建产物
- [x] 验证运行效果
📂 修改的文件
src/apps/cost/
├── public/fonts/
│ ├── jiancheng500.woff2 (新增)
│ ├── jiancheng700.woff2 (新增)
│ ├── youshebiaotihei.woff2 (新增)
│ └── fonts.css (新增)
├── assets/images/
│ ├── bg.webp (新增)
│ ├── circle.webp (新增)
│ ├── indicator.webp (新增)
│ └── null-data.webp (新增)
└── views/
└── costHeat/
├── board/index.vue (修改 CSS)
└── board/components/
├── pieChart.vue (修改图片引用)
└── modalHeat.vue (修改图片引用)
src/assets/font/
└── font.scss (禁用 PingFang 字体)
vite.config.cost.ts (新增 @cost 别名)六、关键经验总结
✅ 有效的优化
- 字体压缩: ttf → woff2,99.8% 减少 ⭐⭐⭐⭐⭐
- 图片压缩: png → webp,91.7% 减少 ⭐⭐⭐⭐⭐
- 产物体积: 93M → 47M,49.5% 减少 ⭐⭐⭐⭐
❌ 无效的优化
- Vite 插件过滤: 对 Module Federation 架构效果有限
- 精简 API: 容易破坏依赖,得不偿失
- 构建速度优化: 2 分钟已是合理值
七、后续计划
- [ ] 将其他业务模块也进行图片优化
- [ ] 建立图片优化规范 (新图片上传时自动转 webp)
- [ ] 清理 public/fonts 中的旧字体文件
八、技术栈
- 构建工具: Vite 4.4.9
- 图片处理: Sharp (Node.js)
- 字体处理: fonttools (Python)
- 格式: WebP (图片), WOFF2 (字体)
- 架构: Module Federation
