【Nuxt.js】head内にSEOに必要なmeta情報を追加する

![eycatch01.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/163786/120faf0c-b0ce-e482-e0aa-382a30443b2a.png)


Nuxt.jsでSEOに必要なmetaタグの情報を入れていく方法を紹介します。:point_up_tone1:

# metaタグとは?
Webサイトのページ情報を検索エンジンに伝えるtagのことです。
metaタグを入力することでこのページはこんな情報を持っていますよということを伝えることができます。
※今回SEO対策が必要なのでSSRを想定しています。

# 想定されるHTML
今回は下記のようなHTMLを出力することを目標とします。

- 基本的なmeta要素 + titleタグ
- OGPに必要なタグ
- TwitterやFacebookなどSNSに必要なタグ 

これらについて解説していきます。

``` html
<!DOCTYPE html>
<html lang="ja" prefix="og: http://ogp.me/ns#">
  <head>

    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">

    <!-- 基本属性 -->
    <title>タイトル</title>
    <meta name="description" content="ディスクリプション">
    <meta name="keywords" content="キーワード">

    <!-- OGPタグ -->
    <meta property="og:site_name" content="サイト名" >
    <meta property="og:type" content="サイトのタイプ">
    <meta property="og:url" content="ページURL">
    <meta property="og:title" content="ページタイトル">
    <meta property="og:description" content="ディスクリプション">
    <meta property="og:image" content="OGP画像URL"> 
    
    <!-- SNS用 -->
    <meta property="fb:app_id" content="App-ID">
    <meta name="twitter:card" content="summary_large_image">
    <meta name="twitter:site" content="@Twitter">

  </head>

  <body>
  -------- 省略 --------
  </body>
</html>
```

メタタグの使い方について知りたい方はこちらの記事をどうぞ
[metaタグの使い方](https://qiita.com/mzmz__02/items/dad4c82555ac2dc5e749)
[OGPを設定しよう！SNSでシェアされやすい設定方法とは？](https://digitalidentity.co.jp/blog/seo/ogp-share-setting.html)

# SSRモードに設定
新規作成なら`SPA`か`SSR/SSG`の選択ができるので`SSR/SSG`を選択。

すでにNuxtを作成済みなら`universal(SSR)モード`に設定してください。
`SPAモード`ではページごとのmeta反映されません。(させる設定もありますがここでは割愛させていただきます。)

``` nuxt.config.js
module.exports = {
  mode: 'universal',
  ...
}
```

# nuxt.config.jsにmeta要素を追加
Nuxtでは全体に使うmeta要素をnuxt.config.jsのhead内に記述します。
※1 faviconやCDNの読み込みなどもこちらから行えますが今回はSEOに必要な要素だけ記述しています。
※2 meta要素が重複する場合、先頭に`hid`を入れておかないとエラーになります。

``` nuxt.config.js
export default {
  head: {
    htmlAttrs: {
      lang: 'ja',
      prefix: 'og: http://ogp.me/ns#'
    },
    titleTemplate: '%s - ' + 'タイトル',
    meta: [
      { charset: 'utf-8' },
      { name: 'viewport', content: 'width=device-width, initial-scale=1' },
      { hid: 'description', name: 'description', content: 'サイトの説明' || '' },
      { hid: 'keywords', name: 'keywords', content: 'キーワード1,キーワード2,キーワード3' },

      { hid: 'og:site_name', property: 'og:site_name', content: 'サイト名' },
      { hid: 'og:type', property: 'og:type', content: 'サイトのタイプ' },
      { hid: 'og:url', property: 'og:url', content: 'サイトURL' },
      { hid: 'og:title', property: 'og:title', content: 'サイトタイトル' },
      { hid: 'og:description', property: 'og:description', content: 'サイトの説明' },
      { hid: 'og:image', property: 'og:image', content: 'サイトURL' },

      { hid: 'fb:app_id', property: 'fb:app_id', content: 'App-ID' },
      { hid: 'twitter:card', name: 'twitter:card', content: 'summary_large_image' },
      { hid: 'twitter:site', name: 'twitter:site', content: '@Twitter' }

    ],
  },
}
```

`htmlAttrs`で言語設定、`prefix`でOGPを使いますよと宣言します。
`titleTemplate`で全ページに「ページ名 - タイトル」を出力させます。`%s`の部分がそれぞれのページで設定したタイトルが表示されます。

# Topページの設定
headタグの中の要素は下記のように記述します。
`titleTemplate`を`null`することで`nuxt.config.js`で設定したものを反映させずにすみます。
そして`title`にTopページのタイトルを入力をすることでtitleタグに表示することができます。
※これを設定しておかないと「タイトル名 - タイトル名」のようになり重複してしまいます。

``` pages/index.vue
<template>
  <main>
    <h1>サイトタイトル</h1>
  </main>

</template>

<script>
export default {
  head: {
    titleTemplate: null,
    title: 'サイトタイトル'
  }
}
</script>

```

# 各ページごとの設定
Topページ以外の書き方です。
nuxt.config.jsで設定したtitleTemplateの機能を使います。
head内のtitle,metaに内容を追加することで反映されます。

``` pages/about.vue
<template>
  <main>
    <h1>各ページのタイトル</h1>
  </main>

</template>

<script>
export default {
  head: {
    return {
      title: 'ページ名',
      meta: [
        { hid: 'description', name: 'description', 'ページの説明' },
        { hid: 'keyword', name: 'keyword', 'ページのキーワード' },
        { hid: 'og:type', property: 'og:type', 'article' },
        { hid: 'og:title', property: 'og:title', content: 'ページ名' },
        { hid: 'og:description', property: 'og:description', content: 'ページの説明' },
        { hid: 'og:url', property: 'og:url', content: 'https://hogehoge.com/about' },
        { hid: 'og:image', property: 'og:image', content: 'https://hogehoge.com/img/ogp/about.jpg' },
      ],
    }
  }
}
</script>

```

## dataに情報をまとめる
dataに情報をまとめることでogp用のタグのtitleやdescriptionなどを使い回せることができます。

```pages/about.vue
<script>
export default {
  data () {
    return {
      meta: {
        title: 'ページ名',
        keyword: 'キーワード'
        description: 'ページの説明',
        type: 'article',
        url: 'https://hogehoge.com/about',
        image: 'https://hogehoge.com/img/ogp/about.png',
      },
    }
  },
  head: {
    return {
      title: this.meta.title,
      meta: [
        { hid: 'description', name: 'description', this.meta.description },
        { hid: 'keyword', name: 'keyword', this.meta.keyword },
        { hid: 'og:type', property: 'og:type', this.meta.type },
        { hid: 'og:title', property: 'og:title', content: this.meta.title },
        { hid: 'og:description', property: 'og:description', content: this.meta.description },
        { hid: 'og:url', property: 'og:url', content: this.meta.url },
        { hid: 'og:image', property: 'og:image', content: this.meta.image },
      ],
    }
  }
}
</script>
```

## Mixinを作成し共通化する
下層ページに毎回同じことを書くのであればMixin化をすることで使い回せることができます。

### assetsフォルダ内にmixinsフォルダを作成
assetsフォルダにmixinsフォルダを作成します。そのなかにmeta.jsファイルを作ります。
先程作ったhead内のソースをそのままもってきます。

```assets/mixins/meta.js
export default {
  head: {
    return {
      title: this.meta.title,
      meta: [
        { hid: 'description', name: 'description', this.meta.description },
        { hid: 'keyword', name: 'keyword', this.meta.keyword },
        { hid: 'og:type', property: 'og:type', this.meta.type },
        { hid: 'og:title', property: 'og:title', content: this.meta.title },
        { hid: 'og:description', property: 'og:description', content: this.meta.description },
        { hid: 'og:url', property: 'og:url', content: this.meta.url },
        { hid: 'og:image', property: 'og:image', content: this.meta.image },
      ],
    }
  }
}
```

## 下層ページでの使い方
`import Meta from '~/assets/mixins/meta'`をscriptのあとに追加し、
`export default`内に`mixins: [Meta]`を追加します。
`head ()`は削除します、

```pages/about.vue
<template>
  <main>
    <h1>各ページのタイトル</h1>
  </main>

</template>

<script>
import Meta from '~/assets/mixins/meta'

export default {
  mixins: [Meta],
  data () {
    return {
      meta: {
        title: 'ページ名',
        keyword: 'キーワード'
        description: 'ページの説明',
        type: 'article',
        url: 'https://hogehoge.com/about',
        image: 'https://hogehoge.com/img/ogp/about.png',
      },
    }
  }
}
</script>
```

Nuxtでのmixinの使い方にかんしてはこちらの記事を参照
https://note.com/aliz/n/nb87adb4d4810

## 出力されるHTL
`genarate`したときにこんな感じ出力されます。

```index.html
<head>
  <title>ページタイトル</title>
  <meta data-n-head="ssr" charset="utf-8">
  <meta data-n-head="ssr" name="viewport" content="width=device-width,initial-scale=1">
  <meta data-n-head="ssr" data-hid="description" name="description" content="ページの説明">
  <meta data-n-head="ssr" data-hid="keywords" name="keywords" content="キーワード">
  <meta data-n-head="ssr" data-hid="og:type" property="og:type" content="airticle">
  <meta data-n-head="ssr" data-hid="og:url" property="og:url" content="https://hogehoge.com/about">
  <meta data-n-head="ssr" data-hid="og:title" property="og:title" content="ページタイトル">
  <meta data-n-head="ssr" data-hid="og:description" property="og:description" content="ページの説明">
  <meta data-n-head="ssr" data-hid="og:image" property="og:image" content="https://hogehoge.com/img/ogp/about.png">
  <meta data-n-head="ssr" data-hid="twitter:card" name="twitter:card" content="summary_large_image">
  <meta data-n-head="ssr" data-hid="twitter:site" name="twitter:site" content="@ACALL_JP">
　<!-- 省略 -->
</head>

```

以上でNuxt上でhead内にseoで必要なmeta情報を追加する方法でした。