Migrate Your TypeScript App To Unhead v2
Introduction
With the release of Unhead v2, we now have first-class support for other frameworks. However, this guide will focus on the changes that affec TypeScript users.
The high-level of Unhead v2 was to remove deprecations and remove the implicit context implementation.
Legacy Support
Unhead v2 is mostly fully backwards compatible with Unhead v1.
While not recommended, if upgrading is not possible for you, you can change your imports to the following:
-import { createServerHead, useHead } from 'unhead'
+import { createServerHead, useHead } from 'unhead/legacy'
This will be removed in a future minor version, so you should lock your dependencies to the version that works for you.
Client / Server Subpath Exports
🚦 Impact Level: Critical
⚠️ Breaking Changes:
createServerHead()
andcreateHead()
exports fromunhead
are removed
The path where you import createHead
from has been updated to be a subpath export.
Please follow the updated installation instructions or simply update the import to use the subpath.
Client bundle:
-import { createServerHead } from 'unhead'
+import { createHead } from 'unhead/client'
// avoids bundling server plugins
createHead()
Server bundle:
-import { createServerHead } from 'unhead'
+import { createHead } from 'unhead/server'
// avoids bundling server plugins
-createServerHead()
+createHead()
Removed Implicit Context
🚦 Impact Level: Critical
⚠️ Breaking Changes:
getActiveHead()
,activeHead
exports are removed
The implicit context implementation kept a global instance of Unhead available so that you could use the useHead()
composables
anywhere in your application.
useHead({
title: 'This just worked!'
})
While safe client side, this was a leaky abstraction server side and led to memory leaks in some cases.
In v2, the core composables no longer have access to the Unhead instance. Instead, you must pass the Unhead instance to the composables.
unhead
. In JavaScript frameworks we tie the context to the framework itself so you
don't need to worry about this.import { useHead } from 'unhead'
// example of getting the instance
const unheadInstance = useMyApp().unhead
useHead(unheadInstance, {
title: 'Looks good'
})
import { useHead } from 'unhead'
useHead({
title: 'Just worked! But with SSR issues'
})
vmid
, hid
, children
, body
Removed
🚦 Impact Level: High
For legacy support with Vue Meta we allowed end users to provide deprecated properties: vmid
, hid
, children
and body
.
You must either update these properties to the appropriate replacement, remove them, or you can use the DeprecationsPlugin
.
Meta tags with vmid
, hid
These are already deduped magically so you can safely remove them there.
useHead({
meta: [{
name: 'description',
- vmid: 'description'
- hid: 'description'
}]
})
Other Tags with vmid
, hid
Use key
if you need the deduplication feature. This is useful for tags that may change from server to client
rendering.
useHead({
script: [{
- vmid: 'my-key'
- hid: 'my-key'
+ key: 'my-key',
}]
})
Using children
The children
key is a direct replacement of innerHTML
which you should use instead.
innerHTML
as this can lead to XSS vulnerabilities.useHead({
script: [
{
- children: '..'
+ innerHTML: '..'
}
]
})
Using body
The body
key should be updated to use the Tag Position feature.
useHead({
script: [
{
- body: true
+ tagPosition: 'bodyClose'
}
]
})
Use Deprecations Plugin
import { createHead } from 'unhead'
import { DeprecationsPlugin } from 'unhead/plugins'
const unhead = createHead({
plugins: [DeprecationsPlugin]
})
Opt-in Template Params & Tag Alias Sorting
🚦 Impact Level: High
To reduce the bundle size and improve performance, we've moved the template params and tag alias sorting to optional plugins.
If you'd like to continue using these, please opt-in to the plugins.
import { AliasSortingPlugin, TemplateParamsPlugin } from 'unhead/plugins'
createHead({
plugins: [TemplateParamsPlugin, AliasSortingPlugin]
})
Vue 2 Support
🚦 Impact Level: Critical
Unhead v2 no longer supports Vue v2. If you're using Vue v2, you will need to lock your dependencies to the latest v1 version of Unhead.
Promise Input Support
🚦 Impact Level: Medium
If you have promises as input they will no longer be resolved, either await the promise before passing it along or register the optional promises plugin.
Option 1: Await Promise
useHead({
link: [
{
- href: import('~/assets/MyFont.css?url'),
+ href: await import('~/assets/MyFont.css?url'),
rel: 'stylesheet',
type: 'text/css'
}
]
})
Option 2: Promise Plugin
import { PromisePlugin } from 'unhead/plugins'
const unhead = createHead({
plugins: [PromisePlugin]
})
useScript()
Updated
🚦 Impact Level: High
⚠️ Breaking Changes:
- Script instance is no longer augmented as a proxy and promise
script.proxy
is rewritten for simpler, more stable behaviorstub()
and runtime hookscript:instance-fn
are removed
Replacing promise usage
If you're using the script as a promise you should instead opt to use the onLoaded()
functions.
const script = useScript()
-script.then(() => console.log('loaded')
+script.onLoaded(() => console.log('loaded'))
Replacing proxy usage
If you're accessing the underlying API directly from the script instance, you will now need to only access it from the .proxy
.
const script = useScript('..', {
use() { return { foo: [] } }
})
-script.foo.push('bar')
+script.proxy.foo.push('bar')
Replacing stub()
If you were using stub for anything you should replace this with either custom use()
behavior.
const script = useScript('...', {
- stub() { return { foo: import.meta.server ? [] : undefined } }
})
+script.proxy = {} // your own implementation
Tag Sorting Updated
🚦 Impact Level:
An optional Capo.js plugin was added to Unhead, in v2 we make this the default sorting behavior.
You can opt-out of Capo.js sorting by providing the option.
createHead({
disableCapoSorting: true,
})
Default SSR Tags
🚦 Impact Level: Low
When SSR Unhead will now insert important default tags for you:
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<html lang="en">
If you were previously relying on these being left empty, you may need to either disable them by using disableDefaultTags
or insert tags
to override them.
import { createHead, useHead } from 'unhead/server'
// disable when creating the head instance
const head = createHead({
disableDefaults: true,
})
useHead(head, {
htmlAttrs: {
lang: 'fr'
}
})
CJS Exports Removed
🚦 Impact Level: Low
CommonJS exports have been removed in favor of ESM only.
-const { createHead } = require('unhead/client')
+import { createHead } from 'unhead/client'
@unhead/schema
Deprecated
🚦 Impact Level: Low
The @unhead/schema
package is now deprecated and will be removed in a future version. You should instead import
the schema from unhead/types
or unhead
.
-import { HeadTag } from '@unhead/schema'
+import { HeadTag } from 'unhead/types'