createRouterMatcher Function | Vue Router
createRouterMatcher is a low-level function that creates a route matcher instance for matching URL paths against route configurations. This function is primarily used internally by Vue Router but can be useful for advanced routing scenarios. 🎯
📋 Function Signature
function createRouterMatcher(
routes: RouteRecordRaw[],
globalOptions?: PathParserOptions
): RouterMatcher🎯 Purpose and Usage
The createRouterMatcher function creates a specialized matcher that can efficiently match URL paths against your route configuration. While most applications use the router directly, this function provides access to the underlying matching logic for advanced use cases.
Key Use Cases:
- ✅ Custom Routing Logic - Build custom routing systems
- ✅ Route Analysis - Analyze route matching without navigation
- ✅ Performance Optimization - Pre-compile routes for faster matching
- ✅ Testing - Test route matching in isolation
🔍 Parameters
routes
- Type:
RouteRecordRaw[] - Description: Array of route records to match against
The routes parameter accepts the same route configuration format as the main router.
const routes: RouteRecordRaw[] = [
{ path: '/', component: Home },
{ path: '/user/:id', component: UserProfile },
{ path: '/blog/:year/:month', component: BlogArchive }
]globalOptions (optional)
- Type:
PathParserOptions - Description: Global options for path parsing
Options for customizing how paths are parsed and matched.
const options: PathParserOptions = {
sensitive: false, // Case sensitivity
strict: false, // Trailing slash handling
end: true, // Match full path
start: true // Match from start
}💡 Practical Usage Examples
Basic Route Matcher Setup
import { createRouterMatcher } from 'vue-router'
const routes = [
{ path: '/', name: 'home' },
{ path: '/user/:id', name: 'user' },
{ path: '/product/:category/:id', name: 'product' }
]
const matcher = createRouterMatcher(routes)
// Match paths against routes
const match1 = matcher.resolve('/')
console.log(match1) // { matched: [...], params: {}, path: '/' }
const match2 = matcher.resolve('/user/123')
console.log(match2) // { matched: [...], params: { id: '123' }, path: '/user/123' }Advanced Route Analysis
class RouteAnalyzer {
private matcher: RouterMatcher
constructor(routes: RouteRecordRaw[]) {
this.matcher = createRouterMatcher(routes)
}
// Analyze which routes match a given path
analyzePath(path: string): RouteAnalysis {
const match = this.matcher.resolve(path)
return {
path,
matches: match.matched.length > 0,
matchedRoutes: match.matched.map(record => record.path),
parameters: match.params,
isExactMatch: this.isExactMatch(match, path)
}
}
// Find all routes that could match a pattern
findPotentialMatches(partialPath: string): RouteRecordRaw[] {
const allRoutes = this.getAllRoutes()
return allRoutes.filter(route =>
this.couldMatch(route.path, partialPath)
)
}
private isExactMatch(match: any, path: string): boolean {
return match.matched.some(record =>
record.path === path || this.normalizePath(record.path) === this.normalizePath(path)
)
}
}Custom Routing System
class CustomRouter {
private matcher: RouterMatcher
private currentRoute: RouteLocationNormalized
constructor(routes: RouteRecordRaw[]) {
this.matcher = createRouterMatcher(routes)
this.currentRoute = this.getInitialRoute()
}
// Custom navigation method
async navigateTo(path: string, options?: NavigationOptions): Promise<boolean> {
const match = this.matcher.resolve(path)
if (match.matched.length === 0) {
throw new Error(`No route found for path: ${path}`)
}
// Custom pre-navigation logic
if (options?.preNavigationHook) {
const shouldProceed = await options.preNavigationHook(this.currentRoute, match)
if (!shouldProceed) return false
}
// Update current route
this.currentRoute = this.createRouteLocation(match)
// Trigger navigation events
this.emit('navigation', this.currentRoute)
return true
}
// Get route for path without navigating
getRouteForPath(path: string): RouteLocationNormalized | null {
const match = this.matcher.resolve(path)
return match.matched.length > 0 ? this.createRouteLocation(match) : null
}
}🔧 Advanced Patterns
Route Precompilation for Performance
class OptimizedRouteMatcher {
private compiledMatchers: Map<string, RouterMatcher> = new Map()
precompileRoutes(routes: RouteRecordRaw[], key: string): void {
const matcher = createRouterMatcher(routes, {
sensitive: true,
strict: true
})
this.compiledMatchers.set(key, matcher)
}
matchWithPrecompiled(key: string, path: string): any {
const matcher = this.compiledMatchers.get(key)
if (!matcher) {
throw new Error(`No precompiled matcher found for key: ${key}`)
}
return matcher.resolve(path)
}
// Batch matching for multiple paths
batchMatch(paths: string[], key: string): Map<string, any> {
const results = new Map()
const matcher = this.compiledMatchers.get(key)
if (!matcher) return results
for (const path of paths) {
results.set(path, matcher.resolve(path))
}
return results
}
}Dynamic Route Configuration
class DynamicRouteManager {
private baseMatcher: RouterMatcher
private dynamicRoutes: RouteRecordRaw[] = []
constructor(baseRoutes: RouteRecordRaw[]) {
this.baseMatcher = createRouterMatcher(baseRoutes)
}
// Add routes dynamically
addDynamicRoute(route: RouteRecordRaw): void {
this.dynamicRoutes.push(route)
// Recreate matcher with updated routes
this.baseMatcher = createRouterMatcher([
...this.getBaseRoutes(),
...this.dynamicRoutes
])
}
// Remove dynamic route
removeDynamicRoute(path: string): boolean {
const index = this.dynamicRoutes.findIndex(route => route.path === path)
if (index !== -1) {
this.dynamicRoutes.splice(index, 1)
this.baseMatcher = createRouterMatcher([
...this.getBaseRoutes(),
...this.dynamicRoutes
])
return true
}
return false
}
// Check if path matches any dynamic route
isDynamicRoute(path: string): boolean {
const match = this.baseMatcher.resolve(path)
return this.dynamicRoutes.some(route =>
match.matched.some(matchedRoute => matchedRoute.path === route.path)
)
}
}Route Testing Utilities
class RouteTestingUtils {
static createTestMatcher(routes: RouteRecordRaw[]): RouterMatcher {
return createRouterMatcher(routes, {
sensitive: false,
strict: false
})
}
// Test route parameter extraction
static testRouteParameters(routePath: string, actualPath: string): Record<string, string> {
const matcher = this.createTestMatcher([{ path: routePath }])
const match = matcher.resolve(actualPath)
return match.params
}
// Test route matching with different options
static testMatchingOptions(
routePath: string,
testPath: string,
options: PathParserOptions
): boolean {
const matcher = createRouterMatcher([{ path: routePath }], options)
const match = matcher.resolve(testPath)
return match.matched.length > 0
}
// Generate test cases for route matching
static generateRouteTestCases(routes: RouteRecordRaw[]): TestCase[] {
const matcher = createRouterMatcher(routes)
const testCases: TestCase[] = []
for (const route of routes) {
if (route.path.includes(':')) {
// Generate test paths for parameterized routes
const testPaths = this.generateParameterizedTestPaths(route.path)
testPaths.forEach(testPath => {
const match = matcher.resolve(testPath)
testCases.push({
routePath: route.path,
testPath,
shouldMatch: match.matched.length > 0,
expectedParams: match.params
})
})
} else {
// Test exact path matching
const match = matcher.resolve(route.path)
testCases.push({
routePath: route.path,
testPath: route.path,
shouldMatch: true,
expectedParams: {}
})
}
}
return testCases
}
}🚨 Important Considerations
Performance Implications
// ⚠️ Creating matchers is computationally expensive
// Avoid creating matchers frequently in performance-critical code
// ❌ Don't do this in loops or frequent operations
function badPattern(path: string) {
const matcher = createRouterMatcher(routes) // Expensive!
return matcher.resolve(path)
}
// ✅ Better: Create once, reuse often
class EfficientMatcher {
private matcher: RouterMatcher
constructor(routes: RouteRecordRaw[]) {
this.matcher = createRouterMatcher(routes) // Create once
}
matchPath(path: string) {
return this.matcher.resolve(path) // Reuse
}
}Memory Management
// Matchers can hold references to routes and configurations
// Be mindful of memory usage with large route configurations
class MemoryAwareMatcher {
private matcher: RouterMatcher | null = null
private routes: RouteRecordRaw[] = []
setRoutes(newRoutes: RouteRecordRaw[]): void {
this.routes = newRoutes
// Clear old matcher to free memory
this.matcher = null
}
getMatcher(): RouterMatcher {
if (!this.matcher) {
this.matcher = createRouterMatcher(this.routes)
}
return this.matcher
}
// Clean up when no longer needed
dispose(): void {
this.matcher = null
this.routes = []
}
}🔗 Related APIs
RouteRecordRaw- Route configuration type
📚 Best Practices
Custom Route Resolution
class AdvancedRouteResolver {
private matcher: RouterMatcher
private customResolvers: Map<string, CustomResolver> = new Map()
constructor(routes: RouteRecordRaw[]) {
this.matcher = createRouterMatcher(routes)
}
// Add custom resolver for specific route patterns
addResolver(pattern: string, resolver: CustomResolver): void {
this.customResolvers.set(pattern, resolver)
}
// Enhanced route resolution with custom logic
async resolveWithCustomLogic(path: string, context: ResolutionContext): Promise<EnhancedRouteMatch> {
const basicMatch = this.matcher.resolve(path)
// Apply custom resolvers
for (const [pattern, resolver] of this.customResolvers) {
if (this.matchesPattern(path, pattern)) {
const enhancedData = await resolver.resolve(basicMatch, context)
return { ...basicMatch, ...enhancedData }
}
}
return basicMatch
}
private matchesPattern(path: string, pattern: string): boolean {
const patternMatcher = createRouterMatcher([{ path: pattern }])
return patternMatcher.resolve(path).matched.length > 0
}
}Route Validation and Sanitization
class RouteValidator {
private matcher: RouterMatcher
constructor(routes: RouteRecordRaw[]) {
this.matcher = createRouterMatcher(routes)
}
// Validate route configuration
validateRoutes(): ValidationResult {
const issues: string[] = []
// Check for duplicate paths
const pathCounts = new Map()
this.getAllPaths().forEach(path => {
pathCounts.set(path, (pathCounts.get(path) || 0) + 1)
})
pathCounts.forEach((count, path) => {
if (count > 1) {
issues.push(`Duplicate path found: ${path}`)
}
})
// Check parameter consistency
this.checkParameterConsistency(issues)
return { isValid: issues.length === 0, issues }
}
// Sanitize user-provided paths
sanitizePath(userPath: string): string {
// Remove potentially dangerous characters
let sanitized = userPath.replace(/[<>"']/g, '')
// Ensure proper formatting
if (!sanitized.startsWith('/')) {
sanitized = '/' + sanitized
}
// Test if sanitized path matches any route
const match = this.matcher.resolve(sanitized)
if (match.matched.length === 0) {
// Fallback to home if no match
return '/'
}
return sanitized
}
}💡 Pro Tip: While
createRouterMatcheris powerful for advanced routing scenarios, most applications should use the standard Vue Router API. Reserve this function for cases where you need fine-grained control over route matching or are building custom routing systems.