Router Guards and Advanced

Back

Loading concept...

Vue Router Guards & Advanced Features 🛡️

Imagine your app is a magical castle with many rooms. Router Guards are like loyal guards standing at every door, checking if visitors are allowed to enter, leave, or even which path they take!


The Castle Analogy 🏰

Think of your Vue app as a castle:

  • Routes = Rooms in the castle
  • Guards = Security checkpoints at doors
  • Users = Visitors trying to enter rooms
  • Lazy Loading = Rooms that build themselves only when someone wants to visit
  • History Modes = Different ways to write the castle’s address book
  • Scroll Behavior = Where you land when you enter a room

1. Global Navigation Guards 🌍

Global guards watch every single door in your castle. They’re like the head of security who sees everything!

What Are They?

Global guards run on every route change in your entire app. There are three types:

// 1. beforeEach - BEFORE entering any room
router.beforeEach((to, from, next) => {
  console.log('Checking if you can enter...')
  next() // Let them in!
})

// 2. beforeResolve - After all guards pass
router.beforeResolve((to, from, next) => {
  console.log('Almost there!')
  next()
})

// 3. afterEach - AFTER entering (no next!)
router.afterEach((to, from) => {
  console.log('You made it inside!')
})

Real-World Example: Login Check

router.beforeEach((to, from, next) => {
  const isLoggedIn = localStorage.getItem('token')

  // Does this room need a key?
  if (to.meta.requiresAuth && !isLoggedIn) {
    next('/login') // Go to login instead!
  } else {
    next() // Welcome in!
  }
})

The Guard Parameters Explained

Parameter What It Is
to The room you WANT to enter
from The room you’re LEAVING
next The magic word to proceed

Using next() Correctly

next()           // Go ahead, enter!
next(false)      // STOP! Stay where you are
next('/login')   // Go to login instead
next(new Error('Oops!')) // Something broke!

2. Per-Route Guards 🚪

Per-route guards are like personal bodyguards for specific rooms. They only work for ONE route!

Setting Up Per-Route Guards

const routes = [
  {
    path: '/treasure-room',
    component: TreasureRoom,
    beforeEnter: (to, from, next) => {
      // Only this room has this guard!
      const hasKey = checkForKey()
      if (hasKey) {
        next()
      } else {
        next('/key-shop')
      }
    }
  }
]

Multiple Guards for One Route

// You can have an array of guards!
beforeEnter: [
  checkAge,
  checkMembership,
  checkTicket
]

Each guard runs one after another. If any guard says “no,” the visitor can’t enter!

When to Use Per-Route Guards?

  • Admin pages - Only admins allowed
  • Premium content - Paid users only
  • Age-restricted - Must be 18+

3. In-Component Guards 🧩

These guards live inside your Vue components. They’re like the room itself deciding who can enter or leave!

The Three In-Component Guards

export default {
  // BEFORE entering this component
  beforeRouteEnter(to, from, next) {
    // Can't use 'this' here! Component doesn't exist yet
    next(vm => {
      // NOW you can use vm (the component)
      vm.loadData()
    })
  },

  // When route changes but component stays
  beforeRouteUpdate(to, from, next) {
    // Same component, different route params
    this.userId = to.params.id
    next()
  },

  // BEFORE leaving this component
  beforeRouteLeave(to, from, next) {
    if (this.hasUnsavedChanges) {
      const answer = confirm('Leave without saving?')
      next(answer) // true = leave, false = stay
    } else {
      next()
    }
  }
}

Quick Comparison

graph TD A["User Navigates"] --> B{beforeRouteEnter} B -->|Allowed| C["Component Created"] C --> D{Route Params Change?} D -->|Yes| E["beforeRouteUpdate"] D -->|No| F["User Leaves"] E --> F F --> G{beforeRouteLeave} G -->|Allowed| H["Goodbye!"]

The beforeRouteEnter Trick

Since this doesn’t exist yet, use a callback:

beforeRouteEnter(to, from, next) {
  fetchUserData(to.params.id).then(user => {
    next(vm => {
      vm.user = user // Now we can set data!
    })
  })
}

4. Route Lazy Loading ⚡

Lazy loading is like building a room only when someone wants to visit. Why build ALL rooms if nobody uses them?

The Problem

// BAD: Loads EVERYTHING at once
import Home from './views/Home.vue'
import About from './views/About.vue'
import Contact from './views/Contact.vue'
// ... 50 more imports

// Your app takes forever to start! 😰

The Solution: Dynamic Imports

// GOOD: Load only when needed
const routes = [
  {
    path: '/',
    component: () => import('./views/Home.vue')
  },
  {
    path: '/about',
    component: () => import('./views/About.vue')
  }
]

Named Chunks for Better Organization

// Give chunks meaningful names!
component: () => import(
  /* webpackChunkName: "admin" */
  './views/AdminDashboard.vue'
)

Grouping Related Routes

// All admin pages in one chunk
const AdminUsers = () => import(
  /* webpackChunkName: "admin" */
  './views/admin/Users.vue'
)
const AdminSettings = () => import(
  /* webpackChunkName: "admin" */
  './views/admin/Settings.vue'
)

Visual: Lazy vs Eager Loading

graph LR subgraph Eager Loading A["App Start"] --> B["Load ALL Pages"] B --> C["Slow Start! 🐌"] end subgraph Lazy Loading D["App Start"] --> E["Load Only Home"] E --> F["Fast Start! 🚀"] F -->|Visit About| G["Load About.vue"] end

5. Router History Modes 📜

History modes decide how your URLs look and work!

The Three Modes

Mode URL Example Server Config?
Hash example.com/#/about No
History example.com/about Yes
Memory No URL changes No

Hash Mode (Default)

const router = createRouter({
  history: createWebHashHistory(),
  routes
})
// URLs look like: example.com/#/about

Pros: Works everywhere, no server setup Cons: Ugly URLs with #

History Mode (Clean URLs)

const router = createRouter({
  history: createWebHistory(),
  routes
})
// URLs look like: example.com/about

Pros: Beautiful, SEO-friendly URLs Cons: Needs server configuration

Server Configuration Example (Nginx)

location / {
  try_files $uri $uri/ /index.html;
}

Memory Mode (No URLs)

const router = createRouter({
  history: createMemoryHistory(),
  routes
})
// Great for SSR or testing!

Choosing the Right Mode

graph TD A["Need Clean URLs?"] -->|No| B["Use Hash Mode"] A -->|Yes| C{Can Configure Server?} C -->|Yes| D["Use History Mode"] C -->|No| B

6. Scroll Behavior 📍

Control where the page scrolls when navigating!

Basic Setup

const router = createRouter({
  history: createWebHistory(),
  routes,
  scrollBehavior(to, from, savedPosition) {
    // Return scroll position
  }
})

Common Scroll Patterns

1. Always scroll to top:

scrollBehavior() {
  return { top: 0 }
}

2. Remember position when going back:

scrollBehavior(to, from, savedPosition) {
  if (savedPosition) {
    return savedPosition // Go back to where you were!
  }
  return { top: 0 }
}

3. Scroll to anchor/hash:

scrollBehavior(to) {
  if (to.hash) {
    return {
      el: to.hash, // Scroll to #section-id
      behavior: 'smooth'
    }
  }
}

4. Delayed scroll (wait for content):

scrollBehavior() {
  return new Promise(resolve => {
    setTimeout(() => {
      resolve({ top: 0 })
    }, 500) // Wait 500ms
  })
}

Complete Example

scrollBehavior(to, from, savedPosition) {
  // Back/forward button? Return to saved spot
  if (savedPosition) {
    return savedPosition
  }

  // Has anchor? Scroll smoothly to it
  if (to.hash) {
    return {
      el: to.hash,
      behavior: 'smooth'
    }
  }

  // Default: scroll to top
  return { top: 0, behavior: 'smooth' }
}

The Complete Navigation Flow 🔄

Here’s how all guards work together:

graph TD A["Navigation Triggered"] --> B["beforeEach - Global"] B --> C["beforeEnter - Per-Route"] C --> D["beforeRouteEnter - Component"] D --> E["beforeResolve - Global"] E --> F["Navigation Confirmed"] F --> G["afterEach - Global"] G --> H["DOM Updated"] H --> I["beforeRouteEnter callback"]

Quick Reference Card 📋

Guard Type Where Can Cancel?
beforeEach Router Yes
beforeResolve Router Yes
afterEach Router No
beforeEnter Route Yes
beforeRouteEnter Component Yes
beforeRouteUpdate Component Yes
beforeRouteLeave Component Yes

Summary: Your Castle is Protected! 🏰

You now know how to:

  1. Global Guards - Watch ALL doors in your castle
  2. Per-Route Guards - Protect specific rooms
  3. In-Component Guards - Let rooms control their own security
  4. Lazy Loading - Build rooms only when needed
  5. History Modes - Choose how addresses look
  6. Scroll Behavior - Control where visitors land

Your Vue app is now a well-guarded, efficient, and smooth-navigating castle! Go build something amazing! 🚀


Remember: Good guards make good apps. Happy routing!

Loading story...

Story - Premium Content

Please sign in to view this story and start learning.

Upgrade to Premium to unlock full access to all stories.

Stay Tuned!

Story is coming soon.

Story Preview

Story - Premium Content

Please sign in to view this concept and start learning.

Upgrade to Premium to unlock full access to all content.