Skip to content
This repository has been archived by the owner on Apr 6, 2023. It is now read-only.

feat(nuxt): migrate to latest @vueuse/head #8000

Merged
merged 36 commits into from Oct 12, 2022
Merged
Show file tree
Hide file tree
Changes from 26 commits
Commits
Show all changes
36 commits
Select commit Hold shift + click to select a range
1629a5c
feat(head): migrate to latest `@vueuse/head`
harlan-zw Oct 5, 2022
52a8084
fix: correct innerHTML casing
harlan-zw Oct 5, 2022
e9bcdf8
revert: @vue/reactivity change
harlan-zw Oct 5, 2022
55b7361
revert: @vue/reactivity change
harlan-zw Oct 5, 2022
871c4d2
fix: typecheck error
harlan-zw Oct 5, 2022
2545cbb
chore: polishing PR
harlan-zw Oct 7, 2022
61f13ae
chore: bump @vueuse/head
harlan-zw Oct 7, 2022
01ddd16
fix: proper input types for `useHeadRaw`
harlan-zw Oct 7, 2022
f29cd62
feat(components): add `body` and `renderPriority` support
harlan-zw Oct 7, 2022
b4db806
fix: pause dom updates in client only
harlan-zw Oct 7, 2022
62c476b
chore: upgrade to @vueuse/head 1.0.0-rc.4
harlan-zw Oct 11, 2022
ecf29af
Merge branch 'main' of github.com:nuxt/framework into feat/vueuse-hea…
harlan-zw Oct 11, 2022
efe084c
chore: sync lock file
harlan-zw Oct 11, 2022
07d9ae4
Merge branch 'main' into feat/vueuse-head-migration
harlan-zw Oct 11, 2022
df84fce
chore: bump pkg
harlan-zw Oct 11, 2022
e38cd77
Merge branch 'feat/vueuse-head-migration' of github.com:harlan-zw/nux…
harlan-zw Oct 11, 2022
f77137a
Merge branch 'main' into feat/vueuse-head-migration
harlan-zw Oct 11, 2022
9475bb3
revert: test change
harlan-zw Oct 11, 2022
b3e2393
Merge branch 'feat/vueuse-head-migration' of github.com:harlan-zw/nux…
harlan-zw Oct 11, 2022
d0e0c3a
chore: simplify shortcuts
harlan-zw Oct 12, 2022
5b6f2a6
Merge branch 'main' of github.com:nuxt/framework into feat/vueuse-hea…
harlan-zw Oct 12, 2022
20e96ec
chore: simplify the initial meta even further
harlan-zw Oct 12, 2022
fb20fbf
doc: improve seo / useHead doc
harlan-zw Oct 12, 2022
c8f7c11
doc: polish and lint
harlan-zw Oct 12, 2022
6389ce4
doc: polish and lint
harlan-zw Oct 12, 2022
4788b1d
chore: pr fixes
harlan-zw Oct 12, 2022
53d6656
style: de-semify
danielroe Oct 12, 2022
b7bd452
refactor: move to dev-deps
danielroe Oct 12, 2022
8857474
fix: update type import
danielroe Oct 12, 2022
8f34199
Merge remote-tracking branch 'origin/main' into feat/vueuse-head-migr…
danielroe Oct 12, 2022
a8044a5
docs: add apostrophe
danielroe Oct 12, 2022
f94a0ab
docs: and this one too
danielroe Oct 12, 2022
5a92a44
Merge branch 'main' into feat/vueuse-head-migration
harlan-zw Oct 12, 2022
034e8ca
chore: bump @vueuse/head, fixes titleTemplate issue
harlan-zw Oct 12, 2022
53db611
style: small tweaks
danielroe Oct 12, 2022
b21a8ce
test: add some very basic type tests
danielroe Oct 12, 2022
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
269 changes: 218 additions & 51 deletions docs/content/1.getting-started/5.seo-meta.md
@@ -1,87 +1,84 @@
---
navigation.icon: uil:file-search-alt
description: Nuxt provides good default values for meta tags, but you can override these if you need to.
description: Improve your Nuxt apps SEO with powerful head config, composables and components.
danielroe marked this conversation as resolved.
Show resolved Hide resolved
---

# SEO and Meta

Out-of-the-box, Nuxt provides good default values for `charset` and `viewport` meta tags, but you can override these if you need to, as well as customize other meta tags for your site in several different ways.
Improve your Nuxt apps SEO with powerful head config, composables and components.
danielroe marked this conversation as resolved.
Show resolved Hide resolved

:ReadMore{link="/api/configuration/nuxt-config#head"}
## App Head

## `useHead` Composable
Providing an [app.head](/api/configuration/nuxt-config#head) property in your `nuxt.config.ts` allows you to customize the head for your entire app.

Within your `setup` function, you can call `useHead` with an object of meta properties with keys corresponding to meta tags: `title`, `titleTemplate`, `base`, `script`, `noscript`, `style`, `meta` and `link`, as well as `htmlAttrs` and `bodyAttrs`. There are also two shorthand properties, `charset` and `viewport`, which set the corresponding meta tags. Alternatively, you can pass a function returning the object for reactive metadata.

For example:
::alert{type=info}
This method does not allow you to provide reactive data, if you need global reactive data you can use `useHead` in `app.vue`.
::

```vue
<script setup>
useHead({
title: 'My App',
// or, instead:
// titleTemplate: (title) => `My App - ${title}`,
viewport: 'width=device-width, initial-scale=1, maximum-scale=1',
charset: 'utf-8',
meta: [
{ name: 'description', content: 'My amazing site.' }
],
bodyAttrs: {
class: 'test'
}
})
</script>
```
Shortcuts are available to make configuration easier: `charset` and `viewport`. Otherwise refer to the [Types](#types).
danielroe marked this conversation as resolved.
Show resolved Hide resolved

::ReadMore{link="/api/composables/use-head"}
::
### Defaults

## Title Templates
Out-of-the-box, Nuxt provides sane defaults, which you can override if needed.

You can use the `titleTemplate` option to provide a dynamic template for customizing the title of your site, for example, by adding the name of your site to the title of every page.
- `charset`: `utf-8`
- `viewport`: `width=device-width, initial-scale=1`

The `titleTemplate` can either be a string, where `%s` is replaced with the title, or a function. If you want to use a function (for full control), then this cannot be set in your `nuxt.config`, and it is recommended instead to set it within your `app.vue` file, where it will apply to all pages on your site:
### Example

```vue [app.vue]
<script setup>
useHead({
titleTemplate: (titleChunk) => {
return titleChunk ? `${titleChunk} - Site Title` : 'Site Title';
```ts{}[nuxt.config.ts]
export default defineNuxtConfig({
app: {
head: {
charset: 'utf-16',
viewport: 'width=500, initial-scale=1',
title: 'My App',
meta: [
// <meta name="description" content="My amazing site">
{ name: 'description', content: 'My amazing site.' }
],
}
})
</script>
}
})
```

Now, if you set the title to `My Page` with `useHead` on another page of your site, the title would appear as 'My Page - Site Title' in the browser tab. You could also pass `null` to default to the site title.
:ReadMore{link="/api/configuration/nuxt-config/#head"}

## Body Meta Tags
## Composable: `useHead`

You can use the `body: true` option on the `link` and `script` meta tags to append them to the end of the `<body>` tag.
The `useHead` composable function allows you to manage your head tags in a programmatic and reactive way, powered by [@vueuse/head](https://github.com/vueuse/head).

For example:
As with all composables, it can only be used with a components `setup` and lifecycle hooks.

```vue
<script setup>
### Example

```vue{}[app.vue]
<script setup lang="ts">
useHead({
script: [
{
src: 'https://third-party-script.com',
body: true
}
]
title: 'My App',
meta: [
{ name: 'description', content: 'My amazing site.' }
],
bodyAttrs: {
class: 'test'
},
script: [ { children: 'console.log(\'Hello world\') } ]
})
</script>
```

## Meta Components
::ReadMore{link="/api/composables/use-head"}
::

## Components

Nuxt provides `<Title>`, `<Base>`, `<Script>`, `<NoScript>`, `<Style>`, `<Meta>`, `<Link>`, `<Body>`, `<Html>` and `<Head>` components so that you can interact directly with your metadata within your component's template.

Because these component names match native HTML elements, it is very important that they are capitalized in the template.

`<Head>` and `<Body>` can accept nested meta tags (for aesthetic reasons) but this has no effect on _where_ the nested meta tags are rendered in the final HTML.

For example:
### Example

<!-- @case-police-ignore html -->

Expand All @@ -103,7 +100,120 @@ const title = ref('Hello World')
</template>
```

## Example: Usage With `definePageMeta`
## Types

The below is the non-reactive types used for `useHead`, `app.head` and components.

```ts
interface MetaObject {
title?: string
titleTemplate?: string | ((title?: string) => string)
base?: Base
link?: Link[]
meta?: Meta[]
style?: Style[]
script?: Script[]
noscript?: Noscript[];
htmlAttrs?: HtmlAttributes;
bodyAttrs?: BodyAttributes;
}
```

See [zhead](https://github.com/harlan-zw/zhead/tree/main/packages/schema/src) for more detailed types.

## Features

### Reactivity

Reactivity is supported on all properties, as computed, computed getter refs and reactive.

It's recommended to use computed getters (`() => {}`) over computed (`computed(() => {})`).

::code-group

```vue [useHead]
<script setup lang="ts">
const desc = ref('My amazing site.')

useHead({
meta: [
{ name: 'description', content: desc }
],
})
</script>
```

```vue [Components]
<script setup>
const desc = ref('My amazing site.')
</script>
<template>
<div>
<Meta name="description" :content="desc" />
</div>
</template>
```

::

### Title Templates

You can use the `titleTemplate` option to provide a dynamic template for customizing the title of your site. for example, by adding the name of your site to the title of every page.

The `titleTemplate` can either be a string, where `%s` is replaced with the title, or a function.

If you want to use a function (for full control), then this cannot be set in your `nuxt.config`, and it is recommended instead to set it within your `app.vue` file, where it will apply to all pages on your site:

::code-group

```vue [useHead]
<script setup lang="ts">
useHead({
titleTemplate: (titleChunk) => {
return titleChunk ? `${titleChunk} - Site Title` : 'Site Title';
}
})
</script>
```

::

Now, if you set the title to `My Page` with `useHead` on another page of your site, the title would appear as 'My Page - Site Title' in the browser tab. You could also pass `null` to default to the site title.

### Body Tags

You can use the `body: true` option on the `link` and `script` meta tags to append them to the end of the `<body>` tag.

For example:

::code-group

```vue [useHead]
<script setup lang="ts">
useHead({
script: [
{
src: 'https://third-party-script.com',
body: true
}
]
})
</script>
```

```vue [Components]
<template>
<div>
<Script src="https://third-party-script.com" body="true" />
</div>
</template>
```

::

## Examples

### Usage With `definePageMeta`

Within your `pages/` directory, you can use `definePageMeta` along with `useHead` to set metadata based on the current route.

Expand Down Expand Up @@ -132,3 +242,60 @@ useHead({
:LinkExample{link="/examples/composables/use-head"}

:ReadMore{link="/guide/directory-structure/pages/#page-metadata"}

### Add Dynamic Title

In the example below, `titleTemplate` is set either as a string with the `%s` placeholder or as a `function`, which allows greater flexibility in setting the page title dynamically for each route of your Nuxt app:

```vue [app.vue]
<script setup>
useHead({
// as a string,
// where `%s` is replaced with the title
titleTemplate: '%s - Site Title',
// ... or as a function
titleTemplate: (productCategory) => {
return productCategory
? `${productCategory} - Site Title`
: 'Site Title'
}
})
</script>
```

`nuxt.config` is also used as an alternative way of setting the page title. However, `nuxt.config` does not allow the page title to be dynamic. Therefore, it is recommended to use `titleTemplate` in the `app.vue` file to add a dynamic title, which is then applied to all routes of your Nuxt app.

### Add External CSS

The example below inserts Google Fonts using the `link` property of the `useHead` composable:

::code-group

```vue [useHead]
<script setup lang="ts">
useHead({
link: [
{
rel: 'preconnect',
href: 'https://fonts.googleapis.com'
},
{
rel: 'stylesheet',
href: 'https://fonts.googleapis.com/css2?family=Roboto&display=swap',
crossorigin: ''
}
]
})
</script>
```

```vue [Components]
<template>
<div>
<Link rel="preconnect" href="https://fonts.googleapis.com" />
<Link rel="stylesheet" href="https://fonts.googleapis.com/css2?family=Roboto&display=swap" crossorigin="" />
</div>
</template>
```

::