onBeforeRender()
hook
Environment: server (configurable).
The
onBeforeRender()
hook is for expert Vike users. If you're new to Vike, we recommend using thedata()
hook instead, and/or Vike extensions for automatically integrating data fetching tools (RPC with Telefunc/tRPC, REST with Tanstack Query, GraphQL with Apollo/Relay, etc).
The most notable use case for the onBeforeRender()
hook is deep integration with data fetching tools.
For simple data fetching needs, use the data()
hook instead. As a strategy to decide which one to use, always first try to use data()
and only use onBeforeRender()
as a fallback if data()
doesn't work out.
The onBeforeRender()
hook can be used to orchestrate multiple custom hooks and settings, see:
Another common use case is to use onBeforeRender()
as a global initializing hook. (As a temporary workaround until #962 - New hook onBoot()
is implemented.)
onBeforeRender()
VS data()
The central difference between the two hooks is that the value returned by data()
always sets the value of pageContext.data
, whereas onBeforeRender()
can set multiple pageContext
values.
// /pages/some-page/+data.js
export function data() {
const someValue = /* ... */
// pageContext.data === someValue
return someValue
}
// /pages/some-page/+onBeforeRender.js
export function onBeforeRender() {
const someValue1 = /* ... */
const someValue2 = /* ... */
// pageContext.prop1 === someValue1
// pageContext.prop2 === someValue2
return {
pageContext: {
prop1: someValue1,
prop2: someValue2
}
}
}
Another difference is that the entire pageContext.data
value is always sent to the client-side, whereas with onBeforeRender()
you can (and have to) decide which values are sent to the client-side by using passToClient
.
In a nutshell: while onBeforeRender()
requires more manual work, it also gives you more control.
Environment
Like data()
, the onBeforeRender()
hook always runs on the server-side by default. By using .shared.js
or .client.js
you can tell Vike to run onBeforeRender()
on the client-side instead, see API > data()
hook > Environment.
onBeforeRender()
+ meta
Using onBeforeRender()
together with custom hooks and settings (see meta
) is a powerful technique enabling you to implement your own tailored DX.
For example.
A custom setting +sql.js
(created with meta
):
// /pages/user/+sql.js
export default { modelName: 'User', select: ['firstName', 'lastName'] }
// /pages/product/+sql.js
export default { modelName: 'Product', select: ['name', 'price'] }
A single global onBeforeRender()
hook orchestrating the custom setting:
// /pages/+onBeforeRender.js
import { runQuery } from 'some-sql-engine'
export async function onBeforeRender(pageContext) {
// The value exported by /pages/**/+sql.js is available at pageContext.config.sql
const { sql } = pageContext.config
const data = await runQuery(sql)
// ...
}
See full implementation at API > meta
> Example: sql
.
Override
There can be only one onBeforeRender()
hook per page. For example, if you define a global onBeforeRender()
hook at /pages/+onBeforeRender.js
as well as a page-specific one at /pages/star-wars/+onBeforeRender.js
then the page-specific one overrides the global one. See API > Config Files > Inheritance.
If you want multiple
onBeforeRender()
hooks, then consider:
- Creating custom hooks instead: you can then use one global
onBeforeRender()
hook that orchestrates many custom hooks.- Using
data()
hooks: you can then use one globalonBeforeRender()
while using page-specificdata()
hooks.
You can also suppress globally defined onBeforeRender()
hooks on a per-page basis:
// /pages/+onBeforeRender.js
// Some global onBeforeRender() hook
export default () => {
// ...
}
// /pages/some-page/+config.js
export default {
// Suppress the global onBeforeRender() hook
onBeforeRender: null
}
Advanced example
The following is an advanced example of using onBeforeRender()
with meta
in order to integrate data fetching tools. In particular, this approach can be used for advanced integration with GraphQL tools.
If you use a custom renderer instead of
vike-react
/vike-vue
/vike-solid
, then you can modify youronRenderHtml()
/onRenderClient()
hooks instead of doing the following.
// /pages/+config.js
// Environment: config
export default {
// Pass the GraphQL cache to the client-side
passToClient: ['cache'],
// Modify/create hooks
meta: {
onBeforeRender: {
// Modify the onBeforeRender() hook to run on both the server- and client-side
env: { client: true, server: true }
},
// Create new hook
onBeforeRenderHtml: {
env: { server: true }
},
// Create new hook
onBeforeRenderClient: {
env: { client: true }
}
}
}
See:
// /pages/+onBeforeRender.js
// Environment: server or client
export async function onBeforeRender(pageContext) {
// When run on the server-side
if (pageContext.config.onBeforeRenderHtml) {
const { pageContext } = await onBeforeRenderHtml(pageContext)
return { pageContext }
}
// When run on the client-side
if (pageContext.config.onBeforeRenderClient) {
await onBeforeRenderClient(pageContext)
}
}
// /pages/+onBeforeRenderHtml.jsx
// Environment: server
import { renderToHtml } from 'my-graphql-tool/server'
export async function onBeforeRenderHtml(pageContext) {
const { Page } = pageContext
// `cache` contains the data fetched by GraphQL
const { cache, html } = await renderToHtml(<Page />)
return {
pageContext: {
pageHtml: html,
cache
}
}
}
// /pages/+onBeforeRenderClient.jsx
// Environment: client
import { hydrate } from 'my-ui-framework/client'
import { CacheProvider } from 'my-graphql-tool/client'
export function onBeforeRenderClient(pageContext) {
const { Page, cache } = pageContext
hydrate(
// Re-use the `cache` data that was fetched on the server-side
<CacheProvider cache={cache}>
<Page />
</CacheProvider>,
document.getElementById('root')
)
}
TypeScript
export { onBeforeRender }
import type { OnBeforeRenderAsync } from 'vike/types'
const onBeforeRender: OnBeforeRenderAsync = async (
pageContext
): ReturnType<OnBeforeRenderAsync> => {
// ...
}
Don't omit
ReturnType<OnBeforeRenderAsync>
otherwise TypeScript won't strictly check the return type.
See API >
pageContext
> Typescript for more information on how to extendpageContext
with your own extra properties.