跳至主要內容
Skip to content

Vue SPA 如何優化首屏載入速度

SPA 的首屏慢,通常不是單一原因。它可能慢在 HTML 回來太晚、JS bundle 太大、主執行緒被阻塞、資料請求太多、圖片太重,或是初次渲染節點太多。

一句話回答:Vue SPA 首屏優化要先量測瓶頸,再從資源體積、分包策略、網路請求、渲染成本、快取策略與渲染模式幾個方向處理;常見手段包含路由懶載入、Tree Shaking、壓縮與 CDN、圖片優化、骨架屏、資料預取、虛擬列表、SSR/SSG。


一、 必考觀念

1. 先定義「首屏」

首屏不是一個單一指標,通常要拆成幾個階段看:

指標意義
TTFB伺服器第一個 byte 回來的時間
FCPFirst Contentful Paint,第一次有內容被畫出來
LCPLargest Contentful Paint,最大內容元素渲染完成
TTITime to Interactive,頁面可互動時間
INPInteraction to Next Paint,互動延遲表現
CLSCumulative Layout Shift,版面位移

面試時不用把所有縮寫背得像考證照,但要能說出:首屏速度包含網路、資源下載、JS 執行、渲染與互動可用性。

2. SPA 首屏為什麼容易慢?

典型 CSR SPA 流程:

如果 HTML 只是空殼:

html
<div id="app"></div>

使用者真正看到內容,必須等:

  1. HTML 回來。
  2. JS bundle 下載。
  3. JS parse/execute。
  4. Router 匹配。
  5. 資料請求完成。
  6. Vue render/patch 完成。

任何一段慢,都會拖累首屏。


二、 分析方向

1. 先量測,不要憑感覺優化

常用工具:

  • Chrome DevTools Performance。
  • Lighthouse。
  • Network 面板。
  • Web Vitals。
  • 打包分析工具,例如 rollup-plugin-visualizer
  • 真實使用者監控 RUM。

要先回答:

  • 是 JS 太大?
  • 是 API 太慢?
  • 是圖片太重?
  • 是 render 太多節點?
  • 是 main thread 被長任務卡住?
  • 是 CDN / cache 沒配置好?

不同瓶頸對應不同解法。

2. 看 Network 瀑布圖

Network 面板可以看:

  • HTML 是否慢。
  • JS/CSS 是否太大。
  • 是否有太多阻塞資源。
  • 圖片是否過大。
  • API 是否串行等待。
  • Cache 是否命中。

如果主 bundle 幾 MB,第一優先通常是分包與減少依賴。

如果 bundle 不大但 API 慢,就要看資料預取、並行請求、快取與 loading 策略。


三、 打包與資源體積優化

1. 路由懶載入

不要把所有頁面都塞進首屏 bundle。

typescript
const routes = [
  {
    path: '/',
    component: () => import('@/views/Home.vue'),
  },
  {
    path: '/admin',
    component: () => import('@/views/Admin.vue'),
  },
]

這樣 /admin 頁面的程式碼不會在首頁首屏就下載。

這和 Vue Router 原理相關,可以延伸讀:Vue 路由實現:Hash 路由與 History 路由原理

2. 組件級懶載入

非首屏的大型組件可以延後載入:

typescript
import { defineAsyncComponent } from 'vue'

const HeavyChart = defineAsyncComponent(() => {
  return import('@/components/HeavyChart.vue')
})

適合:

  • 圖表。
  • 富文本編輯器。
  • 地圖。
  • 大型表格。
  • 很少打開的 Modal。

3. Tree Shaking 與依賴治理

常見問題:

  • 為了一個函數引入整個工具庫。
  • 圖表庫、日期庫、富文本套件進入主包。
  • icon 全量引入。
  • 重複依賴多版本。

優化方向:

typescript
// 避免不必要的全量引入
import _ from 'lodash'

// 優先按需引入
import debounce from 'lodash-es/debounce'

更重要的是用 bundle analyzer 看真實體積,不要猜。

4. 壓縮與傳輸優化

常見手段:

  • 開啟 gzip / brotli。
  • JS/CSS minify。
  • HTTP/2 或 HTTP/3。
  • CDN。
  • 靜態資源長快取。
  • 產物檔名 hash 化。

典型快取策略:

text
index.html: no-cache 或短快取
assets/*.js: max-age=31536000, immutable

原因是 JS/CSS 檔名通常帶 hash,內容變了檔名也變,可以長快取;但 index.html 要能拿到最新資源入口。

5. 圖片與字體優化

圖片常常比 JS 更拖首屏。

優化方向:

  • 使用 WebP / AVIF。
  • 正確尺寸,不要傳超大圖再用 CSS 縮小。
  • 首屏關鍵圖預載。
  • 非首屏圖片 lazy loading。
  • icon 用 SVG sprite 或按需引入。
  • 字體使用 font-display: swap
html
<img
  src="/hero.webp"
  width="1200"
  height="600"
  fetchpriority="high"
  alt=""
/>

四、 資料請求優化

1. 避免瀑布流請求

壞情況:

text
先請求 user
-> user 回來後請求 settings
-> settings 回來後請求 dashboard

如果彼此沒有依賴,應該並行:

typescript
const [user, settings, dashboard] = await Promise.all([
  fetchUser(),
  fetchSettings(),
  fetchDashboard(),
])

2. 首屏資料優先級

不是所有資料都要阻塞首屏。

可以分成:

類型策略
首屏必要資料優先請求,必要時阻塞渲染
首屏可延後資料先渲染骨架或占位,再補資料
非首屏資料滾動到附近再載入
使用者操作後才需要點擊後再載入

3. 資料快取

常見快取層:

  • HTTP cache。
  • CDN cache。
  • API gateway cache。
  • 前端 memory cache。
  • Pinia store cache。
  • IndexedDB / localStorage。

例如列表頁回詳情再返回,不一定要重新請求列表。可以配合 Pinia 或 KeepAlive。

延伸讀:深入 Vue KeepAlive:組件緩存與狀態保留

4. 預取與預載

可以在使用者即將需要時提前載入:

  • hover 某個入口時預取 chunk。
  • 首屏空閒時預取下一頁資料。
  • 對高機率路徑做 prefetch。

但不要無腦 prefetch 所有東西,否則會搶首屏頻寬。


五、 渲染與主執行緒優化

1. 減少首屏 DOM 節點

首屏一次渲染太多節點,會拖慢 JS 執行、Diff、Layout 和 Paint。

優化方式:

  • 分頁。
  • 虛擬列表。
  • 折疊非首屏內容。
  • 大型模組延後 mount。
  • 不重要區塊延後到 idle 時間載入。

如果首屏就渲染一萬列,路由懶載入也救不了渲染成本。

2. 善用 v-ifv-show

不在首屏顯示的大型區塊,可以用 v-if 延後建立。

vue
<HeavyPanel v-if="opened" />

頻繁切換的小型區塊,用 v-show 可能更好。

延伸讀:v-if 與 v-show 的區別

3. 降低響應式成本

大資料量不一定都需要深層響應式。

可考慮:

  • shallowRef
  • markRaw
  • 避免把大型不可變資料整包 reactive。
  • 拆分組件,縮小更新範圍。
  • v-memo 避免不必要列表子樹更新。
vue
<div
  v-for="item in list"
  :key="item.id"
  v-memo="[item.id, item.selected]"
>
  ...
</div>

4. 避免主執行緒長任務

首屏 JS 執行太久會讓頁面無法互動。

優化方向:

  • 拆分重計算。
  • 使用 Web Worker。
  • 延後非必要初始化。
  • 圖表、地圖、編輯器按需載入。
  • 避免同步處理大量資料。

延伸讀:瀏覽器渲染管線與 DOM 操作成本


六、 UI 感知優化

1. 骨架屏

骨架屏不能縮短真實載入時間,但能改善使用者感知。

適合資料請求不可避免的場景:

vue
<template>
  <ProductSkeleton v-if="loading" />
  <ProductDetail v-else :product="product" />
</template>

注意:骨架屏應該接近真實布局,避免資料回來後 CLS 過大。

2. 分階段渲染

先渲染核心內容,再載入次要內容:

text
首屏主內容
-> 推薦區
-> 評論
-> 圖表
-> 非必要互動模組

這比「所有資料都回來才顯示頁面」更友好。

3. Loading 不等於優化

Loading 只能告訴使用者正在等,它不會讓頁面更快。

好的感知優化要配合:

  • 穩定布局。
  • 逐步顯示。
  • 優先顯示有價值內容。
  • 避免白屏。

七、 SSR / SSG / 預渲染

如果 SPA 首屏主要瓶頸是「JS 執行前沒有內容」,可以考慮改渲染模式。

1. SSR

Server 先渲染 HTML,瀏覽器先看到內容,再 hydrate。

適合:

  • SEO 重要。
  • 首屏內容可在 server 取得。
  • 內容頁、商品頁、公開頁。

延伸讀:Vue SSR 的實現原理

2. SSG

建置時產生靜態 HTML。

適合:

  • 文件站。
  • 部落格。
  • 行銷頁。
  • 內容變化不頻繁的頁面。

3. 預渲染

對部分路由預先生成 HTML,其他仍走 SPA。

適合少量公開路由首屏優化,但不想完整導入 SSR 的專案。


八、 追問題庫

Q1:首屏慢第一步做什麼?

先量測。用 Lighthouse、Performance、Network、bundle analyzer 確認瓶頸。

不要一上來就說 SSR。SSR 只能解決部分問題,如果 JS 過大、圖片過重、API 太慢,SSR 也不會自動全部解決。

Q2:路由懶載入一定能提升首屏嗎?

通常能減少首屏 bundle,但不一定改善所有首屏問題。

如果瓶頸是 API 慢、圖片大或首屏 DOM 太多,路由懶載入效果有限。

Q3:CDN 和 gzip/brotli 解決什麼問題?

它們主要解決資源傳輸速度。

但如果 bundle 本身太大,或 JS 執行太久,仍然需要分包、依賴治理與主執行緒優化。

Q4:骨架屏算不算性能優化?

算感知性能優化,不一定降低真實載入時間。

它能減少白屏焦慮,但不能取代資源體積與請求優化。

Q5:首屏一定要 SSR 嗎?

不一定。

後台管理系統、登入後工具、SEO 不重要的應用,通常 CSR + 分包 + 快取就夠。

公開內容頁、SEO 頁、商品頁,SSR/SSG 更值得考慮。


九、 實作題

題目:一個 Vue SPA 首屏 5 秒白屏,你怎麼排查?

可以這樣回答:

  1. 先用 Network 看 HTML、JS、CSS、圖片、API 的耗時與大小。
  2. 用 bundle analyzer 看主包是否過大,是否有大型依賴進入首屏。
  3. 檢查路由是否懶載入,重型組件是否按需載入。
  4. 看 API 是否串行、是否有不必要的首屏阻塞請求。
  5. 用 Performance 看 main thread 是否有 long task。
  6. 檢查首屏是否一次渲染過多 DOM 或列表。
  7. 檢查圖片、字體、CSS 是否阻塞或過大。
  8. 根據瓶頸選擇分包、快取、壓縮、骨架屏、SSR/SSG 等方案。

這個回答比直接背優化清單更像真實工程排查。


十、 資深視角

1. 首屏優化要分層

完整思路:

層級問題
網路層TTFB、CDN、HTTP cache、壓縮
資源層JS/CSS/圖片/字體體積
執行層JS parse/execute、long task
資料層API 串行、快取、預取
渲染層DOM 節點數、layout/paint、Diff 成本
架構層CSR、SSR、SSG、邊緣渲染

2. 不要讓優化破壞產品體驗

例如:

  • 過度拆包可能造成路由切換卡頓。
  • 過度 prefetch 可能搶首屏頻寬。
  • 骨架屏如果布局不準,會造成 CLS。
  • 快取如果策略錯誤,可能顯示舊資料。

性能優化不是越多越好,要看瓶頸與使用者路徑。

3. 面試時要能說出取捨

好答案不是一串名詞,而是:

  • 我先量測。
  • 我判斷瓶頸。
  • 我選對應策略。
  • 我知道副作用。
  • 我會驗證結果。

總結

方向常見手段
分析Lighthouse、Performance、Network、bundle analyzer
分包路由懶載入、組件懶載入、第三方庫按需載入
傳輸gzip/brotli、CDN、HTTP cache、資源 hash
資源圖片壓縮、WebP/AVIF、字體優化、CSS 精簡
資料並行請求、快取、預取、非首屏延後
渲染減少 DOM、虛擬列表、延後重型組件、降低響應式成本
感知骨架屏、分階段渲染、避免白屏
架構SSR、SSG、預渲染

一句完整的面試回答可以是:

Vue SPA 首屏優化要先量測瓶頸,再對症處理。常見方向包括:路由懶載入和組件懶載入減少首屏 JS;Tree Shaking、按需引入、gzip/brotli、CDN 和長快取降低資源傳輸成本;圖片和字體做格式與載入優化;API 請求避免瀑布流並做快取;渲染上減少首屏 DOM、使用虛擬列表、延後重型組件;感知上用骨架屏和分階段渲染避免白屏。如果頁面 SEO 或首屏內容很重要,可以考慮 SSR、SSG 或預渲染,但要權衡伺服器成本與 hydration 複雜度。

延伸閱讀