Routing in Vue applications means mapping a URL pattern to the component that renders at that path, so /about renders <About />. With Vue Router you can do this statically or lazily, and the lazy version is worth doing carefully — the details of how you import each route decide how the bundle gets split. A repository covering everything below is available on GitHub.
The static baseline
A conventional route table looks like this:
import Vue from 'vue'
import VueRouter from 'vue-router'
import Home from '../views/Home.vue'
import About from '../views/About.vue'
import Login from '../views/Login.vue'
Vue.use(VueRouter)
const routes = [
{ path: '/', name: 'Home', component: Home },
{ path: '/about', name: 'About', component: About },
{ path: '/login', name: 'Login', component: Login }
]
const router = new VueRouter({
routes
})
export default router
This maps <Home /> to /, <About /> to /about, and <Login /> to /login. It works, but there is no code splitting: all three components land in the same bundle instead of being fetched on demand.

Dynamic imports and chunk names
Replacing the component references with dynamic imports gives you splitting, and a webpack magic comment lets you name the resulting chunk:
const routes = [
{
path: '/',
name: 'Home',
component: () => import(/* webpackChunkName: "Home" */ '../views/Home.vue')
},
{
path: '/about',
name: 'About',
component: () => import(/* webpackChunkName: "About" */ '../views/About.vue')
},
{
path: '/login',
name: 'Login',
component: () => import(/* webpackChunkName: "Login" */ '../views/Login.vue')
}
]
There is nothing wrong with this beyond verbosity and repetition, so the next move is to abstract it away — put the routes in an array and .map over it:
const routeOptions = [
{ path: '/', name: 'Home' },
{ path: '/about', name: 'About' },
{ path: '/login', name: 'Login' }
]
const routes = routeOptions.map(route => {
return {
...route,
component: () => import(`@/views/${route.name}.vue`)
}
})
const router = new VueRouter({
routes
})
The component key is now written once, with the route name passed as the argument to the import call. The trade-off is the chunk name.
Getting named chunks back
JavaScript has no way to produce dynamic comments, so any approach without a build step has to give up the webpackChunkName comment in exchange for writing less code. That is the point where preference decides.
It can also be fixed. Since webpack 2.6.0 the placeholders [index] and [request] are supported, which means the generated chunk name can be derived rather than hardcoded:
// ...
const routeOptions = [
{ path: '/', name: 'Home' },
{ path: '/about', name: 'About' },
{ path: '/login', name: 'Login' }
]
const routes = routeOptions.map(route => {
return {
...route,
component: () => import(/* webpackChunkName: "[request]" */ `../views/${route.name}.vue`)
}
})
const router = new VueRouter({
routes
})
This keeps dynamically loaded routes with named chunks, and it works in both Vue 2 and Vue 3. Running npm run build shows the output:

Grouping routes into shared chunks
Chunks can also hold more than one route. Split the routes into groups — critical components together, the rest in a second, less important group — by replacing the [request] placeholder with a fixed chunk name:
const routes = [
{
path: "/",
name: "Home",
component: () =>
import(/* webpackChunkName: "VeryImportantThings" */ "../views/Home.vue")
},
{
path: "/about",
name: "About",
component: () =>
import(/* webpackChunkName: "VeryImportantThings" */ "../views/About.vue")
},
{
path: "/login",
name: "Login",
component: () =>
import(/* webpackChunkName: "NotSoImportant" */ "../views/Login.vue")
},
{
path: "/contact",
name: "Contact",
component: () =>
import(/* webpackChunkName: "NotSoImportant" */ "../views/Contact.vue")
}
];
The four components now end up in two separate chunks.

That covers lazy loading routes in Vue with dynamic imports, along with options for naming and grouping the chunks webpack emits at build time.



