Integration (more)
Feel free to reach out if you run into any issues integrating a tool.
Vanilla UI tools
To initialize UI vanilla tools (jQuery, tooltips, ...) you can use the onHydrationEnd()
hook.
// pages/+onHydrationEnd.js
export default () => {
// Initializing vanilla JS component libraries, for example tooltips, after hydration.
tooltip.init(document.querySelectorAll('.tooltip'))
// Or some vanilla JS modal library
$('.my-modals').modal()
}
Analytics
To inject external <script>
tags, you can use:
You can use the +client.js
file to initialize analytics code.
// pages/+client.js
someAnalyticsLibrary.init(/* ... */)
That way you can install tools such as Google Analytics, Plausible, or Segment.
You can also load and/or initialize analytics code only after the hydration ends by using the +onHydrationEnd hook.
Component libraries
Some component libraries need initialization, most notably vanilla component libraries such as Bootstrap.
To initialize code, you can use
To inject external scripts, you can use:
Examples:
Data fetching
Instead of using the +data
hook, you can use tools to fetch the page's initial data.
🧠The following explains how to integrate tools for fetching initial data. Instead of manually integrating tools yourself, we generally recommend using Vike extensions such as
vike-react-apollo
orvike-vue-query
.⚠️ We recommend using such advanced capability, which can be complex to use, only if you have a clear reason why simpler alternatives aren't an option for you.
Some data-fetching tools enable you to fetch a page's initial data on a component-level instead of using the page-level Vike hook data()
On a high-level, the integration works like this:
- The initial data of a component is fetched while server-side rendering the component.
- The initial data is serialized and passed to the client. (So that the client uses the exact same data, avoiding double-fetching and hydration mismatches.)
If SSR is disabled, then the data is only fetched on the client-side. (The component's data is fetched where the component is loaded and executed.)
Some tools provide utilities to integrate more or less automatically. For example Apollo GraphQL provides many utilities to make integration easy.
A fully manual integration can be done as follows:
-
Determine the initial data on the server side (after SSR) and make it available as
pageContext.dataInitial
.You can configure/initialize the tool's client at
onBeforeRenderHtml()
:// pages/+onBeforeRenderHtml.js import { init } from 'awesome-data-tool' export function onBeforeRenderHtml(pageContext) { pageContext.dataClient = init({ someConfiguration: 'value' }) }
You can determine the initially fetched data at
onAfterRenderHtml()
:// pages/+onAfterRenderHtml.js export function onAfterRenderHtml(pageContext) { pageContext.dataInitial = pageContext.dataClient.getFetchedData() }
If you use React then you may also need to use
+Wrapper
:// pages/+Wrapper.jsx import { Provider } from 'awesome-data-tool/react' import { usePageContext } from 'vike-react/usePageContext' export function Wrapper({ children }) { const pageContext = usePageContext() return <Provider client={pageContext.dataClient}>{children}</Provider> }
-
Make
pageContext.dataInitial
available to the client-side by usingpassToClient
. -
On the client-side, initialize with
pageContext.dataInitial
.Typically at
onBeforeRenderClient()
:// pages/+onBeforeRenderClient.js import { initClient } from 'awesome-data-tool' export function onBeforeRenderClient(pageContext) { pageContext.dataClient = initClient({ data: pageContext.initialData }) }
See also:
- Tool guides & examples > Data fetching
- Guides > Data Fetching
- Integration > Store (State Management)
Service worker
You can use the +client.js
file to initialize service workers.
// pages/+client.js
// Initializing a Service Worker
navigator.serviceWorker.register(/* ... */)
View transitions
You can use navigate()
to implement View Transitions, see Tutorial on how to do View Transitions with Vike.
UI framework
You can manually integrate React/Vue/Solid (or any other UI framework) yourself:
You gain control not only over how React/Vue/Solid is integrated, but also how React/Vue/Solid tools are integrated.
// /renderer/+onRenderHtml.js
// Environment: server
import { escapeInject, dangerouslySkipEscape } from 'vike/server'
// This can be any UI framework (React, Vue, Solid, Svelte, ...)
import renderToHtml from 'some-ui-framework'
export { onRenderHtml }
async function onRenderHtml(pageContext) {
// `Page` is the `export { Page }` of our +Page.js files;
// Vike doesn't do anything with `Page` and just makes it available as
// `pageContext.Page`; we can export any `Page` value we want and do whatever we want with it.
const { Page } = pageContext
// We control how we use our UI framework to render our pages to HTML
const pageHtml = await renderToHtml(Page)
// We control the entire HTML
return escapeInject`<html>
<body>
<head>
<!-- Some libraries recommend loading code from a CDN -->
<script src="https://cdn.example.com/some-library/3.3.7/lib.min.js"></script>
</head>
<div id="root">
${dangerouslySkipEscape(pageHtml)}
</div>
</body>
</html>`
}
// /renderer/+onRenderClient.js
// Environment: browser
export { onRenderClient }
import { hydrateDom } from 'some-ui-framework'
async function onRenderClient(pageContext) {
// Here we can integrate performance measurement tools, e.g. to measure hydration performance
const { Page } = pageContext
// We control how our pages are hydrated
await hydrateDom(Page)
}
See:
Since you control how your pages are rendered, you can use any tool you want without any restrictions.
- Any UI framework (React 16, React 17, Vue 2, Vue 3, petite-vue, Svelte, Solid, Preact, ...)
- Any UI library (Vuex, Redux, Pinia, Relay, Apollo GraphQL, Recoil, ...)
- Any CSS framework (Tailwind CSS, Bulma, Bootstrap, Material Design, ...)
- Any client-side library (Vanilla JS component libraries, Bugsnag, Sentry, jQuery, Google Analytics, ...)
- Any browser technology (Service Workers, PWA, ...)
- Etc.
The Vike extensions
vike-react
/vike-vue
/vike-solid
aim to be almost as flexible. If you reach a limitation you believe is caused byvike-{react,vue,solid}
then reach out before considering going for a manual integration.
Non-JavaScript Backend
You can use Vike with any non-JavaScript backend using the following setup:
- Your non-JavaScript backend implements all the backend business logic while exposing a REST/GraphQL API.
- Your Vike app uses that REST/GraphQL API to render your pages to HTML with SSR or SSG. (The client-side of your Vike app then hydrates the HTML into a rich interactive user interface.)
If want to use SSR then, in addition to your non-JavaScript server, you'll need to deploy a JavaScript SSR server (with Node.js/Deno/Bun, or with an edge worker). Since that JavaScript server is only responsible for server-side rendering your pages to HTML, you can simply deploy it to a serverless/edge platform such as Cloudflare which is inexpensive and scalable.
Alternatively, instead of using a JavaScript server, you can pre-render your pages (SSG) while disabling SSR. In other words: you generate empty HTML shells that you statically deploy (using a static host, or using your own static assets deployment).
The HTML must be generated by Vike because the UI is completely owned by React/Vue/Solid. You cannot generate the HTML using your non-JavaScript backend: React/Vue/Solid would otherwise throw a hydration mismatch.
That way, you can use Vike with any backend:
- Java (Spring, Grails, ...)
- PHP (Laravel, Symfony, CakePHP, ...)
- Ruby on Rails
- Python (Django, Flask, FastAPI, ...)
- Elixir (Phoenix, ...)
- Go (Gin, Echo, Fiber, ...)
- Rust (Actix Web, Rocket, ...)
- Backend-as-a-Service (Firebase, ..)
- ...
Example:
See also:
Server (manual integration)
In general, we recommend using vike-server
for automatically integrating Vike with your JavaScript server (Express.js, Hono, Fastify, ...). But you can manually integrate Vike into your server instead if you prefer.
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)
// `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 and any deployment environment.
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).
You can use:
- Any server framework (Express, Fastify, Hono, Nitro, HatTip, Koa, Hapi, ...)
- Any authentication strategy/tool (email/password, OAuth, Auth.js, Passport.js, Grant, Keycloak, Auth0, ...).
- Any serverless/edge environment (Cloudflare Workers, Vercel, Firebase, AWS Lambda, Google Cloud Functions, Deno Deploy, ...)
- Any virtual private server (AWS EC2, Google Cloud, ...)
- Any static host (Cloudflare Pages, GitHub Pages, Netlify, ...)
- Any server utility (Docker, Nginx, PM2, ...)
Examples:
See also:
- Non-JavaScript Backend
- Integration > Server
-
API >
renderPage()
- Tool guides & examples > Server
- Deploy > Deploy