Route Function
Route Functions provide full programmatic flexibility to define routes.
// /pages/product/edit/+route.js
// This file defines the route of /pages/product/edit/+Page.js
// We use a RegExp, but we could as well use a routing library.
import partRegex from 'part-regex'
const routeRegex = partRegex`/product/${/([0-9]+)/}/edit`
export function route(pageContext) {
if (!pageContext.user.isAdmin) return false
const match = pageContext.urlPathname.match(routeRegex)
if (!match) return false
const [, id] = match
return {
routeParams: { id }
}
}
The parameter
id
is available atpageContext.routeParams.id
.
If you merely want to guard your page, then you can use a Route String with a guard()
hook instead of a Route Function.
You can use any routing tool you want, such as:
- Vike's Route String resolver
resolveRoute()
- partRegex
- path-to-regexp (the router used by Express.js)
- etc.
Precedence
The precedence
number can be used to resolve route conflicts, see API > Routing Precedence.
// /pages/product/edit/+route.js
export { route }
const route = (pageContext) => {
// ...
return {
precedence: 10,
}
}
resolveRoute()
You can use Route Strings inside Route Functions:
// /pages/product/edit/+route.js
export { route }
import { resolveRoute } from 'vike/routing'
const route = (pageContext) => {
if (!pageContext.user.isAdmin) {
return false
}
return resolveRoute('/product/@id/edit', pageContext.urlPathname)
}
// /pages/product/index/+route.js
export { route }
import { resolveRoute } from 'vike/routing'
const route = (pageContext) => {
{
const result = resolveRoute('/product/@id', pageContext.urlPathname)
if (result.match) {
result.routeParams.view = 'overview'
return result
}
}
const result = resolveRoute('/product/@id/@view', pageContext.urlPathname)
if (!['reviews', 'pricing'].includes(result.routeParams.view)) {
return false
}
return result
}
TypeScript
// /pages/product/index/+route.ts
export { route }
import type { RouteSync } from 'vike/types'
import { resolveRoute } from 'vike/routing'
const route: RouteSync = (pageContext): ReturnType<RouteSync> => {
// ..
}
Lightweight & fast
Route Functions should be lightweight and fast.
Vike executes all Route Functions every time the user navigates to a new page. This means that a slow Route Function slows down all pages.
Vike always has to run all Route Functions because it cannot magically predict the outcome of Route Functions. Consider the following example:
// /pages/login/+route.js
export { route }
const route = (pageContext) => {
// Only render the login page to unauthenticated users
if (pageContext.user !== null) return false
return {
// We override all other routes by setting a high `precedence` value of `99`.
// This means that, if the user isn't authenticated, then *all* URLs render the login page.
precedence: 99
}
}
This authentication routing trick is further explained at Integration > Authentication > Login flow.
Vike cannot know whether another Route Function will return a higher precedence number, therefore Vike has to execute all Route Functions.
If you use Client Routing, then all your Route Functions are loaded in the browser. This means that if a Route Function imports a lot of code, then all that code is loaded on the client-side of every page. A heavy Route Function slows down your whole app.
Route Functions should be lightweight and fast.
Async
Asynchronous Route Functions are forbidden.
// +route.js
// ❌ This is forbidden
export default async () => { /* ... */ }
The motivation for having an asynchronous Route Function is usually to redirect/protect a private
page. You can achieve that by using throw render()
/ throw redirect()
with an async guard()
, async data()
, or
async onBeforeRender()
hook.
An asynchronous Route Function would slow down your entire app: as explained in Lightweight & fast, every time the user navigates to a new page all your Route Functions are called. This means that a single slow Route Function slows down all your pages.
Redirection
Cannot provide pageContext
Using Route Functions to provide pageContext
values is forbidden.
// +route.js
export default () => {
return {
// This is forbidden and Vike will throw an error
pageContext: {
some: 'value'
}
}
}
In principle, Vike could support providing pageContext
values but it deliberately doesn't support it in order to foster lightweight Route Functions.
As explained in Lightweight & fast, you should keep Route Functions simple and you shouldn't implement complex logic in
+route.js
files.
That said, you can work around it by misusing pageContext.routeParams
to provide data.
// +route.js
export default () => {
return {
routeParams: {
// Any data can be added here
}
}
}
But it isn't recommended: pageContext.routeParams
is supposed to hold only a minimal amount of information. Instead,
we recommend to implement complex logic in data()
,
onBeforeRender()
, guard()
,
or in a custom hook.