Ssr

Install Unhead SSR

Get started with Unhead SSR by installing the dependency to your project.

Setup

  1. Install @unhead/ssr dependency to your project:
yarn
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")',
    }
  ]
})