Skip to content

成本应用资源优化记录

📊 优化成果

优化项优化前优化后减少
字体资源75MB (ttf)176KB (woff2)-99.8%
图片资源2.06MB (png)170KB (webp)-91.7%
dist-cost 体积93MB47MB-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 → 7KB

2.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    7KB

3.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 别名)

六、关键经验总结

✅ 有效的优化

  1. 字体压缩: ttf → woff2,99.8% 减少 ⭐⭐⭐⭐⭐
  2. 图片压缩: png → webp,91.7% 减少 ⭐⭐⭐⭐⭐
  3. 产物体积: 93M → 47M,49.5% 减少 ⭐⭐⭐⭐

❌ 无效的优化

  1. Vite 插件过滤: 对 Module Federation 架构效果有限
  2. 精简 API: 容易破坏依赖,得不偿失
  3. 构建速度优化: 2 分钟已是合理值

七、后续计划

  • [ ] 将其他业务模块也进行图片优化
  • [ ] 建立图片优化规范 (新图片上传时自动转 webp)
  • [ ] 清理 public/fonts 中的旧字体文件

八、技术栈

  • 构建工具: Vite 4.4.9
  • 图片处理: Sharp (Node.js)
  • 字体处理: fonttools (Python)
  • 格式: WebP (图片), WOFF2 (字体)
  • 架构: Module Federation

You may not distribute, modify, or sell this software without permission.