How it works
Core
The Unhead core is a small API which abstracts the common logic for all head integrations. It is designed to be used by any head integration, and is not specific to any one framework.
Extensibility and customisation is a core goal of Unhead. All internal logic is powered by hooks and plugins, hooks being provided by hookable.
The API is as follows:
export interface Unhead<Input extends {} = Head> {
/**
* The active head entries.
*/
headEntries: () => HeadEntry<Input>[]
/**
* Create a new head entry.
*/
push: (entry: Input, options?: HeadEntryOptions) => ActiveHeadEntry<Input>
/**
* Resolve tags from head entries.
*/
resolveTags: () => Promise<HeadTag[]>
/**
* Exposed hooks for easier extension.
*/
hooks: Hookable<HeadHooks>
/**
* Resolved options
*/
resolvedOptions: CreateHeadOptions
/**
* @internal
*/
_popSideEffectQueue: () => SideEffectsRecord
}
Head entries
Head entries are the data for Unhead. They are created by calling push
on the Unhead instance.
An entry is a simple object which contains the tags to be added. Head entries are resolved to tags with the
resolveTags
method.
const myFirstEntry = head.push(
{
title: 'My title',
meta: [
{
name: 'description',
content: 'My description',
},
],
}
)
Resolve Tags
When a DOM or SSR render is triggered, the tags will be resolved.
This is done by calling resolveTags
on the Unhead instance. This will return a promise which resolves to an array of tags.
const tags = await head.resolveTags()
// [
// {
// "_d": "title",
// "_e": 0,
// "_p": 0,
// "textContent": "My title",
// "props": {},
// "tag": "title",
// },
// {
// "_d": "meta:name:description",
// "_e": 0,
// "_p": 1,
// "props": {
// "content": "My description",
// "name": "description",
// },
// "tag": "meta",
// },
// ]
When resolving the tags, the following steps are taken:
Call hook entries:resolve
Resolve any reactive elements within the input
Call hook tags:normalise
Normalise the tags, makes sure the schema of the tag is correct:
- Assigns a dedupe key to the tag
- Handles deprecated options
- Assigns tag meta data (entry id, position id, etc)
Call hook tags:resolve
Process the hooks for default plugin logic:
- Deduping tags, including class and style merging
- Ordering tags
- Handling title template
Frameworks integrations will abstract these lifecycle functions away, but they are available for custom integrations.
@unhead/dom
By default, when entries are updated, the hook entries:updated
is called, which
will trigger a debounced DOM update.
The DOM rendered resolves the tags as above and starts patching
The DOM patching algorithm is non-aggressive and will preserve existing state as much as possible.
To support mismatch SSR / CSR content, Unhead assigns a data-h-key="${hash}"
key to rendered attributes when a key
is provided.
Side effects
When rendering elements or attributes, side effects are collected with the head entry to dispose of when needed.
When you dispose or update the entry, these side effects will be cleared.
myFirstEntry.dispose()
// next time the DOM render is called, the side effects will be cleared