Vue 3 Routing with Vue Router 4
Implement navigation guards, lazy loading, and advanced routing patterns in Vue 3.
Overview
Vue Router 4 brings TypeScript support and Composition API integration to Vue's routing system. Understanding its patterns enables building complex navigation flows with route guards, meta fields, and efficient code splitting through lazy loading. Route lazy loading with dynamic imports automatically code-splits route components, reducing initial bundle size. Each route becomes a separate chunk loaded only when navigated to. This is essential for large applications where not all users need all routes immediately. Navigation guards intercept routing decisions at multiple phases: before route changes (beforeEach), after route resolves (afterEach), and when navigating away from routes (beforeRouteLeave). Guards receive to, from, and next parameters enabling complex authorization logic. Async guards should resolve promptly—slow checks should show loading states rather than blocking navigation indefinitely. Route meta fields type-safely attach application-specific data to routes. Authentication requirements, breadcrumb configurations, and page titles can all live in meta. The router's matched array provides access to all meta fields from parent and child routes, enabling hierarchical permission systems. Programmatic navigation with router.push() and router.replace() enables navigation from event handlers and async operations. Understanding the difference between push (adds to history) and replace (replaces current entry) matters for back button behavior. Navigation can be prevented in guards, and router.currentRoute provides access to current route state.
Code Example
<script setup lang="ts">
import { useRouter, useRoute } from 'vue-router';
import { computed, onMounted } from 'vue';
import { useAuthStore } from '@/stores/auth';
const router = useRouter();
const route = useRoute();
const authStore = useAuthStore();
const isAuthenticated = computed(() => !!authStore.token);
const userRole = computed(() => authStore.user?.role);
// Breadcrumbs from route meta
const breadcrumbs = computed(() => {
return route.matched.map(r => ({
title: r.meta.title as string || r.name as string,
to: r.path,
}));
});
async function handleLogout() {
await authStore.logout();
router.push('/login');
}
onMounted(() => {
console.log('Current route:', route.name);
console.log('Route meta:', route.meta);
});
</script>
<template>
<nav class="navigation">
<router-link to="/" class="logo">DevRules</router-link>
<div class="nav-links">
<router-link to="/rules">Rules Directory</router-link>
<router-link to="/frameworks">Frameworks</router-link>
<router-link to="/about">About</router-link>
<template v-if="isAuthenticated">
<router-link to="/dashboard">Dashboard</router-link>
<button @click="handleLogout">Logout</button>
</template>
<template v-else>
<router-link to="/login">Login</router-link>
</template>
</div>
<div v-if="breadcrumbs.length > 1" class="breadcrumbs">
<router-link
v-for="(crumb, index) in breadcrumbs"
:key="crumb.to"
:to="crumb.to"
>
{{ crumb.title }}
<span v-if="index < breadcrumbs.length - 1"> / </span>
</router-link>
</div>
</nav>
</template>More Vue.js Rules
Vue 3 Composition API Patterns
Prefer Composition API with script setup for better TypeScript support and reusable logic patterns.
<script setup lang="ts">
import { ref, computed, onMounted, watch } from 'vue';
import { useAuth } from '@/composables/useAuth';
import { useTodos } f...Vue 3 Pinia State Management
Implement centralized state management with Pinia for Vue 3 applications.
import { defineStore } from 'pinia';
import { ref, computed } from 'vue';
import type { User, Project } from '@/types';
import { userApi } from '@/api...Vue 3 Composables Pattern
Extract and reuse stateful logic with Vue 3 Composables using the Composition API.
import { ref, computed, watch, onMounted, onUnmounted } from 'vue';
import { useLocalStorage } from './useLocalStorage';
import { useFetch } from './u...