Architecture

Vike provides an frontend architecture that is both flexible and robust.

Do-one-thing-do-it-well

Vike's architecture is designed with meticulous care and follows what we call a "do-one-thing-do-it-well architecture": Vike focuses on being an excellent frontend framework while not interfering with the rest of your stack.

With Vike, you can choose:

  • Any UI framework (React/Vue/Solid/...)
  • Any server (Express.js, Deno, HatTip, ...)
  • Any deployment (AWS, Cloudflare Workers, Vercel, ...)

With Vike, your application's architecture is composed of loosely coupled core constituents with a clear separation of concerns.

We believe it's paramount for the web that these core constituents are developed mostly independent of each other. Providing freedom for the user, and fostering a vibrant ecosystem with an innovation-driven competition delivering high-quality tools for the users.

onRenderHtml() & onRenderClient()

The UI framework Vike extension (vike-react/vike-vue/vike-solid) integrate UI frameworks. But, if you want, instead of using vike-react/vike-vue/vike-solid you can use the hooks onRenderHtml() and onRenderClient() for complete control over how pages are rendered.

Not only can you manually integrate with any UI framework you want and however you want, you can also deeply integrate with your favorite data fetching tools. For example, you can integrate with Relay in ways that aren't possible with other frameworks.

// /renderer/+onRenderHtml.js
// Environment: server
 
export { onRenderHtml }
 
import { renderToHtml } from 'some-ui-framework'
import { escapeInject, dangerouslySkipEscape } from 'vike/server'
 
async function onRenderHtml(pageContext) {
  const { Page } = pageContext
  const pageHtml = await renderToHtml(Page)
  return escapeInject`<!DOCTYPE html>
    <html>
      <head>
        <title>My Vike app</title>
      </head>
      <body>
        <div id="root">${dangerouslySkipEscape(pageHtml)}</div>
      </body>
    </html>`
}
// /renderer/+onRenderClient.js
// Environment: browser
 
export { onRenderClient }
 
import { renderToDom } from 'some-ui-framework'
 
async function onRenderClient(pageContext) {
  const { Page } = pageContext
  await renderToDom(Page, document.getElementById('#root'))
}

renderPage()

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).

Vike can easily be embedded into any server architecture and any deployment strategy.