Skip to content
⚠️ This article was written in 2018. Some content may be outdated.

Vue Router 的懶加載和性能優化

後台管理系統越來越大,首頁加載時間越來越長。用 Vue Router 的懶加載把初始 bundle 拆開,明顯感受到了加速。

什麼是路由懶加載

javascript
// 不用懶加載:所有頁面打進一個 bundle
import Home from "./views/Home.vue";
import User from "./views/User.vue";
import Order from "./views/Order.vue";

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

// 問題:用户進首頁,也要下載 User 和 Order 的代碼
javascript
// 懶加載:只有訪問對應路由時才下載該頁面的代碼
const routes = [
  {
    path: "/",
    component: () => import("./views/Home.vue"),
  },
  {
    path: "/user",
    component: () => import("./views/User.vue"),
  },
  {
    path: "/order",
    component: () => import("./views/Order.vue"),
  },
];

分組打包(魔法註釋)

默認情況下每個懶加載路由會生成一個單獨的 chunk。可以用魔法註釋把相關頁面打進同一個 chunk:

javascript
const routes = [
  // 用户模塊:打進同一個 chunk
  {
    path: "/user/list",
    component: () =>
      import(/* webpackChunkName: "user" */ "./views/UserList.vue"),
  },
  {
    path: "/user/:id",
    component: () =>
      import(/* webpackChunkName: "user" */ "./views/UserDetail.vue"),
  },

  // 訂單模塊
  {
    path: "/order/list",
    component: () =>
      import(/* webpackChunkName: "order" */ "./views/OrderList.vue"),
  },
];

結果:

dist/
├── app.js          ← 主 bundle
├── chunk-user.js   ← 用户模塊
└── chunk-order.js  ← 訂單模塊

效果

我們項目的實際數據:

優化前:app.js 1.2MB(gzip 後 380KB)
優化後:
  app.js:340KB(gzip 110KB)
  各功能模塊 chunk:50-150KB 不等

首屏加載從 4.2s → 1.8s

路由級別的 loading 狀態

懶加載會有短暫的加載時間,可以用路由的 loading 組件處理:

javascript
// 創建 Loading 和 Error 組件
const LoadingComponent = {
  template: '<div class="loading">加載中...</div>',
};
const ErrorComponent = {
  template: '<div class="error">加載失敗</div>',
};

// 帶加載狀態的懶加載
function lazyLoad(componentFn) {
  return () => ({
    component: componentFn(),
    loading: LoadingComponent,
    error: ErrorComponent,
    delay: 200, // 200ms 後才顯示 loading(避免快速網絡下閃爍)
    timeout: 10000, // 10s 超時
  });
}

const routes = [
  {
    path: "/dashboard",
    component: lazyLoad(() => import("./views/Dashboard.vue")),
  },
];

預加載(Prefetch)

用户還沒跳轉,但提前下載代碼:

javascript
// webpackPrefetch:瀏覽器空閒時預下載(推薦)
() => import(/* webpackPrefetch: true */ './views/UserDetail.vue')

// webpackPreload:和當前 chunk 並行下載(適合高概率跳轉)
() => import(/* webpackPreload: true */ './views/Dashboard.vue')

在後台管理系統裏,登錄後預加載主要功能模塊是個好實踐。

小結

  • 路由懶加載:component: () => import('./Page.vue')
  • 魔法註釋 webpackChunkName:把相關頁面打進同一個 chunk
  • 首屏加載優化:只加載當前需要的 JS,其他按需加載
  • webpackPrefetch:瀏覽器空閒時預加載,進一步改善體驗

MIT Licensed