Help us understand the problem. What is going on with this article?

nuxt.js(v2)でSEOに必要なmeta(OGP)を入れたい

初のアドベントカレンダー参加。こんな内容でいいのかなと思いつつ…nuxt.jsにSEOに必要なmeta(OGP)タグを入れていきます。

SEOに必要なmeta(OGP)タグを入れたい

nuxt.jsでは、metaタグのコントロールにvue-metaが使われている。これ、ページ数が増えるとめんどくさい記入漏れなどのミスが起こる。なので、最低限必要なmeta(OGP)をフォーマット化しておく。あとから仕様を変更できればなおよし。

今回の目標

The Open Graph protocolを参考にしつつ、meta(OGP)を以下のようにしたい。(icon関連はPWAの設定と一緒にやるので今回は保留。)

最低限のmeta(OGP)
<html prefix="og: http://ogp.me/ns#">
<head>
  <!-- title/description -->
  <title>タイトル</title>
  <meta name="description" 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" /> 

  <!-- FB/twitter ※必要ならば以下追加-->
  <!-- meta property="article:publisher" content="FacebookURL" -->
  <!-- meta property="fb:app_id" content="FacebookAppID" -->
  <!-- meta name="twitter:card" content="summary_large_image" -->
  <!-- meta name="twitter:site" content="@Twitter" -->
  ...
</head>

meta(OGP)の仕様

当たり前のことを、一度書き出す。

タイトル

  • トップページ -> サイト名
  • 下層ページ -> ページタイトル - サイト名

ディスクリプション

  • トップページ -> 共通ディスクリプション
  • 下層ページ -> ページ個別のディスクリプション

ページタイプ

  • トップページ -> website
  • 下層ページ -> artice

サイトのURLとページURL

  • 絶対パスで入力

OGP画像URL

  • トップページ -> 共通画像への絶対パス
  • 下層ページ -> ページ個別画像への絶対パス

ということで、試していく。

universal(SSR)モードにする!

まずは、universal(SSR)モードにする。generateする場合でもuniversal(SSR)モードにする。(大事なことなので2回言う。)
SPAモードは(たとえgenerateしたとしても)ページ毎のmeta(OGP)が反映されない。

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

公式ドキュメントを参考にベースを作成

nuxt.jsの公式ドキュメントと、vue-metaの公式ドキュメントを参考にベース部分を作成。小規模のサイトならこれだけでもOK。

nuxt.config.js

nuxt.config.jsにheadを追加。本来は、CDNの読み込みやicon関連なども入ってくるが、今回はSEOに関連するmeta(OGP)のみ記載。

nuxt.config.js
module.exports = {
  head: {
    htmlAttrs: {
      prefix: 'og: http://ogp.me/ns#'
    },
    titleTemplate: '%s - サイト名',
    meta: [
      { hid: 'description', name: 'description', content: '共通ディスクリプション' },
      { hid: 'og:site_name', property: 'og:site_name', content: 'サイト名' },
      { hid: 'og:type', property: 'og:type', content: 'website' },
      { hid: 'og:url', property: 'og:url', content: 'https://example.com' },
      { hid: 'og:title', property: 'og:title', content: 'サイト名' },
      { hid: 'og:description', property: 'og:description', content: '共通ディスクリプション' },
      { hid: 'og:image', property: 'og:image', content: 'https://example.com/img/ogp/common.jpg' },
      // { property: 'article:publisher', content: 'FacebookURL' },
      // { property: 'fb:app_id', content: 'FacebookAppID' },
      // { name: 'twitter:card', content: 'summary' },
      // { name: 'twitter:site', content: '@Twitter' },
      ...
    ],
  },
}

pagesファイル(トップページ)

トップページでは、titleTemplateの機能をnullにしつつ、サイト名のみ表示されるようにする。

pages/index.vue
<template lang="pug">
.main
  h1 サイト名
  nuxt-link(to="/test") go to Test-Page
</template>

<script>
export default {
  head () {
    return {
      titleTemplate: null,
      title: 'サイト名',
    }
  },
}
</script>

pagesファイル(トップページ以外)

下層ページでは、titleTemplateの機能を使いタイトルを表示。また、各種metaタグの内容を変える。

pages/test.vue
<template lang="pug">
.main
  h1 {{ meta.title }}
  nuxt-link(to="/") go to HOME
</template>

<script>
export default {
  data () {
    return {
      meta: {
        title: 'Test-Page!',
        description: 'ページ個別のディスクリプション',
        type: 'article',
        url: 'https://example.com/test',
        image: 'https://example.com/img/ogp/test.jpg',
      },
    }
  },
  head () {
    return {
      title: this.meta.title,
      meta: [
        { hid: 'description', name: 'description', content: this.meta.description },
        { hid: 'og:type', property: 'og:type', content: 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>

結果

/
<html prefix="og: http://ogp.me/ns#" data-n-head="prefix">
  <head>
    <title data-n-head="true">サイト名</title>
    <meta data-n-head="true" data-hid="og:site_name" property="og:site_name" content="サイト名">
    ...
    <meta data-hid="description" name="description" content="共通ディスクリプション" data-n-head="true">
    <meta data-hid="og:type" property="og:type" content="website" data-n-head="true">
    <meta data-hid="og:url" property="og:url" content="https://example.com" data-n-head="true">
    <meta data-hid="og:title" property="og:title" content="サイト名" data-n-head="true">
    <meta data-hid="og:description" property="og:description" content="共通ディスクリプション" data-n-head="true">
    <meta data-hid="og:image" property="og:image" content="https://example.com/img/ogp/common.jpg" data-n-head="true">
  </head>
/test
<html prefix="og: http://ogp.me/ns#" data-n-head="prefix">
  <head>
    <title data-n-head="true">Test-Page! - サイト名</title>
    <meta data-n-head="true" data-hid="og:site_name" property="og:site_name" content="サイト名">
    ...
    <meta data-hid="description" name="description" content="ページ個別のディスクリプション" data-n-head="true">
    <meta data-hid="og:type" property="og:type" content="article" data-n-head="true">
    <meta data-hid="og:title" property="og:title" content="Test-Page!" data-n-head="true">
    <meta data-hid="og:description" property="og:description" content="ページ個別のディスクリプション" data-n-head="true">
    <meta data-hid="og:url" property="og:url" content="https://example.com/test" data-n-head="true">
    <meta data-hid="og:image" property="og:image" content="https://example.com/img/ogp/test.jpg" data-n-head="true">
  </head>

いい感じ。generateで生成されたhtmlファイルにも反映されている。

何度も書く場所をmixin化

test.vueへ書いたhead () {...}の部分。めんどくさいのでミス軽減のためmixinで共通化する。

mixinファイル作成

mixinファイルを作成して、head () {...}をごそっと移植。

assets/mixins/meta.js
export default {
  head () {
    return {
      title: this.meta.title,
      meta: [
        { hid: 'description', name: 'description', content: this.meta.description },
        { hid: 'og:type', property: 'og:type', content: 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 },
      ],
    }
  }
}

pagesファイル(トップページ)

トップページとなるindex.vueはそのままで問題ない。

pagesファイル(トップページ以外)

下層ページに、mixins: [Head]を追加していく。mixinファイルをimportするのを忘れずに。

test.vue
<template lang="pug">
...
</template>

<script>
import Meta from '~/assets/mixins/meta' // ←追加
export default {
  mixins: [Meta], // ←追加
  data () {
    return {
      meta: {
        title: 'Test-Page!',
        description: 'ページ個別のディスクリプション',
        type: 'article',
        url: 'https://example.com/test',
        image: 'https://example.com/img/ogp/test.jpg',
      },
    }
  },
  // ←`head ()`は削除。
}
</script>

GOOD!generateで生成されたhtmlも大丈夫。
mixin化が出来たので、あとは好みで使いやすいようにカスタマイズすればいい。


第2段、nuxt.js(v2)でSEOに必要なmeta(OGP)で入力漏れの事故をなくす。書きました。

Link

以下、公開中のnuxt.js(v2)関連の記事一覧

技術よりの記事

  1. nuxt.js(v2)のインストール〜ESLint設定まで
  2. nuxt.js(v2)の作業ディレクトリを整理
  3. nuxt.js(v2)のベースURLをターミナルからコントロール
  4. nuxt.js(v2)でpug/stylusを利用する
  5. nuxt.js(v2)でIE11対応をする(CSS編)
  6. nuxt.js(v2)でIE11対応をする(JS編)
  7. nuxt.js(v2)で絶対パス(https~)を取得する方法
  8. nuxt.js(v2)でSEOに必要なmeta(OGP)を入れたい
  9. nuxt.js(v2)でSEOに必要なmeta(OGP)で入力漏れの事故をなくす

よく使うプラグインのお話

  1. nuxt.js(v2)で便利なvue-mqを使ってみるがSSRモードでコンソールエラーがでるので確認してみた。
  2. nuxt-linkでスムーズスクロールするならvue-scrolltoが便利で気が利いている…と思う。
  3. nuxt.jsでパララックスをするならvue-parallax-jsがお手軽。Cool!

まとめ系

  1. nuxt.js(v2)でgenerate納品する前にやっておきたい設定
  2. nuxt.jsにおける「components」ディレクトリの規約(案)
Why do not you register as a user and use Qiita more conveniently?
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away
Comments
Sign up for free and join this conversation.
If you already have a Qiita account
Why do not you register as a user and use Qiita more conveniently?
You need to log in to use this function. Qiita can be used more conveniently after logging in.
You seem to be reading articles frequently this month. Qiita can be used more conveniently after logging in.
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away