renderPage()

Environment: server.

The renderPage() function enables you to embed Vike into any server.

You only need renderPage() if you use SSR, see Optional.

From the perspective of a server, Vike is just a middleware:

// renderPage() doesn't depend on Node.js and can be used within any JavaScript environment:
// Node.js, AWS, Cloudflare, Vercel, Deno, Bun, Lagon, ...
import { renderPage } from 'vike/server'
 
// Any server: Express.js, Cloudflare Worker, AWS Lambda Function, Fastify, Hono, Nitro, ...
server.addMiddleware({
  method: 'GET',
  route: '*', // catch-all
  async handler(request) {
    const pageContextInit = { urlOriginal: request.url }
    const pageContext = await renderPage(pageContextInit)
    if (!pageContext.httpResponse) return null
    // `body` is the HTML of the page with a route matching pageContextInit.urlOriginal
    const { body, statusCode, headers } = pageContext.httpResponse
    const response = { body, statusCode, headers }
    return response
  }
})

You can embed renderPage() into any server.

Alternatively, instead of using renderPage(), you can pre-render your pages and remove the need for a production server (and deploy to a static host instead).

Examples

Usage

// server/index.js
 
// In this example we use Express.js but we could use any other server framework
import express from 'express'
import { renderPage } from 'vike/server'
 
const isProduction = process.env.NODE_ENV === 'production'
const root = `${__dirname}/..`
 
startServer()
 
async function startServer() {
  // Create an Express.js server
  const app = express()
 
  // Vite integration
  if (!isProduction) {
    // We instantiate Vite's development server and integrate its middleware to our server.
    // ⚠️ We instantiate it only in development. (It isn't needed in production and it
    // would unnecessarily bloat our production server.)
    const vite = await import('vite')
    const viteDevMiddleware = (await vite.createServer({
      root,
      server: { middlewareMode: true }
    })).middlewares
    app.use(viteDevMiddleware)
  } else {
    // In production, we need to serve our static assets ourselves.
    // (In dev, Vite's middleware serves our static assets.)
    app.use(express.static(`${root}/${outDir}/client`))
  }
 
  // ...
  // Other middlewares (e.g. some RPC middleware such as Telefunc)
  // ...
 
  // Vike middleware. It should always be our last middleware (because it's a
  // catch-all middleware superseding any middleware placed after it).
  app.get('*', async (req, res, next) => {
    const pageContextInit = {
      // Required: the URL of the page
      urlOriginal: req.originalUrl
 
      // Optional: the HTTP Headers
      headersOriginal: req.headers,
 
      // Optional: information about the logged-in user (when using an
      // Express.js authentication middleware that defines `req.user`).
      user: req.user
 
      // ... we can provide any additional information about the request here ...
    }
 
    const pageContext = await renderPage(pageContextInit)
    if (pageContext.httpResponse === null) return next()
 
    const { body, statusCode, headers } = pageContext.httpResponse
    headers.forEach(([name, value]) => res.setHeader(name, value))
    res.status(statusCode).send(body)
  })
 
  const port = 3000
  app.listen(port)
  console.log(`Server running at http://localhost:${port}`)
}

The pageContext.httpResponse.body value is the HTML string returned by the onRenderHtml() hook with additional <script> and <style> tags automatically injected by Vike.

For HTML streams use httpResponse.pipe() instead of pageContext.httpResponse.body, see Guides > HTML Streaming.

The pageContext.httpResponse value is null if:

  • An error occurred while rendering the page and no error page is defined.
  • An error occurred while rendering the error page.
  • Vike skips certain URLs, such as /favicon.ico (because browsers automatically make favicon requests).

The renderPage() function doesn't depend on Node.js and you can use renderPage() (and therefore embed Vike) anywhere:

  • Any server environment (Express.js, HatTip, Deno, Fastify, Vite's development server, Node.js's HTTP server, ...)
  • Any deployment provider (AWS, Cloudflare Workers, Vercel, ...)

When modifying your server, you may need to manually restart your server for your changes to take effect. See #562.

See also:

Optional

If you pre-render all your pages then you don't need to use renderPage(), because:

  • Upon development, Vike automatically embeds itself into Vite's development server ($ vite/$ vite dev).
  • Upon pre-rendering ($ vite build/$ vike prerender) Vike renders all your pages.

But, if you use Server-Side Rendering (SSR) and you don't pre-render all your pages, then you need a production server and you need to use renderPage() in order to embed Vike into your server. See Guides > Pre-rendering (SSG).

See also