跳至主要內容
Skip to content

效能優化:路由懶加載 (Lazy Loading)

如果你的 Vue 專案有 50 個頁面,而使用者只是想看首頁。這時如果瀏覽器把這 50 個頁面的程式碼全部下載下來,那首屏載入速度絕對會慢到令人髮指。

路由懶加載 (Lazy Loading) 就是來解決這個問題的:只有當使用者真的點擊了某個路由,才去下載該頁面的程式碼。


一、 靜態 vs 動態 Import

❌ 靜態導入 (不推薦)

這是最直覺的寫法,但它會把所有組件打包進同一個 JS 檔案 (index.js)。

javascript
import Home from "../views/Home.vue";
import About from "../views/About.vue";
import User from "../views/User.vue";

const routes = [
  { path: "/", component: Home },
  { path: "/about", component: About },
  { path: "/user", component: User },
];

✅ 動態導入 (推薦)

Vue Router 支援使用動態 import() 語法。

javascript
const routes = [
  {
    path: "/",
    name: "Home",
    // 只有訪問首頁時,才加載 Home.vue
    component: () => import("../views/Home.vue"),
  },
  {
    path: "/about",
    name: "About",
    component: () => import("../views/About.vue"),
  },
];

當你這樣寫時,打包工具 (Vite/Webpack) 會自動把 Home.vue 分割成一個獨立的 JS 檔案 (例如 Home.12345.js)。


二、 分包策略 (Chunking)

有時候我們不希望每個頁面都切得太碎 (會導致過多的 HTTP 請求)。我們可能希望把「同一個功能模組」的頁面打包在一起。

例如:UserList, UserDetail, UserEdit 這三個頁面,使用者通常會連續訪問。我們希望載入其中一個時,順便把其他兩個也載入進來 (Preload)。

在 Vite 中 (基於 Rollup)

使用 Rollup 的動態導入註釋

javascript
const UserList = () => import("../views/UserList.vue");
const UserDetail = () => import("../views/UserDetail.vue");

// 目前 Vite (Rollup) 預設會自動根據 import 分析 chunks
// 但如果你想強制分組,可以在 vite.config.js 中配置 manualChunks

在 Webpack 中

使用 Magic Comments

javascript
const UserList = () =>
  import(/* webpackChunkName: "group-user" */ "../views/UserList.vue");
const UserDetail = () =>
  import(/* webpackChunkName: "group-user" */ "../views/UserDetail.vue");
const UserEdit = () =>
  import(/* webpackChunkName: "group-user" */ "../views/UserEdit.vue");

加上這個註釋後,Webpack 會把這三個組件打包成同一個 group-user.js


三、 載入狀態 (Loading State)

當使用者點擊連結,到 JS 下載完成並渲染之間,會有一段空白時間。

雖然 Vue Router 沒有內建 Loading 指示器,但我們可以用 vue-router非同步組件 特性,或者直接在全域守衛處理。

極簡 Loading 條 (NProgress)

這是一個業界標準做法。

javascript
import NProgress from "nprogress";
import "nprogress/nprogress.css";

router.beforeEach((to, from) => {
  // 開始進度條
  NProgress.start();
});

router.afterEach(() => {
  // 結束進度條
  NProgress.done();
});

這樣每次切換路由(下載 JS)時,頂部就會有一條細細的進度條跑過去,給使用者很好的反饋。


總結

  1. 務必使用 () => import(...) 來定義路由組件。
  2. 這會大幅減少首屏加載時間 (LCP)。
  3. 利用分包 (Chunking) 策略來優化相關頁面的載入體驗。

下一章,也是本系列的最後一章,我們將稍微窺探一下 Vue Router 的內部原理,並總結 Composition API 的最佳實踐。

下一章:Composition API 與 Router 內部原理探索