SEO и Meta

Улучшайте SEO приложения на Nuxt через head в конфиге, композаблы и компоненты.

Управление тегами в <head> в Nuxt построено на Unhead. Он задаёт разумные значения по умолчанию, даёт несколько мощных композаблов и множество опций для настройки <head> и SEO-метатегов приложения.

Конфигурация Nuxt

В nuxt.config.ts через app.head можно статически задать <head> для всего приложения.

Здесь нельзя использовать реактивные данные. Для этого лучше useHead() в app.vue.

Имеет смысл задавать здесь то, что редко меняется: заголовок сайта по умолчанию, lang и favicon.

nuxt.config.ts
export default defineNuxtConfig({
  app: {
    head: {
      title: 'Nuxt', // default fallback title
      htmlAttrs: {
        lang: 'en',
      },
      link: [
        { rel: 'icon', type: 'image/x-icon', href: '/favicon.ico' },
      ],
    },
  },
})

Ниже в разделе «Типы» перечислены и другие допустимые поля.

Теги по умолчанию

Nuxt по умолчанию добавляет теги, чтобы сайт корректно отображался сразу:

  • viewport: width=device-width, initial-scale=1
  • charset: utf-8

Большинству сайтов не нужно менять эти значения по умолчанию; при необходимости их можно обновить через сокращённые поля charset и viewport.

nuxt.config.ts
export default defineNuxtConfig({
  app: {
    head: {
      // update Nuxt defaults
      charset: 'utf-16',
      viewport: 'width=device-width, initial-scale=1, maximum-scale=1',
    },
  },
})

useHead

Композабл useHead принимает реактивные значения и позволяет управлять <head> из кода.

app.vue
<script setup lang="ts">
useHead
({
title
: 'My App',
meta
: [
{
name
: 'description',
content
: 'My amazing site.' },
],
bodyAttrs
: {
class
: 'test',
},
script
: [{
innerHTML
: 'console.log(\'Hello world\')' }],
}) </script>

Мы рекомендуем композаблы useHead и useHeadSafe.

useSeoMeta

useSeoMeta задаёт SEO-метатеги одним объектом с полной типобезопасностью.

Так проще не ошибиться в атрибутах — например, не перепутать name и property.

app.vue
<script setup lang="ts">
useSeoMeta
({
title
: 'My Amazing Site',
ogTitle
: 'My Amazing Site',
description
: 'This is my amazing site, let me tell you all about it.',
ogDescription
: 'This is my amazing site, let me tell you all about it.',
ogImage
: 'https://example.com/image.png',
twitterCard
: 'summary_large_image',
}) </script>
Узнать больше Docs > 3 X > API > Composables > Use Seo Meta.

Компоненты

Во всех сценариях предпочтительнее useHead, но при желании метатеги можно описать в шаблоне компонентами.

Nuxt предоставляет <Title>, <Base>, <NoScript>, <Style>, <Meta>, <Link>, <Body>, <Html> и <Head> для работы с <head> из разметки. Имена этих компонентов должны начинаться с заглавной буквы — так они не пересекаются с обычными HTML-тегами.

<Head> и <Body> могут принимать вложенные мета-теги (из эстетических соображений), но это не влияет на то, где именно вложенные мета-теги будут отображаться в конечном HTML.

app.vue
<script setup lang="ts">
const title = ref('Hello World')
</script>

<template>
  <div>
    <Head>
      <Title>{{ title }}</Title>
      <Meta
        name="description"
        :content="title"
      />
      <Style>
        body { background-color: green; }
      </Style>
    </Head>

    <h1>{{ title }}</h1>
  </div>
</template>

Удобнее оборачивать теги в <Head> или <Html> — так дедупликация работает предсказуемее.

Если нужно дублировать теги по границе клиент–сервер, задайте атрибут key на компоненте <Head>.

Типы

Ниже приведены нереактивные типы, используемые для useHead, app.head и компонентов.

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

Более подробную информацию о типах см. в @unhead/vue.

Возможности

Реактивность

Реактивность поддерживается для всех свойств путем предоставления вычисляемого значения (computed), геттера или реактивного объекта.

<script setup lang="ts">
const 
description
=
ref
('My amazing site.')
useHead
({
meta
: [
{
name
: 'description',
content
:
description
},
], }) </script>

Шаблон названия

Опция titleTemplate задаёт шаблон заголовка сайта — например, суффикс с названием проекта на каждой странице.

Это может быть строка с %s вместо заголовка страницы или функция.

Функцию нельзя задать в nuxt.config; для полного контроля указывайте titleTemplate в app.vue — тогда шаблон действует на все страницы:

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

Если на другой странице через useHead задать заголовок Моя страница, на вкладке будет «Моя страница - Заголовок сайта». Передав null, получите только «Заголовок сайта».

Параметры шаблона (templateParams)

Через templateParams можно задать свои плейсхолдеры в titleTemplate помимо стандартного %s и собирать заголовок гибче.

<script setup lang="ts">
useHead
({
titleTemplate
: (
titleChunk
) => {
return
titleChunk
? `${
titleChunk
} %separator %siteName` : '%siteName'
},
templateParams
: {
siteName
: 'Site Title',
separator
: '-',
}, }) </script>

Теги body

Вы можете использовать опцию tagPosition: 'bodyClose' для соответствующих тегов, чтобы добавить их в конец тега <body>.

Например:

<script setup lang="ts">
useHead
({
script
: [
{
src
: 'https://third-party-script.com',
// valid options are: 'head' | 'bodyClose' | 'bodyOpen'
tagPosition
: 'bodyClose',
}, ], }) </script>

Примеры

Используя definePageMeta

В каталоге pages/ можно сочетать definePageMeta с useHead, чтобы задавать метаданные с учётом маршрута.

Сначала задаём заголовок страницы (макрос обрабатывается на этапе сборки, значение не бывает динамическим):

pages/some-page.vue
<script setup lang="ts">
definePageMeta
({
title
: 'Some Page',
}) </script>

В лейауте можно прочитать метаданные маршрута, заданные на странице:

layouts/default.vue
<script setup lang="ts">
const 
route
=
useRoute
()
useHead
({
meta
: [{
property
: 'og:title',
content
: `App Name - ${
route
.
meta
.
title
}` }],
}) </script>
Прочитайте и отредактируйте живой пример в Docs > 3 X > Examples > Features > Meta Tags.
Узнать больше Docs > 3 X > Directory Structure > Pages > #page Metadata.

Динамический заголовок (title)

В примере ниже titleTemplate задается либо как строка с заполнителем %s, либо как функция, что позволяет более гибко устанавливать заголовок страницы динамически для каждого маршрута вашего приложения Nuxt:

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

nuxt.config также используется в качестве альтернативного способа установки заголовка страницы. Однако nuxt.config не позволяет сделать заголовок страницы динамическим. Поэтому рекомендуется использовать titleTemplate в файле app.vue для добавления динамического заголовка, который затем применяется ко всем маршрутам вашего приложения Nuxt.

Внешний CSS

В примере ниже показано, как можно включить Google Fonts, используя свойство link композабла useHead или компонент <Link>:

<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>