Routing Precedence

If the route of two pages both match the same URL then we have a routing conflict: Vike has to decide which of the two pages should be rendered for that URL.

Upon Route String conflicts, Vike chooses the first route from most specific to least specific. For example:

  1. /about/team (most specific: it matches only a single URL)
  2. /about/@path (less specific: it also matches /about/company, /about/vision, ...)
  3. /about/* (less specific: it also matches /about/some/nested/path)
  4. /* (least specific: it matches all URLs)

More examples at resolvePrecedence/route-strings.spec.ts.

Upon conflicts between Filesystem Routing, Route Strings and Route Functions, Vike chooses the first route in following order:

  1. Route Function, returned high positive precedence number (e.g. 99)
  2. Route Function, returned low positive precedence number (e.g. 1)
  3. Filesystem Routing
  4. Route String, static (i.e. without @param segment, e.g. /about/company)
  5. Route Function, returned no precedence number (or 0)
  6. Route String, parameterized (i.e. with @param segment, e.g. /product/@productId or /product/*)
  7. Route Function, returned low negative precedence number (e.g. -1)
  8. Route Function, returned high negative precedence number (e.g. -99)

Example (4) + (6) + (7):

// product/list/+route.js
export default '/product'
// product/item/+route.js
export default '/product/@productId'
// product/catch-all/+route.js
export default pageContext => {
  if (!pageContext.urlPathname.startsWith('/product/')) return false
  return {
    precedence: -1,
    pageContext: {
      // E.g. redirect `/product/wrong/url` to `/product`
      redirectTo: '/product'
    }
  }
}
URL                           MATCHES                                WINNER
==================            ===============================        ======
/product/42                   product/item/+route.js      (6)        ⬅️
                              product/catch-all/+route.js (7)
URL                           MATCHES                                WINNER
==================            ===============================        ======
/product                      product/list/+route.js      (4)        ⬅️
                              product/catch-all/+route.js (7)
URL                           MATCHES                                WINNER
==================            ===============================        ======
/product/wrong/url            product/catch-all/+route.js (7)        ⬅️

4: Route String, static (without @param segment, e.g. /about/company)
6: Route String, parameterized (with @param segments, e.g. /product/@productId or /product/*)
7: Route Function, returned low negative precedence number (e.g. -1)

Example (1) + (4):

// admin/+route.js
export default '/admin'
// login/+route.js
 
export default pageContext => {
  if( pageContext.user === null ) {
    return {
      precedence: 99
    }
  }
  return false
}
URL                   pageContext.user       MATCHES                   WINNER
======                ================       ===================       ======
/admin                null                   login/+route.js (1)       ⬅️
                                             admin/+route.js (4)
URL                   pageContext.user       MATCHES                   WINNER
======                ================       ===================       ======
/admin                'brillout'             admin/+route.js (4)       ⬅️

1: Route Function, returned high positive precedence number
4: Route String, static (without @param segment, e.g. /about/company)

More examples at resolvePrecedence/overall.spec.ts.