Nuxt3でCanonical URLをlayoutで設定する

掲載日

はじめに

Canonical(カノニカル) URLは複数のパス(URL)でアクセスできるページで、どれが主たるURLかを指定するmetaタグです。

これがないと、GoogleなどのクローラーはわざわざURLをすべて見に行ってくれている?等、そこまで重要じゃないけどよろしくはない状態になります。
(Googleのクローラーは賢いので、重複は重複として扱ってくれてるので検索エンジンに同じページが2つも3つも載るということはないみたいですが。)
今回はNuxt3でそのCanonical URLを設定しようとしたら意外とハマったので解決までの備忘録です。

結論

layoutsディレクトリ配下の、Canonical URLを設定したいファイルにこれで多分OKです。

const route = useRoute()
const url = useRequestURL()
const getCanonicalPath = (path: string) => {
    if (path.endsWith('/')) {
        path = path.slice(0, -1)
    }
    const baseUrl = url.protocol + '//' + url.host
    return baseUrl + path
}
useHead(() => ({
    link: [
        {
            rel: 'canonical',
            href: getCanonicalPath(route.path),
        },
    ],
}))

解決までの流れ

Nuxt3でcanonicalを設定しようとしたとき、まず考えられるのがlayoutsディレクトリ配下に以下のような感じで配置することです。

素直にuseHeadへの記載

useHead({
    link: [
        {
            rel: 'canonical',
            href: 'https://example.com' + useRoute().path,
        },
    ],
});

これは上手くいきません。
最初にアクセスしたURLがcanonicalには設定され、その後ページ遷移しても設定値は変わりません。
(最初 https://example.com  にアクセスして、その後 https://example.com/hoge  にアクセスしてもcanonicalは https://example.com  のままになります。)
ちょっとNuxtのライフサイクルへの理解が怪しいので、あってるか自信がありませんが、layouts内の内容は最初にレンダリングされてその後は同じ内容を使いまわすようになっているので、そうなるのだと思います。
(titleTemplate等例外はありますが。)

引数を関数で書く

ここでStackOverflowで海外ニキのドンピシャ質問とドンピシャ回答を見つけます。

const route = useRoute()
useHead(() => ({
  link: [
    {
      rel: 'canonical',
      href: 'https://example.com' + route.path,
    },
  ],
}))

理屈が書かれていないので私のような人間には何故こうなっているのかきちんとわかってませんが、
同じくuseHeadの titleTemplate と同じような仕組み(こちらも動的にタイトルタグを設定できる)なのかなと思ってます。

これで解決かと思いましたが、今度は Googleサーチコンソールに「ページが重複しているよ」と言われ、URL末尾に「/」(スラッシュ)つけるかつけないか問題を発見します。
(以下のようなURLで違うURLで同じページに遷移できてしまい、かつカノニカルも別々になっていました。)

設定時に末尾にスラッシュがあるか見て除去する関数をかませる

ここまで来たらもう解説は不要かもしれませんが、URLを見て末尾にスラッシュがあるかをendWith関数で判断し、除去する(自分はこっちを採用)。もしくはスラッシュが存在しなければスラッシュを付与する。のどちらかの処理を行ってからカノニカルを設定するだけでOKです。結論のコードに戻ります。

所感

Canonical URLを共通の処理で設定するだけなのですが、意外とハマってしまったので備忘録として残しておきます。

記事の作成者のA.W.のアイコン

この記事を書いた人

A.W.
茨城県在住Webエンジニアです。 PHPなどを業務で使用しています。 趣味ではGoやNuxt、Flutterをやってます。

Comment