📄 前端效能優化
本文記錄實施過的效能優化方案
1. 路由層級優化
問題背景(Situation)
專案特性:
- 📦 27+ 個不同的多租戶版型(多租戶架構)
 - 📄 每個版型有 20-30 個頁面(首頁、大廳、促銷、代理、新聞等)
 - 💾 如果一次載入所有程式碼:首次進入需要下載 10MB+ 的 JS 檔案
 - ⏱️ 使用者等待時間超過 10 秒(尤其在手機網路環境下)
 
優化目標(Task)
- 減少首次載入的 JavaScript 體積(目標:< 1MB)
 - 縮短首屏時間(目標:< 3 秒)
 - 按需載入(使用者只下載需要的內容)
 - 維持開發體驗(不能影響開發效率)
 
解決方案(Action)
我們採用了三層路由 Lazy Loading 的策略,從「版型」→「頁面」→「權限」三個層級進行優化。
第 1 層:動態模板載入
// src/router/routes.ts
export default async function (siteKey?: string) {
  // 根據環境變數動態載入對應的版型路由
  const module = await import(`../../template/${siteKey}/router/routes.ts`);
  return { routes: module.routes };
}
說明:
- 專案有 27 個版型,但用戶只會使用其中 1 個
 - 透過 environment.json 判斷當前是哪個品牌
 - 只載入該品牌的路由配置,其他 26 個版型完全不載入
 
效果:
- 首次載入減少約 85% 的路由配置程式碼
 
第 2 層:頁面 Lazy Loading
// 傳統寫法(X - 不好)
import HomePage from './pages/HomePage.vue';
component: HomePage; // 所有頁面都會被打包進 main.js
// 我們的寫法(✓ - 好)
component: () => import('app/template/okbet_green/pages/HomePage/Home.vue');
- 每個路由使用 箭頭函式 + import() 包裹
 - 只有當用戶真正訪問該頁面時,才會下載對應的 JS chunk
 - Vite 會自動將每個頁面打包成獨立的檔案
 
第 3 層:按需載入策略
// src/router/index.ts
router.beforeEach((to, from, next) => {
  const { needAuth } = to.meta;
  if (needAuth && !store.isLogin) {
    // 未登入用戶不會載入「代理中心」等需要登入的頁面
    return next({ name: 'HomePage' });
  }
  next();
});
✅ 優化成效(Result)
優化前:
首次載入:main.js (12.5 MB)
首屏時間:8-12 秒
包含所有 27 個版型 + 所有頁面
優化後:
首次載入:main.js (850 KB) ↓ 93%
首屏時間:1.5-2.5 秒 ↑ 70%
僅包含核心程式碼 + 當前首頁
具體數據:
- ✅ JavaScript 體積減少:12.5 MB → 850 KB(減少 93%)
 - ✅ 首屏時間縮短:10 秒 → 2 秒(提升 70%)
 - ✅ 後續頁面載入:平均 300-500 KB per page
 - ✅ 使用者體驗評分:從 45 分提升至 92 分(Lighthouse)
 
商業價值:
- 跳出率下降 35%
 - 頁面停留時間增加 50%
 - 轉換率提升 25%
 
面試重點
常見延伸問題:
- 
Q: 為什麼不用 React.lazy() 或 Vue 的異步組件?
A: 我們確實有用 Vue 的異步組件(() => import()),但關鍵是三層架構:- 第 1 層(版型):編譯時決定(Vite 配置)
 - 第 2 層(頁面):運行時 Lazy Loading
 - 第 3 層(權限):導航守衛控制
 
單純的 lazy loading 只做到第 2 層,我們多做了版型層級的分離。
 - 
Q: 如何決定哪些程式碼該放在 main.js?
A: 使用 Vite 的manualChunks配置:build: {
rollupOptions: {
output: {
manualChunks: {
'vendor': ['vue', 'pinia', 'vue-router'],
'ui': ['element-plus'],
}
}
}
}原則:只有「每個頁面都會用到」的才放 vendor chunk。
 - 
Q: Lazy Loading 會不會影響用戶體驗(等待時間)?
A: 有兩個策略應對:- 預載(Prefetch):在閒置時預先載入可能訪問的頁面
 - Loading 狀態:使用 Skeleton Screen 代替白屏
 
實際測試:後續頁面平均載入時間 < 500ms,用戶無感知。
 - 
Q: 如何測量優化效果?
A: 使用多種工具:- Lighthouse:Performance Score(45 → 92)
 - Webpack Bundle Analyzer:視覺化分析 chunk 大小
 - Chrome DevTools:Network waterfall、Coverage
 - Real User Monitoring (RUM):真實用戶數據
 
 - 
Q: 有什麼 Trade-off(權衡)?
A:- ❌ 開發時可能遇到循環依賴問題(需要調整模組結構)
 - ❌ 首次路由切換會有短暫載入時間(用 prefetch 解決)
 - ✅ 但整體利大於弊,尤其對 手機用戶體驗提升明顯
 
 
2. 圖片載入優化
問題背景 (Situation)
想像你在滑手機看網頁,螢幕只能顯示 10 張圖片,但網頁一次載入了 500 張圖片的完整資料,你的手機會卡到爆,流量也瞬間燒掉 50MB。
對應到專案的實際情況:
📊 某頁面首頁統計
├─ 300+ 張縮圖(每張 150-300KB)
├─ 50+ 張促銷 Banner
└─ 如果全部載入:300 × 200KB = 60MB+ 的圖片資料
❌ 實際問題
├─ 首屏只看得到 8-12 張圖片
├─ 使用者可能只滾動到第 30 張就離開了
└─ 剩下 270 張圖片完全白載入(浪費流量 + 拖慢速度)
📉 影響
├─ 首次載入時間:15-20 秒
├─ 流量消耗:60MB+(用戶怨聲載道)
├─ 頁面卡頓:滾動不流暢
└─ 跳出率:42%(極高)
優化目標 (Task)
- 只載入可視範圍內的圖片
 - 預載即將進入視窗的圖片(提前 50px 開始載入)
 - 控制併發數量(避免同時載入過多圖片)
 - 防止快速切換導致的資源浪費
 - 首屏圖片流量 < 3MB