In general, thanks to the fact that we have control over how our pages are rendered, we can use whatever tool we want.
In fact, vite-plugin-ssr
is already being used with a high variety of tools within all kinds of diverse environments.
// _default.page.server.js
// Environment: Node.js
import { escapeInject, dangerouslySkipEscape } from 'vite-plugin-ssr'
// This can be any UI framework (React, Vue, Svelte, ...)
import renderToHtml from 'some-ui-framework'
export { render }
async function render(pageContext) {
// `Page` is the `export { Page }` (or `export default Page`) of our `*.page.js` files;
// `vite-plugin-ssr` doesn't do anything with `Page` and just makes it available as
// `pageContex.Page`; we can export any `Page` value we want and do whatever we want with it.
const { Page } = pageContext
// We have control over how we use our UI framework to render our pages to HTML
const pageHtml = await renderToHtml(Page)
// We have control over 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>`
}
// _default.page.client.js
// Environment: Browser
import { getPage } from 'vite-plugin-ssr/client'
import { hydrateToDom } from 'some-ui-framework'
async hydrate() {
const pageContext = await getPage()
const { Page } = pageContext
// We have control over how our pages are hydrated
await hydrateToDom(Page)
}
Since we control how our pages are render to HTML and hydrated, we can use:
petite-vue
, Svelte, Solid, Preact, ...)And, more importantly, integrating a view tool is simply a matter of following its official installation guide.
// _default.page.client.js
// Environment: Browser
import { getPage } from 'vite-plugin-ssr/client'
import { hydrateToDom } from 'some-ui-framework'
// This is the first browser-side line of code.
// This is a good place to initialize error tracking such as Sentry or Bugsnag.
Sentry.init()
// And also for initializing a Service Worker.
navigator.serviceWorker.register(/* ... */)
// This file represents the *entire* browser-side code; we have full control over the browser-
// side. If we save an empty `.page.client.js` then we have zero browser-side JavaScript.
hydrate()
// After hydration we usually initialize vanilla JS component libraries, for example tooltips
tooltip.init(document.querySelectorAll('.tooltip')
// Or some vanilla JS modal library
$('.my-modals').modal()
async hydrate() {
// Here we can integrate performance measurement tools, e.g. to measure hydration performance
const { Page } = await getPage()
await hydrateToDom(Page)
}
We can use:
Integrating a browser tool is only a matter of following its official installation guide.
From a server architecture perspective, vite-plugin-ssr
is just a server middleware.
// `app` can be any server framework such as Express.js/Fastify/Koa/Hapi/...
app.get('*', async (req, res) => {
// The `renderPage()` function, for a given URL, returns the result of our
// `render()` hook (usually an HTML string). It doesn't know anything about Express.js and
// can be used in any server environment, including serverless such as Cloudflare Workers
// or Vercel.
const pageContext = await renderPage({ url: req.url })
res.send(pageContext.httpResponse.body)
})
By pre-rendering we can remove the need for a Node.js production server and deploy to any static host instead.
We can use: