+onRenderHtml() hook
The onRenderHtml() hook defines how pages are rendered to HTML.
The hooks onRenderHtml() and onRenderClient() are essentially the glue code between Vike and your UI framework (React/Vue/Solid/...).
If you use a UI framework Vike extension
vike-react/vike-vue/vike-solid, then you don't need to (and shouldn't) defineonRenderHtml()as it's already defined byvike-react/vike-vue/vike-solid.
// +onRenderHtml.js
// Environment: server
export { onRenderHtml }
import { escapeInject, dangerouslySkipEscape } from 'vike/server'
import { renderToHtml, createElement } from 'some-ui-framework'
async function onRenderHtml(pageContext) {
const { Page, data } = pageContext
const pageHtml = await renderToHtml(createElement(Page, data))
const documentHtml = escapeInject`<!DOCTYPE html>
<html>
<head>
<title>My SSR App</title>
</head>
<body>
<div id="page-root">${dangerouslySkipEscape(pageHtml)}</div>
</body>
</html>`
return {
documentHtml,
pageContext: {
// We can define pageContext values here
}
}
}// +onRenderHtml.ts
// Environment: server
export { onRenderHtml }
import type { PageContextServer } from 'vike/types'
import { escapeInject, dangerouslySkipEscape } from 'vike/server'
import { renderToHtml, createElement } from 'some-ui-framework'
async function onRenderHtml(pageContext: PageContextServer){
const { Page, data } = pageContext
const pageHtml = await renderToHtml(createElement(Page, data))
const documentHtml = escapeInject`<!DOCTYPE html>
<html>
<head>
<title>My SSR App</title>
</head>
<body>
<div id="page-root">${dangerouslySkipEscape(pageHtml)}</div>
</body>
</html>`
return {
documentHtml,
pageContext: {
// We can define pageContext values here
}
}
}Where pageContext.Page is the +Page value of the page that is being rendered.
Non-HTML content
Instead of returning documentHtml, the onRenderHtml() hook can set pageContext.content to render a page that isn't HTML, such as an RSS/Atom feed, a sitemap, a Markdown file, or an image.
// pages/feed/+route.js
export default '/feed.atom'// pages/feed/+route.ts
export default '/feed.atom'// pages/feed/+onRenderHtml.js
// Environment: server
export { onRenderHtml }
function onRenderHtml(pageContext) {
pageContext.content = `<?xml version="1.0" encoding="utf-8"?>
<feed xmlns="http://www.w3.org/2005/Atom">
<title>My blog</title>
</feed>`
}// pages/feed/+onRenderHtml.ts
// Environment: server
export { onRenderHtml }
import type { PageContextServer } from 'vike/types'
function onRenderHtml(pageContext: PageContextServer) {
pageContext.content = `<?xml version="1.0" encoding="utf-8"?>
<feed xmlns="http://www.w3.org/2005/Atom">
<title>My blog</title>
</feed>`
}The value of pageContext.content can be:
- A
string - A
Uint8Array(binary content, such as images) - A
ReadableStream<Uint8Array>(streamed to the client upon SSR)
The Content-Type HTTP response header is deduced from the URL's file extension (e.g. /feed.atom => application/atom+xml;charset=utf-8). You can override it by using API > +headersResponse. For URLs without a known file extension, the default is application/octet-stream.
Upon pre-rendering, the content is written to the file at the page's URL: /feed.atom => dist/client/feed.atom.
Add
rel="external"to links pointing to non-HTML pages (e.g.<a href="/feed.atom" rel="external">), so that the browser fetches them instead of Vike's client-side router. See+clientRouting> Links intercepting.