CtrlK
BlogDocsLog inGet started
Tessl Logo

tessl/npm-vue-router

Official router for Vue.js 2 providing declarative routing, navigation guards, and nested route configuration.

Pending
Overview
Eval results
Files

navigation-guards.mddocs/

Navigation Guards

Comprehensive guard system for controlling route transitions with global, per-route, and component-level hooks. Guards provide fine-grained control over navigation flow with support for authentication, authorization, and custom logic.

Capabilities

Global Guards

Router-wide navigation guards that apply to all route transitions.

/**
 * Global before guard - runs before every route transition
 * @param guard - Navigation guard function
 * @returns Function to remove the guard
 */
beforeEach(guard: NavigationGuard): () => void;

/**
 * Global before resolve guard - runs after all component guards and async components are resolved
 * @param guard - Navigation guard function  
 * @returns Function to remove the guard
 */
beforeResolve(guard: NavigationGuard): () => void;

/**
 * Global after hook - runs after every route transition (cannot affect navigation)
 * @param hook - After navigation hook function
 * @returns Function to remove the hook
 */
afterEach(hook: (to: Route, from: Route) => any): () => void;

/**
 * Navigation guard function signature
 * @param to - Target route being navigated to
 * @param from - Current route being navigated away from
 * @param next - Function to call to resolve the hook
 */
type NavigationGuard = (to: Route, from: Route, next: NavigationGuardNext) => any;

/**
 * Next function for controlling navigation flow
 * @param to - Optional navigation target or false to abort
 */
type NavigationGuardNext = (to?: RawLocation | false | ((vm: Vue) => any) | void) => void;

Usage Examples:

// Authentication guard
const removeGuard = router.beforeEach((to, from, next) => {
  if (to.meta.requiresAuth && !isAuthenticated()) {
    next('/login');
  } else {
    next();
  }
});

// Authorization guard
router.beforeEach((to, from, next) => {
  if (to.meta.roles && !hasRequiredRole(to.meta.roles)) {
    next('/unauthorized');
  } else {
    next();
  }
});

// Loading state management
router.beforeEach((to, from, next) => {
  showLoadingSpinner();
  next();
});

router.afterEach((to, from) => {
  hideLoadingSpinner();
  
  // Analytics tracking
  trackPageView(to.path);
  
  // Update page title
  document.title = to.meta.title || 'My App';
});

// Remove guard when no longer needed
removeGuard();

Route-Level Guards

Guards defined directly on route configurations.

/**
 * Route-level guard in route configuration
 */
interface RouteConfig {
  beforeEnter?: NavigationGuard;
}

Usage Examples:

const routes = [
  {
    path: '/admin',
    component: AdminPanel,
    beforeEnter: (to, from, next) => {
      if (!hasAdminAccess()) {
        next('/dashboard');
      } else {
        next();
      }
    }
  },
  {
    path: '/user/:id',
    component: UserProfile,
    beforeEnter: async (to, from, next) => {
      try {
        // Validate user exists and is accessible
        await validateUserAccess(to.params.id);
        next();
      } catch (error) {
        next('/not-found');
      }
    }
  }
];

Component Guards

Guards defined within Vue component definitions.

/**
 * Component-level navigation guards (defined in component options)
 */
interface ComponentGuards {
  /** Called when route is about to change but component is reused */
  beforeRouteUpdate?: NavigationGuard;
  /** Called before navigating away from this component */
  beforeRouteLeave?: NavigationGuard;
  /** Called when this route is confirmed (after all guards pass) */
  beforeRouteEnter?: (to: Route, from: Route, next: (callback?: (vm: any) => any) => void) => any;
}

Usage Examples:

// In component definition
export default {
  name: 'UserProfile',
  
  beforeRouteEnter(to, from, next) {
    // Component instance not yet created, so no access to `this`
    getUserData(to.params.id).then(user => {
      next(vm => {
        // Access component instance via callback
        vm.setUser(user);
      });
    });
  },
  
  beforeRouteUpdate(to, from, next) {
    // Component is reused, so `this` is available
    this.loadUser(to.params.id);
    next();
  },
  
  beforeRouteLeave(to, from, next) {
    if (this.hasUnsavedChanges) {
      const confirmed = confirm('You have unsaved changes. Are you sure you want to leave?');
      if (confirmed) {
        next();
      } else {
        next(false); // Cancel navigation
      }
    } else {
      next();
    }
  }
};

Composition API Guards

Guards for use with composition API (Vue 2.7+ or @vue/composition-api).

/**
 * Composition API guard for route updates
 * @param guard - Navigation guard to register
 */
function onBeforeRouteUpdate(guard: NavigationGuard): void;

/**
 * Composition API guard for route leave
 * @param guard - Navigation guard to register  
 */
function onBeforeRouteLeave(guard: NavigationGuard): void;

Usage Examples:

import { onBeforeRouteUpdate, onBeforeRouteLeave } from 'vue-router/composables';

export default {
  setup() {
    const hasUnsavedChanges = ref(false);
    
    onBeforeRouteUpdate((to, from, next) => {
      // Handle route parameter changes
      if (to.params.id !== from.params.id) {
        loadUserData(to.params.id);
      }
      next();
    });
    
    onBeforeRouteLeave((to, from, next) => {
      if (hasUnsavedChanges.value) {
        const confirmed = confirm('Leave without saving?');
        next(confirmed);
      } else {
        next();
      }
    });
    
    return {
      hasUnsavedChanges
    };
  }
};

Navigation Flow Control

Control navigation behavior using the next function.

/**
 * Navigation control options for next() function
 */
type NavigationGuardNext = (
  /** Continue navigation normally */
  to?: void |
  /** Abort current navigation */
  false |
  /** Redirect to different location */
  RawLocation |
  /** Execute callback when navigation confirmed (beforeRouteEnter only) */
  ((vm: Vue) => any)
) => void;

Usage Examples:

router.beforeEach((to, from, next) => {
  // Continue navigation
  next();
  
  // Abort navigation
  next(false);
  
  // Redirect to different route
  next('/login');
  next({ name: 'login', query: { redirect: to.fullPath }});
  
  // Multiple conditions
  if (!isAuthenticated()) {
    next('/login');
  } else if (!hasPermission(to.meta.permission)) {
    next('/unauthorized');  
  } else {
    next();
  }
});

// Callback usage in beforeRouteEnter
beforeRouteEnter(to, from, next) {
  fetchUserData(to.params.id).then(userData => {
    next(vm => {
      vm.userData = userData;
    });
  });
}

Error Handling in Guards

Handle errors and failed navigation attempts.

/**
 * Navigation error types
 */
enum NavigationFailureType {
  aborted = 4,
  cancelled = 8,
  duplicated = 16,
  redirected = 2
}

/**
 * Check if error is a navigation failure
 * @param error - Error to check
 * @param type - Optional specific failure type to check for
 * @returns True if error is navigation failure of specified type
 */
function isNavigationFailure(error: any, type?: NavigationFailureType): boolean;

Usage Examples:

import { isNavigationFailure, NavigationFailureType } from 'vue-router';

// Handle navigation errors
router.push('/some-route').catch(error => {
  if (isNavigationFailure(error, NavigationFailureType.aborted)) {
    console.log('Navigation was aborted');
  } else if (isNavigationFailure(error, NavigationFailureType.duplicated)) {
    console.log('Navigation to same location');
  } else {
    console.error('Navigation error:', error);
  }
});

// Global error handling
router.onError(error => {
  console.error('Router error:', error);
  // Handle errors globally
});

// Guard error handling
router.beforeEach(async (to, from, next) => {
  try {
    await validateRoute(to);
    next();
  } catch (error) {
    console.error('Route validation failed:', error);
    next('/error');
  }
});

Guard Execution Order

Understanding the complete navigation resolution flow.

/**
 * Complete navigation resolution flow:
 * 1. Navigation triggered
 * 2. Call beforeRouteLeave guards in deactivated components  
 * 3. Call global beforeEach guards
 * 4. Call beforeRouteUpdate guards in reused components
 * 5. Call beforeEnter in route configs
 * 6. Resolve async route components
 * 7. Call beforeRouteEnter in activated components
 * 8. Call global beforeResolve guards
 * 9. Navigation confirmed
 * 10. Call global afterEach hooks
 * 11. DOM updates triggered
 * 12. Call callbacks passed to next in beforeRouteEnter guards
 */

Usage Example:

// Complete guard setup demonstrating execution order
export default {
  // Component guard (step 7)
  beforeRouteEnter(to, from, next) {
    console.log('7. beforeRouteEnter');
    next();
  },
  
  // Component guard (step 4) 
  beforeRouteUpdate(to, from, next) {
    console.log('4. beforeRouteUpdate');
    next();
  },
  
  // Component guard (step 2)
  beforeRouteLeave(to, from, next) {
    console.log('2. beforeRouteLeave');
    next();
  }
};

// Route config guard (step 5)
const routes = [{
  path: '/example',
  component: ExampleComponent,
  beforeEnter: (to, from, next) => {
    console.log('5. beforeEnter');
    next();
  }
}];

// Global guards
router.beforeEach((to, from, next) => {
  console.log('3. global beforeEach');
  next();
});

router.beforeResolve((to, from, next) => {
  console.log('8. global beforeResolve');
  next();
});

router.afterEach((to, from) => {
  console.log('10. global afterEach');
});

Types

interface NavigationFailure extends Error {
  from: Route;
  to: Route;
  type: NavigationFailureType.aborted | NavigationFailureType.cancelled | NavigationFailureType.duplicated;
}

type ErrorHandler = (err: Error) => void;

Install with Tessl CLI

npx tessl i tessl/npm-vue-router

docs

components.md

composables.md

index.md

navigation-guards.md

route-configuration.md

router-instance.md

tile.json