初心者がNuxt.jsでcanonical設定しようとしたら死ぬほどハマった件

シェアする:

この記事をおすすめしたい人

  • WordPressしか知らないのにNuxt.jsを始めようとしてる人
  • Nuxt.jsでcanonicalの設定を追加したい人
  • つまりオレ

何も知らない超初心者が脱WordPressしたくてNuxt.jsでサイト構築していくシリーズです。

今回はhead内に「canonical」の設定を追加していきたいと思います。

死ぬほどハマりました。

もうNuxt.jsを覚えていくプロジェクト自体なかったことにしたろうかと思うほどに…。

たった1行のHTMLコードの追加にもがき苦しんだ様をお届けしたいと思います!

WordPressの上でな!

※ このブログはWordPress製です

canonicalの意味をおさらい

canonicalというのはですね、HTMLのソースコードのheadタグ内に次のように入れるやつです。


<link rel="canonical" href="https://dev.ore-shika.com/">

canonicalは「正規の」という意味らしく、「このページの正しいURLはこれですよー」とブラウザや検索エンジンに教えてあげるためのLINKタグです。

GoogleのSearch Consoleでも「ユーザーが指定した正規 URL」「Google が選択した正規 URL」という項目があるので、SEO上も大事な情報なんでしょう。

Nuxt.jsでcanonicalはどこに指定するのか

読み込まれるファイルならけっこうどこでもいけそうです。

nuxt.config.js、index.vue、Layoutなど。 僕は最終的にデフォルトのLayoutに入れました。

効率的にcanonicalを指定するにはどこに書くべきか

canonicalはページ毎に必要な情報です。

理想としては、共通で読み込まれるファイルに設定しておいて、ページが生成されると自動でそのページのURLをcanonicalに設定。

なので各ページのファイル(index.vueなど)に指定するのは効率が悪いでしょう。

nuxt.config.jsは全ページで必ず読み込まれるだろうし、既にLINKタグの設定項目もあったので良さそうです。

次点でLayout。 Layoutを複数使い回すようなケースだと同じルーチンが複数のファイルにまたがるので、そこがちょっと微妙。
(プラグイン機能で回避できる?)

nuxt.config.jsにcanonicalを書き足してみた

デフォルトのnuxt.config.jsに既にLINKタグの設定があったので真似して追加してみます。


{ rel: 'icon', type: 'image/x-icon', href: '/favicon.ico' },

canonicalを追加↓。


{ rel: 'icon', type: 'image/x-icon', href: '/favicon.ico' },
{ rel: 'canonical', href: 'https://dev.ore-shika.com/' },

エラーなく無事にビルドされました。

出力されたHTMLにもちゃんとcanonicalが確認できます。


<link rel="canonical" href="https://dev.ore-shika.com/">

次は現在のURLを取得

次のような流れを考えてます。

  1. 現在のページの相対パスを取得(/test/など)
  2. 最終的なドメインのURL(https://dev.ore-shika.com/)
  3. 両者を連結してcanonicalのURLとする

Nuxt.jsではベースとなっているVue.jsのVue-routerというモジュールを使ってURLを生成しているようなので、次↓のように書けば上の①(/test/など)が取得できるそうです。


this.$route.path

なので、この↓ように書けば期待通りに動くはず。


{ rel: 'canonical', href: (トップページのURL) + this.$route.path },

結果…

(クリックで拡大)

プロパティ「path」が未定義ですよ、ってことですかね。

そんなアホな!

ちょこちょこいじくり回してみましたが、よく分からず、とりあえずindex.vue内で本当にこのプロパティにアクセスできるのか確認してみました。


<template>
(略)
{{ this.$route.path }}
(略)
</template>

中括弧が2つくっついてますが、templateタグ内で変数を出力する時はこうするそうです。

結果、トップページの場合は「/」が、テストページの場合は「/test/」が出力されました。 問題なさそうです。

ということはnuxt.config.jsがロードされる時点では「path」が未定義で、HTMLが出力される段階では定義されているとか、そういう問題でしょうきっと。

index.vue内に書き足してみた

nuxt.config.jsは名前からして設定ファイルですからね。 そりゃ早い段階で読み込まれるんでしょうよ。

index.vueに書けば大丈夫だろうと、nuxt.config.jsの書き方を真似て「export default」内に書き足してみます。


<script>

export default {
  (略)
  head: {
    link: [
      { rel: 'canonical', href: (トップページのURL) + this.$route.path },
    ]
  },
  (略)
}

</script>

結果…。


Cannot read property '$route' of undefined

今度は「path」どころか、その親の「$route」が未定義だと…。

ネットで「Nuxt.js canonical」で検索

ネットで検索すればすぐだと思ったんですよ。 僕みたいなポンコツ向けに書いてくれてる記事が絶対あると思いました。

ところが、どうも検索結果が思った感じじゃない。

調べども調べども、何がどうなっているのかさっぱり分からず…。

たった1行canonical追加するだけなのに丸一日潰してしまいました。

結論、headプロパティではなくheadメソッドを使う

Nuxt.js公式のマニュアルを読んでいるとこんな↓注意書きがありました。

コンポーネントの関数として head を使うこともでき、this を経由してコンポーネントのデータにアクセスできます。

この「関数としてのhead」というのがheadメソッドというやつです。 これまでの書き方は全てheadプロパティという方法になっていたようです。

つまりどういうことかというと、

「this」からデータにアクセスしたいならheadメソッドの方を使いなさいよ

ということらしい。

さっそく書き直してみたのがコレ↓。


<script>

export default {
  head () {
    return {
      link: [
        { rel: 'canonical', href: (トップページのURL) + `${this.$route.path}` },
      ],
    }
  },
}

</script>

元のコレ↓に比べると、


<script>

export default {
  head: {
    link: [
      { rel: 'canonical', href: (トップページのURL) + this.$route.path },
    ]
  },
}

</script>

メソッドというだけあって、何やら関数っぽい書き方になっています。

ここから先は推論ですが、headプロパティの方はファイル読み込み時に変数を展開しようとするので未定義エラーが出て、headメソッドは実行時に展開するのでその頃には変数が定義されている、みたいな感じなんでしょうか。

とにかく動いてよかったです…。

nuxt.config.jsにcanonicalを追加する場合の注意点

canonicalは全ページで出力してほしいので、必ず読み込まれる「nuxt.config.js」に書いておきたいです。

レイアウトでもいいですが、default.vue以外のレイアウトも使用する場合、複数のレイアウトに同じコードを書かなければなりません。 なのでnuxt.config.jsに書くのがベスト(のはず)。

nuxt.config.jsに追記する場合、headプロパティは既にあるのでこの↓ようにheadメソッドを追加したくなりますが…。


export default {
  head: {
    (略)
  },
  head () {
    return {
      link: [
        { rel: 'canonical', href: (トップページのURL) + `${this.$route.path}` },
      ],
    }
  },
}

この書き方をすると、プロパティで設定した全内容(canonicalも含めて全て)を破棄した後、メソッドで設定した内容(canonicalのみ)が反映されてしまいます。
(titleもfaviconも出力されない)

なので、nuxt.config.jsでcanonicalの自動取得をする場合は、既にあるheadプロパティの設定をheadメソッドの方に全て移してやらないといけません。


export default {
  head () {
    return {
      title: (タイトル名),
      meta: [
        { name: 'description', content: (ページの説明) },
        { rel: 'canonical', href: (トップページのURL) + `${this.$route.path}` },
      ]
    }
  }
}

canonical用のモジュールを使う

こんな便利なもんがあったんかいっ!!

というわけでcanonical出力用のモジュールの紹介です。

チョー簡単、チョー楽勝です。

まずはインストール!


$ npm i nuxt-canonical

インストールが終わったら「nuxt.config.js」を開きます。 modulesプロパティに以下の内容を追加。


export default {
  modules: [
    ['nuxt-canonical', { baseUrl: 'https://dev.ore-shika.com' }],
  ],
}

「https://dev.ore-shika.com」の部分は自分のサイトのトップページのURLに読み替えてください。

たったこれだけ!!

これで全ページ自動でcanonicalが出力されるようになります。

ストレスフルだったオレの1日を返せっ!

注意点①:URLは末尾のスラッシュ不要

上の例では「https://dev.ore-shika.com」になっているトップページのURL部分ですが、末尾のスラッシュを付けていません。

「baseUrl」と連結しているであろう「this.$route.path」はスラッシュから始まる(トップページなら「/」)ので、末尾スラッシュがあると「https://dev.ore-shika.com//」と出力されてしまうからです。

注意点②:「npm run dev」上では表示されない

「all generated pages」と説明がある通り、「npm run dev」の開発モードではcanonicalが出力されません。

ビルドしたページでのみ表示されます。

注意点③:OGPの「og:url」も設定する場合は別途設定が必要

「nuxt-canonical」というモジュールは名前の通り「Nuxt.jsでcanonicalを出力するためだけのモジュール」です。

なのでcanonicalと同時にOGPの「og:url」を設定したい場合はそちら用に結局自分でURLを取得する必要が出てきます。

まぁもしかするとOGP用のモジュールもあるのかもしれませんが今回は調べていません。

静的HTMLに出力したらエラーが出た…

「npm run dev」でテスト中はここに載せたやり方でうまくいっていたのですが、「export」するとこの↓ようなエラーが…。


TypeError: Cannot read property 'path' of undefined

まーたpathが未定義ですよと。

オレは一体どれだけcanonicalに悩まされるのか…。

とりあえずdevモードではちゃんと動いているので、エラーが発生した時だけ別処理にしようと例外処理の格好にしてみました。


//baseUrl(トップのURL)で初期化
var url = baseUrl// + this.$route.path

try {
  url = baseUrl + this.$route.path
} catch (e) {
  //エラーが出た場合の処理
}

何故かこれでうまくいきました…。

「エラーが出た場合の処理」のところは何もしてません。 tryで囲むだけで期待通りの動作になったんです。

何故だ…。

エラーが出ていたのは200.html

静的HTMLを出力すると「200.html」というファイルが作られます。

Nuxt.js公式サイトによるとどうも404のことらしい。
(404にアクセスしてもこのページが表示されないのでたぶんちょっと違う)

つまり、404だとURLなんかあるわけないので「$route」が未定義でエラーが出ていたわけです。

tryで囲むとエラーは起きているけど、エラーが起きたのが200.htmlだったため、一見うまくいったように見えていただけでした。

というわけで、「$route」が定義済みの場合だけcanonicalを追加するように変更します。


export default {
  head () {
    const baseUrl = (サイトURL)
    
    var link = [
      { rel: 'icon', type: 'image/x-icon', href: '/favicon.ico' },
    ]
    
    if ( this.$route != null ) {
      var url = baseUrl + this.$route.path
      
      link.push( { rel: 'canonical', href: url } )
    }
    
    return {
      htmlAttrs: {
        lang: 'ja',
      },
      title: (ページタイトル),
      meta: [
        (略)
      ],
      link
    }
  },
}
  1. headメソッド内で先に変数としてlinkプロパティを作成。
  2. $routeが定義済みだった場合は、URLを生成してcanonicalを追加。
  3. 戻り値に作成済みのlinkプロパティを指定。

のような格好です。

これで200.htmlではcanonicalが追加されなくなり、export時のエラーも消えました。

が…。

依然静的出力したサイトでの404はサーバ側の404ページが表示されており、devモードではcanonicalが出力されています(404でも$routeが定義されているため)。

この辺りは404の仕組みを勉強してから改めて解決したいと思います。

末尾に「/」がない

静的出力したcanonicalを見ると末尾に「/」がありません。

Nuxt.jsの解説見ているとそんなもんらしいんですが、個人的には末尾にスラッシュがないとなんか気持ち悪いです。

なので、URL末尾にスラッシュを追加してみます。


export default {
  head () {
    const baseUrl = (サイトURL)
    
    var link = [
      { rel: 'icon', type: 'image/x-icon', href: '/favicon.ico' },
    ]
    
    if ( this.$route != null ) {
      var url = baseUrl + this.$route.path
      
      if ( url.slice(-1) != '/' ) {
        url += '/'
      }
      
      link.push( { rel: 'canonical', href: url } )
    }
    
    return {
      htmlAttrs: {
        lang: 'ja',
      },
      title: (ページタイトル),
      meta: [
        (略)
      ],
      link
    }
  },
}

自分で作るリンクでは末尾「/」になっているので、その場合にスラッシュが重複しないよう、「末尾がスラッシュでなければ」という条件付けをしています。

まとめ

Nuxt.jsでcanonicalを自動設定する場合は「headプロパティ」ではなく「headメソッド」を使います。


export default {
  head () {
    return {
      link: [
        { rel: 'canonical', href: (トップページのURL) + `${this.$route.path}` },
      ],
    }
  },
}

nuxt.config.jsに設定を追加するなど、既にheadプロパティがある場合は、プロパティの内容を全てメソッド側に移植する必要があります。

「nuxt-canonical」というモジュールを使うと導入・設定はめちゃくちゃ簡単になりますが、「og:url」など他にURLを使う場合にはひと手間必要です。

以上、WordPressからお届けしました!

Nuxt.js HEADタグ操作編の目次

シェアする: