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

Vue Router Lazy Loading and Performance Optimization

Our back-office admin app kept growing and the homepage load time kept increasing. Using Vue Router's lazy loading to split the initial bundle made a noticeable difference in speed.

What Is Route Lazy Loading

javascript
// Without lazy loading: all pages bundled into one 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 },
];

// Problem: visiting the homepage also downloads the User and Order code
javascript
// Lazy loading: only download a page's code when that route is accessed
const routes = [
  {
    path: "/",
    component: () => import("./views/Home.vue"),
  },
  {
    path: "/user",
    component: () => import("./views/User.vue"),
  },
  {
    path: "/order",
    component: () => import("./views/Order.vue"),
  },
];

Group Bundling (Magic Comments)

By default, each lazy-loaded route generates a separate chunk. You can use magic comments to bundle related pages together:

javascript
const routes = [
  // User module: bundled into the same chunk
  {
    path: "/user/list",
    component: () =>
      import(/* webpackChunkName: "user" */ "./views/UserList.vue"),
  },
  {
    path: "/user/:id",
    component: () =>
      import(/* webpackChunkName: "user" */ "./views/UserDetail.vue"),
  },

  // Order module
  {
    path: "/order/list",
    component: () =>
      import(/* webpackChunkName: "order" */ "./views/OrderList.vue"),
  },
];

Result:

dist/
├── app.js          ← main bundle
├── chunk-user.js   ← user module
└── chunk-order.js  ← order module

Real-World Results

Actual numbers from our project:

Before: app.js 1.2MB (380KB gzipped)
After:
  app.js: 340KB (110KB gzipped)
  Feature module chunks: 50–150KB each

First-screen load: 4.2s → 1.8s

Route-Level Loading State

Lazy loading introduces a brief loading time. Handle it with a loading component:

javascript
// Create Loading and Error components
const LoadingComponent = {
  template: '<div class="loading">Loading...</div>',
};
const ErrorComponent = {
  template: '<div class="error">Load failed</div>',
};

// Lazy load with loading state
function lazyLoad(componentFn) {
  return () => ({
    component: componentFn(),
    loading: LoadingComponent,
    error: ErrorComponent,
    delay: 200, // show loading only after 200ms (avoids flash on fast networks)
    timeout: 10000, // 10s timeout
  });
}

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

Prefetch

Download code before the user navigates:

javascript
// webpackPrefetch: download during browser idle time (recommended)
() => import(/* webpackPrefetch: true */ './views/UserDetail.vue')

// webpackPreload: download in parallel with the current chunk (for high-probability navigations)
() => import(/* webpackPreload: true */ './views/Dashboard.vue')

In back-office admin apps, prefetching major feature modules after login is a good practice.

Summary

  • Route lazy loading: component: () => import('./Page.vue')
  • Magic comment webpackChunkName: bundle related pages into the same chunk
  • First-screen optimization: only load the JS you currently need; load the rest on demand
  • webpackPrefetch: preload during browser idle time for even better UX

MIT Licensed