+passToClient
Most pageContext and globalContext properties are available only on the server-side, but you can use passToClient to make properties available on the client-side.
// /pages/+config.js
// Environment: config
export default {
passToClient: [
// pageContext.someData
'someData',
// pageContext.user.id
'user.id', // nested
// pageContext.user.info.avatar.url
'user.avatar.url' // deeply nested
]
}// /pages/+config.ts
// Environment: config
import type { Config } from 'vike/types'
export default {
passToClient: [
// pageContext.someData
'someData',
// pageContext.user.id
'user.id', // nested
// pageContext.user.info.avatar.url
'user.avatar.url', // deeply nested
]
} satisfies Config// /pages/+onHydrationEnd.js
// Environment: client
export { onHydrationEnd }
async function onHydrationEnd(pageContext) {
// Available here on the client-side thanks to passToClient
console.log(pageContext.someData)
console.log(pageContext.user.id)
console.log(pageContext.user.avatar.url)
// ...
}// /pages/+onHydrationEnd.ts
// Environment: client
import type { PageContextClient } from 'vike/types'
export { onHydrationEnd }
async function onHydrationEnd(pageContext: PageContextClient) {
// Available here on the client-side thanks to passToClient
console.log(pageContext.someData)
console.log(pageContext.user.id)
console.log(pageContext.user.avatar.url)
// ...
}Some values, such as pageContext.data, are already passed to the client-side by default, see Default.
Default
When using Client Routing, the following are also available on the client-side by default:
pageContext.PagepageContext.datapageContext.configpageContext.isHydrationpageContext.isBackwardNavigationpageContext.routeParamspageContext.urlOriginalpageContext.urlPathnamepageContext.urlParsed
When using Server Routing, the following are also available on the client-side by default:
pageContext.PagepageContext.datapageContext.configpageContext.routeParams
Serialization
Serialization is done with @brillout/json-serializer.
User-defined classes are lost during serialization:
class MyClass {
prop = 42
}
// On the server-side:
const obj = new MyClass()
console.log(obj) // MyClass { prop: 42 }
console.log(obj instanceof MyClass) // true
// On the browser-side, after `obj` was (de)serialized:
console.log(obj) // { prop: 42 }
console.log(obj instanceof MyClass) // falseSee GitHub > brillout/json-serializer > #3 Support user-defined classes.
Streaming
A passToClient value can be, or contain, a Promise, a ReadableStream, or an async iterable (e.g. an async generator). Vike sends the pageContext object to the client-side without waiting for these asynchronous values, and then sends them in the same HTTP response.
// /pages/product/@id/+data.js
// Environment: server
export async function data(pageContext) {
const product = await getProduct(pageContext.routeParams.id)
return {
// Sent immediately
product,
// Sent later, once it resolves
reviews: getReviews(product.id),
// Sent as a stream, chunk by chunk
recommendations: getRecommendations(product.id)
}
}
async function getReviews(productId) {
const reviews = await db.reviews(productId)
return reviews
}
async function* getRecommendations(productId) {
for await (const product of db.recommendations(productId)) {
yield product
}
}// /pages/product/@id/+data.ts
// Environment: server
import type { PageContextServer } from 'vike/types'
export type Data = Awaited<ReturnType<typeof data>>
export async function data(pageContext: PageContextServer) {
const product = await getProduct(pageContext.routeParams.id)
return {
// Sent immediately
product,
// Sent later, once it resolves
reviews: getReviews(product.id),
// Sent as a stream, chunk by chunk
recommendations: getRecommendations(product.id),
}
}
async function getReviews(productId: string) {
const reviews = await db.reviews(productId)
return reviews
}
async function* getRecommendations(productId: string) {
for await (const product of db.recommendations(productId)) {
yield product
}
}// /pages/product/@id/+onHydrationEnd.js
// Environment: client
export async function onHydrationEnd(pageContext) {
const { product, reviews, recommendations } = pageContext.data
// Already available
console.log(product)
// A Promise
console.log(await reviews)
// An async iterable
for await (const product of recommendations) {
console.log(product)
}
}// /pages/product/@id/+onHydrationEnd.ts
// Environment: client
import type { PageContextClient } from 'vike/types'
import type { Data } from './+data'
export async function onHydrationEnd(pageContext: PageContextClient<Data>) {
const { product, reviews, recommendations } = pageContext.data
// Already available
console.log(product)
// A Promise
console.log(await reviews)
// An async iterable
for await (const product of recommendations) {
console.log(product)
}
}- The value of a
Promiseand the chunks of aReadableStream/ async iterable can be any serializable value, including further promises, streams and async iterables. AUint8Arraychunk is sent byte for byte. - If a value fails, the error is logged on the server-side, and the value fails on the client-side with a generic error.
- With an HTML string (instead of an HTML stream) and upon pre-rendering, the HTML waits for all values.
- Upon client-side navigation, the values the previous page fetched are cancelled. (The values of the first page, sent with its HTML, keep streaming until they end.)
The HTTP response must be a stream: use
pageContext.httpResponse.pipe()orpageContext.httpResponse.getReadableWebStream()instead ofpageContext.httpResponse.body, see API >renderPage().
Escape .
In the (unlikely) event you need to pass properties that include . in their name:
// /pages/+config.js
// Environment: config
export default {
passToClient: [
// pageContext['some-weird.prop-name']
'some-weird\\.prop-name',
// pageContext['some-weird\\.prop-name']
'some-weird\\\\.prop-name',
// pageContext['some-weird\\\\.prop-name']
'some-weird\\\\\\.prop-name'
]
}// /pages/+config.ts
// Environment: config
import type { Config } from 'vike/types'
export default {
passToClient: [
// pageContext['some-weird.prop-name']
'some-weird\\.prop-name',
// pageContext['some-weird\\.prop-name']
'some-weird\\\\.prop-name',
// pageContext['some-weird\\\\.prop-name']
'some-weird\\\\\\.prop-name'
]
} satisfies Config