Install Unhead SSR
Setup
- Install
@unhead/ssr
dependency to your project:
yarn add @unhead/ssr
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
}
Options
When using renderSSRHead
, you can pass an optional options
object to customize the output.
export interface RenderSSRHeadOptions {
omitLineBreaks?: boolean
}
omitLineBreaks
- Type:
boolean
- Default:
false
Set omitLineBreaks
to true
if you prefer to render the head tags without line breaks.
Example usage:
const options = { omitLineBreaks: true }
const payload = await renderSSRHead(head, options)
This will render the head tags as a single line, omitting any line breaks that would normally be included.
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
<html${htmlAttrs}>
<head>
${headTags}
</head>
<body${bodyAttrs}>
${bodyTagsOpen}
<div id="app">${appHTML}</div>
${bodyTags}
</body>
</html>
Simple string replace
<!DOCTYPE html>
<html<!--htmlAttrs-->>
<head>
<!--headTags-->
<!--preload-links-->
</head>
<body<!--bodyAttrs-->>
<!--bodyTagsOpen-->
<div id="app"><!--app-html--></div>
<script type="module" src="/src/entry-client.js"></script>
<!--bodyTags-->
</body>
</html>
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.
useHead({
script: [
{
// key is needed to avoid seperate scripts being created
key: 'my-script',
innerHTML: process.server ? '' : 'console.log("hello world")',
}
]
})