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

nuxt.js(v2)でSEOに必要なmeta(OGP)で入力漏れの事故をなくす

nuxt.js(v2)でSEOに必要なmeta(OGP)を入れたいで、最低限必要なmeta(OGP)をmixinにまとめた。このままでも使えるけど、共通化できるものを整理してつつ入力漏れの事故をなくしたい。

今回の目標

基本情報はnuxt.config.jsで管理する

以下をnuxt.config.jsで管理しつつ、環境変数でいつでも変更できるようにしておく。

  • サイト名
  • 共通のディスクリプション
  • ドメイン
  • ベースディレクトリ
  • OGP画像置き場

下層ページのmeta(OGP)情報未入力時の対応をする

下層ページでmeta(OGP)情報の書き忘れが発生してもいいようにする。全ページ内容を変えるのはSEOにっとて大事。入力しなくても、全ページ違っていてほしい。そもそも、ページURLとか、毎回書かなくてよくない?

ということで、こんな感じを目標に…

タイトル

titleTemplate機能は使わない。

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

ディスクリプション

  • トップページ&未入力 -> 共通ディスクリプション
  • 下層ページ -> ページ個別のディスクリプション
  • 未入力&ページタイトルあり -> {サイト名}サイトの{ページタイトル}ページです。{共通ディスクリプション}

ページタイプ

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

サイトのURLとページURL

  • 絶対パスで入力(自動)

OGP画像URL

OGP置き場のURLは毎回書かなくていいようにしておいた上で、

  • トップページ -> 共通画像への絶対パス
  • 下層ページ -> ページ個別画像への絶対パス
  • 未入力 -> 表示なし

やってきます。

universal(SSR)モードにする!

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

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

環境変数を設定する

環境変数とディフォルト値を設定する。

nuxt.config.js
const baseName = process.env.BASE_NAME || '株式会社アミテン'
const baseDesc = process.env.BASE_DISC || '共通のディスクリプション。得意分野で「ヒトの自立」「ヒトのつながり」を促進する。そんな会社にしたいです。'
const baseUrl = process.env.BASE_URL || 'http://localhost:3000'
const baseOgp = process.env.BASE_OGP || '/lib/img/ogp'
const baseDir = process.env.BASE_DIR || '/'

使い方

MAC
terminal
BASE_URL=https://example.com BASE_DIR=/yourDir/ npm run dev
WIN

※windowsは環境変数の扱い方が違うのでcross-env経由で行う。nuxt.js(v2)系からは、cross-envがはじめから入っている。

terminal
npx cross-env BASE_URL=https://example.com BASE_DIR=/yourDir/ nuxt

よくつかう場合はpackage.jsonに書いておく。

package.json
{
  "scripts": {
    "generate": "nuxt generate",
    "generate:production": "cross-env BASE_URL=https://example.com BASE_DIR=/yourDir/ nuxt generate",
    ...
  },
}
terminal
npm run generate:production

OK。

どこでも使えるようにする

nuxt.config.jsのrouterプロパティのbaseにbaesDirを登録する。あとの項目は、envプロパティに登録。これで、バックエンド・フロントエンドともにどこからでも使えるようになる。

nuxt.config.js
const baseName = process.env.BASE_NAME || '株式会社アミテン'
const baseDesc = process.env.BASE_DISC || '共通のディスクリプション。共通のディスクリプション。得意分野で「ヒトの自立」「ヒトのつながり」を促進する。そんな会社にしたいです。'
const baseUrl = process.env.BASE_URL || 'http://localhost:3000'
const baseOgp = process.env.BASE_OGP || '/lib/img/ogp'
const baseDir = process.env.BASE_DIR || '/'

module.exports = {
  mode: 'universal',
  env: {
    baseName: baseName,
    baseDesc: baseDesc,
    baseUrl: baseUrl,
    baseOgp: baseOgp,
  },
  router: {
    base: baseDir,
  },
  ...
}

contextかprocessを経由してどこからでも使えるようになった。試しに使ってみる。

index.vue
<template lang="pug">
.main
  p context経由でアクセス:{{test1}}
  p process経由でアクセス:{{test2}}
  p おまけ(router.base取得):{{test3}}
</template>

<script>
export default {
  asyncData (context) {
    console.log(context)
    return {
      test1: context.env.baseName,
      test2: process.env.baseDesc,
      test3: context.base,
    }
  },
}
</script>

Good!基本情報をnuxt.config.jsで管理できるようになりました。

nuxt.config.jsにheadを追加

nuxt.config.jsにhead情報を追加していく。早速、さっき設定したbaseセットを利用する。
本来は、CDNの読み込みやicon関連なども入ってくるが、今回はSEOに関連するmeta(OGP)のみ記載。

nuxt.config.js
const baseName = process.env.BASE_NAME || '株式会社アミテン'
const baseDesc = process.env.BASE_DISC || '共通のディスクリプション。共通のディスクリプション。得意分野で「ヒトの自立」「ヒトのつながり」を促進する。そんな会社にしたいです。'
const baseUrl = process.env.BASE_URL || 'http://localhost:3000'
const baseOgp = process.env.BASE_OGP || '/lib/img/ogp'
const baseDir = process.env.BASE_DIR || '/'

module.exports = {
  mode: 'universal',
  env: {
    baseName: baseName,
    baseDesc: baseDesc,
    baseUrl: baseUrl,
    baseOgp: baseOgp,
  },
  router: {
    base: baseDir,
  },
  ...
  head: { // 以下を追加
    htmlAttrs: {
      prefix: 'og: http://ogp.me/ns#'
    },
    title: baseName,
    meta: [
      { hid: 'description', name: 'description', content: baseDesc },
      { hid: 'og:site_name', property: 'og:site_name', content: baseName },
      { hid: 'og:type', property: 'og:type', content: 'article' },
      { hid: 'og:url', property: 'og:url', content: baseUrl },
      { hid: 'og:title', property: 'og:title', content: baseName },
      { hid: 'og:description', property: 'og:description', content: baseDesc },
      { hid: 'og:image', property: 'og:image', content: `${baseOgp}/common.jpg` },
      // { property: 'article:publisher', content: 'FacebookURL' },
      // { property: 'fb:app_id', content: 'FacebookAppID' },
      // { name: 'twitter:card', content: 'summary' },
      // { name: 'twitter:site', content: '@Twitter' },
    ],
    ...
  },
}

OK。環境変数で指定した内容もバッチリ反映される。

本題

下層ページのmeta(OGP)情報未入力時の対応をしていく。
まずは、mixinファイルをカスタマイズ。

assets/mixins/meta.js
export default {
  asyncData (context) {
    return {
      baseName: context.env.baseName,
      baseDesc: context.env.baseDesc,
      baseUrl: context.env.baseUrl,
      baseOgp: context.env.baseOgp,
    }
  },
  head () {
    const head = { meta: [] }

    // タイトル
    if (this.meta.title) {
      const title = `${this.meta.title} - ${this.baseName}`
      head.title = title
      head.meta.push({ hid: 'og:title', property: 'og:title', content: title })
    }

    // ディスクリプション
    if (this.meta.description) {
      head.meta.push({ hid: 'description', name: 'description', content: this.meta.description })
      head.meta.push({ hid: 'og:description', property: 'og:description', content: this.meta.description })
    } else if (!this.meta.description && this.meta.title) {
      const disc = `${this.baseName}サイトの${this.meta.title}ページです。${this.baseDesc}`
      head.meta.push({ hid: 'description', name: 'description', content: disc })
      head.meta.push({ hid: 'og:description', property: 'og:description', content: disc })
    }

    // ページタイプ
    if (this.meta.type) {
      head.meta.push({ hid: 'og:type', property: 'og:type', content: this.meta.type })
    } else if (this.$route.path === '/') {
      head.meta.push({ hid: 'og:type', property: 'og:type', content: 'website' })
    }

    // ページURL
    const url = `${this.baseUrl}${this.$router.history.base}${this.$route.path}`
    head.meta.push({ hid: 'og:url', property: 'og:url', content: url })

    // OGP画像URL
    if (this.meta.image) {
      const imageUrl = `${this.baseUrl}${this.$router.history.base}${this.baseOgp}${this.meta.image}`
      head.meta.push({ hid: 'og:image', property: 'og:image', content: imageUrl })
    }

    return head
  }
}

これで、index.vueでは何も設定しなくて良くなった。
変更したかったら、head()を使って修正すればよい。

index.vue
<template lang="pug">
.main
  nuxt-link(to="/test") goto testPage
</template>

<script>
export default {
  // head () {
  //   return {
  //     titleTemplate: null.
  //     title: 'すごくかっこいいサイト名をつかったタイトル'
  //   }
  // }
}
</script>

からの、下層ページでは、mixinを利用する。

pages/test.vue
<template lang="pug">
.main
  nuxt-link(to="/") goto top
</template>

<script>
import Meta from '~/assets/mixins/meta' // ←追加
export default {
  mixins: [Meta], // ←追加
  data () {
    return {
      meta: {
        title: 'Test-Page!', // ←未入力も対応
        description: 'ページ個別のディスクリプション', // ←未入力も対応
        type: 'article', // ←未入力も対応
        image: '/test.jpg', // ←OGP画像置き場からのURLだけでOK、未入力も対応
      },
    }
  },
}
</script>

極端な話、titleだけでも大丈夫。

pages/ex.vue
<template lang="pug">
.main
  nuxt-link(to="/") goto top
</template>

<script>
import Meta from '~/assets/mixins/meta'
export default {
  mixins: [Meta],
  data () {
    return {
      meta: {
        title: 'サンプルページ', // ←これだけでもなんとかなる。
      },
    }
  },
}
</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-n-head="true" data-hid="og:type" property="og:type" content="artice">
  <meta data-n-head="true" data-hid="og:image" property="og:image" content="/lib/img/ogp/common.jpg">
  <meta data-hid="og:title" property="og:title" content="サンプルページ - 株式会社アミテン" data-n-head="true">
  <meta data-hid="description" name="description" content="株式会社アミテンサイトのサンプルページページです。共通のディスクリプション。得意分野で「ヒトの自立」「ヒトのつながり」を促進する。そんな会社にしたいです。" 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="http://localhost:3000/ex" data-n-head="true">
</head>

入力漏れの事故がなくなりました。\(^o^)/

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