最終更新日: 2023年08月15日

SEO and Meta

NuxtのSEOを強化するためには、強力なヘッド構成、コンポーザブル、およびコンポーネントを活用することです。

デフォルト

デフォルトでは、Nuxtは適切なデフォルト設定になっていますが、必要に応じてオーバーライドすることもできます。 nuxt.config.tsにapp.headプロパティを指定することで、アプリ全体のheadをカスタマイズすることができます。

  • charset: utf-8
  • viewport: width=device-width, initial-scale=1
  • nuxt.config.ts
  • ts
export default defineNuxtConfig({
  app: {
    head: {
      charset: 'utf-8',
      viewport: 'width=device-width, initial-scale=1',
    }
  }
})

charsetおよびviewportというショートカットを使用すると、設定を簡単に行うことができます。 また、Typesにリストされているキーのいずれかを提供することもできます。

useHead

useHeadコンポーザブル関数を使用すると、Unheadによって強力にサポートされたプログラマティックでリアクティブな方法でheadタグを管理することができます。

すべてのコンポーザブルと同様に、useHeadコンポーザブルはコンポーネントのsetupとライフサイクルフック(lifecycle hooks)と共に使用することができます。

  • app.vue
  • ts
<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 と useServerSeoMeta

useSeoMetauseServerSeoMetaのコンポーザブルを使用すると、完全なTypeScriptサポートを備えたフラットなオブジェクトとしてサイトのSEOメタタグを定義することができます。

これにより、nameの代わりにpropertyを使用するなどの入力ミスや一般的なミスを防ぐことができます。

  • app.vue
  • ts
<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>

詳細については、useSeoMetaとuseServerSeoMetaのコンポーザブルについてドキュメントを参照してください。

コンポーネント / Components

Nuxtは、<Title><Base><NoScript><Style><Meta><Link><Body><Html>、および<Head>のコンポーネントを提供しています。 これにより、コンポーネントのテンプレート内で直接メタデータとやり取りすることができます。

これらのコンポーネント名は、ネイティブのHTML要素と一致しているため、テンプレート内で大文字にすることが非常に重要です。

<Head><Body>はネストされたメタタグを受け入れることができます(可読性を高めるため)。ただし、ネストされたメタタグの配置は最終的なHTMLには影響しません。

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

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

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

Types

以下は、useHeadapp.headおよびコンポーネントで使用される非リアクティブな型です。

  • ts
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/schemaを参照してください。

機能 / Features

リアクティビティ(Reactivity)

リアクティビティ(Reactivity)は、computed、getters、およびreactiveとしてすべてのプロパティでサポートされています。

computed(() => value)よりも() => valueの使用を推奨します。

  • useHead
  • ts
<script setup lang="ts">
    const description = ref('My amazing site.')

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

    useSeoMeta({
        description
    })
</script>
  • Components
  • ts
<script setup>
    const description = ref('My amazing site.')
</script>

<template>
  <div>
    <Meta name="description" :content="description" />
  </div>
</template>

タイトルテンプレート

titleTemplateオプションを使用して、サイトのタイトルをカスタマイズするための動的なテンプレートを提供することができます。 例えば、サイト名を各ページのタイトルに追加することができます。

titleTemplateは、文字列で指定することもできます。この場合、%sはタイトルに置き換えられます。また、関数としても指定することができます。

関数を使用する場合(完全な制御を目指す場合)、nuxt.configで設定することはできません。 代わりに、app.vueファイル内で設定することをおすすめします。 これにより、サイトのすべてのページに適用されます。

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

もし別のページでuseHeadを使ってタイトルをMy Pageと設定した場合、ブラウザのタブには「My Page - サイトタイトル」と表示されます。 また、nullを渡すことでデフォルトのサイトタイトルを使うこともできます。

Bodyタグ

適用可能なタグに対して、tagPosition: 'bodyClose'オプションを使用することで、それらを <body>タグの末尾に追加することができます。

例:

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

definePageMetaについて

pages/ディレクトリ内では、definePageMetauseHeadと組み合わせて使用することで、現在のルートに基づいてメタデータを設定することができます。

例えば、現在のページのタイトルを最初に設定することができます(これはマクロを介してビルド時に抽出されるため、動的に設定することはできません):

  • pages/some-page.vue
  • vue
<script setup>
    definePageMeta({
        title: 'Some Page'
    })
</script>

以前に設定したルートのメタデータをレイアウトファイルで使用することがあります。:

  • pages/layouts/default.vue
  • vue
<script setup>
    const route = useRoute()

    useHead({
        meta: [{ property: 'og:title', content: `App Name - ${route.meta.title}` }]
    })
</script>

Info 詳細はMeta Tagsを参照してください。

Info 詳細は、ガイド > ディレクトリ構築 > ページのメタデータを参照してください。

動的なタイトル

以下の例では、titleTemplate%sプレースホルダーを含む文字列または関数として設定されています。 関数を使用することで、Nuxtアプリの各ルートごとにページタイトルを動的に設定する際により柔軟な操作が可能です。

  • npx
  • ts
<script setup>
    useHead({
        // 文字列として,
        // %s はタイトルに置き換えられます。
        titleTemplate: '%s - Site Title',
        
        // ... または関数として
        titleTemplate: (productCategory) => {
            return productCategory
            ? `${productCategory} - Site Title`
            : 'Site Title'
        }
    })
</script>

nuxt.configもページタイトルを設定する別の方法として使用できます。ただし、nuxt.configではページタイトルを動的に設定することはできません。そのため、app.vueファイルでtitleTemplateを使用して動的なタイトルを追加し、それをNuxtアプリのすべてのルートに適用することが推奨されます。

外部CSS

以下の例は、useHeadコンポーザブルのlinkプロパティまたは<Link>コンポーネントを使用してGoogle Fontsを有効にする方法を示しています。

  • npx
  • ts
<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>
  • Components
  • vue
<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>