Router Setup
12.1.1. createRouter Configuration
- The router instance must be created using
createRouterandcreateWebHistory. - Hash mode (
createWebHashHistory) must not be used. All projects must use History mode. - The router configuration file must be located at
src/router/index.ts.
typescript
// src/router/index.ts
import { createRouter, createWebHistory } from 'vue-router'
import type { RouteRecordRaw } from 'vue-router'
import { routes } from './routes'
const router = createRouter({
history: createWebHistory(import.meta.env.BASE_URL),
routes,
scrollBehavior(_to, _from, savedPosition) {
return savedPosition ?? { top: 0 }
},
})
export default router12.1.2. Route Definition Structure
- The route array must be defined with the
RouteRecordRaw[]type. - Each route must specify the
path,name,component, andmetaproperties. - The
nameproperty is required and is used for programmatic navigation. - The
metaproperty defines authentication requirements, permissions, page titles, and other metadata.
typescript
// src/router/routes.ts
import type { RouteRecordRaw } from 'vue-router'
export const routes: RouteRecordRaw[] = [
{
path: '/',
name: 'Home',
component: () => import('@/views/HomeView.vue'),
meta: { title: 'Home', requiresAuth: false },
},
{
path: '/users',
name: 'UserList',
component: () => import('@/views/user/UserListView.vue'),
meta: { title: 'User List', requiresAuth: true, roles: ['admin'] },
},
{
path: '/users/:id',
name: 'UserDetail',
component: () => import('@/views/user/UserDetailView.vue'),
meta: { title: 'User Detail', requiresAuth: true },
},
]- The
metatype must be defined viavue-routermodule augmentation.
typescript
// src/router/types.ts
import 'vue-router'
declare module 'vue-router' {
interface RouteMeta {
title: string
requiresAuth: boolean
roles?: string[]
}
}12.1.3. Nested Routes
- Pages that share a layout must be organized as nested routes (
children). - The parent route's component must include a
<RouterView />. - The parent route must either omit the
nameproperty or define aredirectto prevent direct access.
typescript
// src/router/routes.ts (nested route example)
{
path: '/settings',
component: () => import('@/layouts/SettingsLayout.vue'),
redirect: { name: 'SettingsProfile' },
children: [
{
path: 'profile',
name: 'SettingsProfile',
component: () => import('@/views/settings/ProfileView.vue'),
meta: { title: 'Profile Settings', requiresAuth: true },
},
{
path: 'security',
name: 'SettingsSecurity',
component: () => import('@/views/settings/SecurityView.vue'),
meta: { title: 'Security Settings', requiresAuth: true },
},
],
}vue
<!-- src/layouts/SettingsLayout.vue -->
<template>
<div class="settings-layout">
<SettingsSidebar />
<main>
<RouterView />
</main>
</div>
</template>12.1.4. Router Registration
- The router must be registered by calling
app.use(router)inmain.ts. router.isReady()must be used to mount the app only after the initial navigation is complete.- The router must be registered after Pinia, because guards need access to Stores.
typescript
// src/main.ts
import { createApp } from 'vue'
import { createPinia } from 'pinia'
import App from './App.vue'
import router from './router'
const app = createApp(App)
app.use(createPinia())
app.use(router)
router.isReady().then(() => {
app.mount('#app')
})| Item | Rule |
|---|---|
| Router mode | createWebHistory required |
| Route type | RouteRecordRaw[] must be specified |
name property | Required for all leaf routes |
meta type | Type safety ensured via module augmentation |
| Registration order | Router must be registered after Pinia |
| Mount timing | Mount after router.isReady() resolves |