Route Functions give you full programmatic flexibility to define routes.
// /pages/product/edit/+route.jsexport { route }import partRegex from 'part-regex'const route = (pageContext) => { // Route guard (we can also use a guard() hook instead) if (!pageContext.user.isAdmin) { return false } // We can use RegExp / any library we want if (!partRegex`/product/${/[0-9]+/}/edit`.test(pageContext.urlPathname)) { return false } const id = pageContext.urlPathname.split('/')[2] return { // Make `id` available as pageContext.routeParams.id 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, which is usually a better approach.
// /pages/product/index/+route.jsexport { 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.tsexport { 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.jsexport { 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 }}
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
Async Route Functions are forbidden.
// +route.js// ❌ This is forbiddenexport default async () => { /* ... */ }
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 Route Functions are called. This means that a slow Route Function slows down all pages.
Using Route Functions to provide pageContext values is forbidden.
// +route.jsexport 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.jsexport default () => { return { routeParams: { // Any data can be added here } }}
But this 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.