Server-Side Rendering Setup

1. Generating the SSR payload

Once you're ready to start displaying tags on the server, you'll need to generate the SSR payload.

For this you will need the @unhead/ssr dependency.

import { renderSSRHead } from '@unhead/ssr'
// head is from createHead()
// if you need access to it you can also use getActiveHead()
const payload = await renderSSRHead(head)

The payload schema looks like the following:

export interface SSRHeadPayload {
headTags: string
bodyTags: string
bodyTagsOpen: string
htmlAttrs: string
bodyAttrs: string

2. Update your app template

You will need to update your app template to add in the templates for the SSR tags.

Different frameworks differ in how they handle this template.

Some examples below:

Lodash template function

<div id="app">${appHTML}</div>

Simple string replace

<!DOCTYPE html>
<div id="app"><!--app-html--></div>
<script type="module" src="/src/entry-client.js"></script>

To handle this type of template you can use this code

const headPayload = await renderSSRHead(head)
Object.entries(headPayload).forEach(([key, value]) => {
html = html.replace(`<!--${key}-->`, value)

3. Done! How hydration works

When your client-side app hydrates the server head tags, it will attempt to hydrate each element based on the nodes being equal $el.isEqualNode($newEl) or them sharing the same dedupe key (see Tag Deduping).

If you're rendering content that differs between client and server, you should specify a key attribute if the element does not have a unique dedupe key.

script: [
// key is needed to avoid seperate scripts being created
key: 'my-script',
innerHTML: process.server ? '' : 'console.log("hello world")',