START_LOCATION Variable | Vue Router
START_LOCATION is a special constant that represents the initial route location when the router is first initialized. This value is used internally by Vue Router and can be useful for detecting initial navigation states. 🚦
📋 Variable Definition
typescript
const START_LOCATION: RouteLocationNormalized🎯 Purpose and Usage
The START_LOCATION constant serves as a marker for the router's initial state before any navigation occurs. It's particularly useful for:
- Initialization Detection - Determining if the router is in its starting state
- Navigation Comparison - Comparing current route with the initial state
- Guard Logic - Special handling for the very first navigation
🔍 Technical Details
Internal Representation
START_LOCATION is a normalized route object with specific properties that indicate it's the initial state:
typescript
// Simplified internal structure
const START_LOCATION = {
path: '/',
fullPath: '/',
hash: '',
query: {},
params: {},
name: undefined,
matched: [],
meta: {},
href: '/'
}Key Characteristics
- Path: Always
'/'(root path) - Empty State: All collections (params, query, meta) are empty
- No Matches:
matchedarray is empty since no routes are matched yet - Internal Use: Primarily used internally by Vue Router
💡 Practical Usage Examples
Detecting Initial Navigation
typescript
import { START_LOCATION } from 'vue-router'
import { useRoute } from 'vue-router'
const route = useRoute()
// Check if this is the very first navigation
const isInitialNavigation = computed(() =>
route.fullPath === START_LOCATION.fullPath
)
// Use in component lifecycle
onMounted(() => {
if (route.fullPath === START_LOCATION.fullPath) {
console.log('Component mounted during initial navigation')
// Perform initialization logic
}
})Navigation Guard Special Handling
typescript
import { START_LOCATION } from 'vue-router'
router.beforeEach((to, from) => {
// Special handling for initial navigation
if (from === START_LOCATION) {
console.log('This is the first navigation in the app')
// You might want different behavior for initial navigation
if (to.meta.requiresInitialSetup) {
return '/welcome' // Redirect first-time users
}
}
// Normal guard logic for subsequent navigations
if (to.meta.requiresAuth && !isAuthenticated()) {
return '/login'
}
})Analytics and Tracking
typescript
import { START_LOCATION } from 'vue-router'
router.afterEach((to, from) => {
// Track navigation events
if (from === START_LOCATION) {
// This is the app's first navigation
analytics.track('app_initial_navigation', {
target: to.path,
timestamp: Date.now()
})
} else {
// Normal navigation between pages
analytics.track('page_navigation', {
from: from.path,
to: to.path,
timestamp: Date.now()
})
}
})🔧 Advanced Usage Patterns
Initialization State Management
typescript
class AppInitialization {
private isInitialized = false
setupNavigationTracking(router: Router) {
router.afterEach((to, from) => {
if (from === START_LOCATION && !this.isInitialized) {
this.handleInitialNavigation(to)
this.isInitialized = true
}
})
}
private handleInitialNavigation(initialRoute: RouteLocationNormalized) {
console.log('App initialized with route:', initialRoute.path)
// Perform one-time initialization tasks
this.loadEssentialData()
this.setupServiceWorker()
this.initializeThirdPartyServices()
}
}Route Comparison Utility
typescript
function createRouteComparator(router: Router) {
const initialRoute = START_LOCATION
return {
isInitialRoute(route: RouteLocationNormalized): boolean {
return route.fullPath === initialRoute.fullPath
},
hasRouteChanged(from: RouteLocationNormalized, to: RouteLocationNormalized): boolean {
// Special case: initial navigation always counts as a change
if (from === initialRoute) return true
// Normal route change detection
return from.fullPath !== to.fullPath
},
getNavigationType(from: RouteLocationNormalized, to: RouteLocationNormalized): string {
if (from === initialRoute) return 'initial'
if (from.path === to.path) return 'same-route'
return 'cross-route'
}
}
}Progressive Web App Integration
typescript
class PWAIntegration {
constructor(private router: Router) {
this.setupAppShellNavigation()
}
private setupAppShellNavigation() {
this.router.afterEach((to, from) => {
// Special handling for app shell initialization
if (from === START_LOCATION) {
this.initializeAppShell()
this.prefetchCriticalResources()
}
})
}
private initializeAppShell() {
// Initialize app shell components
// Set up service worker communication
// Prepare offline capabilities
console.log('App shell initialized')
}
private prefetchCriticalResources() {
// Prefetch resources needed for smooth navigation
// based on common user paths
}
}🚨 Important Considerations
Equality Comparison
typescript
import { START_LOCATION } from 'vue-router'
const route = useRoute()
// ✅ Correct - compare with START_LOCATION constant
if (route.fullPath === START_LOCATION.fullPath) {
// Handle initial state
}
// ❌ Incorrect - creating new objects for comparison
if (route.fullPath === '/') {
// This might not detect START_LOCATION correctly in all cases
}
// ✅ Correct - using the provided constant
if (route === START_LOCATION) {
// Direct comparison works because START_LOCATION is a singleton
}Reactivity and Timing
typescript
import { START_LOCATION } from 'vue-router'
import { onMounted, ref } from 'vue'
const route = useRoute()
const isInitialLoad = ref(true)
onMounted(() => {
// By the time onMounted runs, navigation might have already occurred
// START_LOCATION comparison might not work as expected here
// Better approach: use navigation guards or watch route changes
})
// More reliable approach
watch(() => route.fullPath, (newPath, oldPath) => {
if (oldPath === START_LOCATION.fullPath) {
console.log('Initial navigation completed')
isInitialLoad.value = false
}
}, { immediate: true })🔗 Related APIs
- Navigation Guards - Where START_LOCATION comparisons are commonly used
- Router Initialization - The process that creates START_LOCATION
📚 Use Case Scenarios
1. Splash Screen Management
typescript
class SplashScreenManager {
private router: Router
private showSplash = ref(true)
constructor(router: Router) {
this.router = router
this.setupNavigationTracking()
}
private setupNavigationTracking() {
this.router.afterEach((to, from) => {
// Hide splash screen after initial navigation
if (from === START_LOCATION && this.showSplash.value) {
setTimeout(() => {
this.showSplash.value = false
}, 1000) // Keep splash visible for 1 second
}
})
}
get shouldShowSplash() {
return this.showSplash.value
}
}2. Authentication Flow
typescript
function setupAuthNavigation(router: Router) {
router.beforeEach((to, from) => {
// Special handling for initial navigation to protected routes
if (from === START_LOCATION && to.meta.requiresAuth) {
// If app starts on a protected route, redirect to login
// but remember the intended destination
return {
path: '/login',
query: { redirect: to.fullPath }
}
}
// Normal auth check for subsequent navigations
if (to.meta.requiresAuth && !isAuthenticated()) {
return '/login'
}
})
}3. Performance Monitoring
typescript
class PerformanceMonitor {
private initialLoadTime: number | null = null
constructor(router: Router) {
this.setupNavigationMonitoring(router)
}
private setupNavigationMonitoring(router: Router) {
const navigationStart = performance.now()
router.afterEach((to, from) => {
if (from === START_LOCATION) {
const loadTime = performance.now() - navigationStart
this.initialLoadTime = loadTime
console.log(`Initial app load time: ${loadTime}ms`)
this.reportInitialLoadPerformance(loadTime)
}
})
}
}💡 Pro Tip: While
START_LOCATIONis useful for detecting initial states, most application logic should work correctly regardless of whether it's the first navigation or subsequent ones. Use it sparingly for special initialization cases.