📌

Nuxt3でOGPを定義する

2023/01/11に公開

Nuxt3でOGPを設定する方法

以前自分のサイトをVuePressからNuxt3に変更しましたが、Vue3自体の理解の低さなどもあり
OGPの設定を行うのに非常に手間取ってしまったのとNuxt3向けの解説がそこまでなかったので備忘録的にまとめておきます。

最終的なコードから解説

細かい説明などは省いて、設定するためのコードの書き方を中心にまとめます。
用語の説明などがない部分もありますが、基本的にNuxt3の初期設定ぐらいは分かってVueもなんとなく触ったことがあるぐらいの人を想定して記載しています。
分かりづらい箇所などありましたらコメントなどでお知らせください。

サイト共通かつ静的な値はnuxt.config.tsに記載

まずは、サイト全体で共通の項目をnuxt.config.tsに設定します。
ここで指定した値はApp.vuepages/**/*.vuelayout/**/*.vueで上書きされるようで、フォールバック的に他の項目を設定しておいても問題ありません。
一方でnuxt.config.tsには動的な値が設定できないため、あくまでこちらに記載するのはサイト全体で共通の静的な項目のみとなります。

  1. htmlタグにprefixを追加
  2. og:typewebsiteに指定
  3. og:site_nameにサイト名を指定
  4. og:imageに画像を絶対パスで指定
nuxt.config.ts
export default defineNuxtConfig({
// ...
app: {
  head: {
    htmlAttrs: {
      lang: 'ja', prefix: 'og: https://ogp.me/ns#'
    },
    meta: [
      { property: 'og:type', content: 'website' },
      { property: 'og:site_name', content: '<サイト名>' },
      { property: 'og:image', content: '<ogpに使われる画像の絶対パス>', },
    ]
  }
}
// ...
});

動的な値の設定はApp.vueで指定

og:urlなどのページごとに異なるが動的に指定可能なものに関してはApp.vueに指定を行います。
layoutが1つしかない場合はlayout/default.vueに設定しても同じように動作します。

App.vue
<script lang="ts" setup>
import { computed } from '#imports';
import { useHead, useRouter } from '#app';

const router = useRouter();
const currentPath = computed(
  () => `https://example.com${router.currentRoute.value.path}`
);

useHead({
  meta: [
    { property: 'og:url', content: currentPath }
  ],
});
</script>

useHead

useHeadは各種コンポーネントから直接<head>を設定できる関数で、この場合は<meta>の追加・上書きに使用しています。

computed

絶対パスを取得するcurrentPathの指定方法ですが、computedを利用しています。
この値はuseRouterを利用して現在のパスを取得していますがcomputedを使用しないと再計算が行われないため指定しています。

`import.meta`を使用する場合の注意点

SSRの場合new URL(import.meta.url)を利用してprotocolhostを取得できますが、この指定をする場合URLはクライアント側のJSで解決されるためOGPのクローラーが正しく読み取れない場合があります。
そのため各種環境ごとにURLを変更したい場合は.env経由で指定するなどビルド時に解決される方法を選択する必要がありそうです。

余談ですが個人的にVue3を使用していて一番混乱したのがこのcomputedの指定方法でした、reactstatepropsのように再計算を行わないため明示的に更新の指示を行う必要があるようです。

ページ固有のものはpages/**/*.vueで指定

最後にページ固有かつ静的な項目はぞれぞれページごとにuseHeadを使用して指定を行います。
og:descriptionについては指定必須ではありませんが設定する場合はpagesで指定するのが適切だと思います。

pages/**/*.vue
<script lang="ts" setup>
import { useHead } from "#app";

useHead({
  title: '<ページタイトル>',
  meta: [
    { property: 'og:title', content: '<ページタイトルを記載>' },
    { property: 'og:description', content: '<descriptionを記載>' }
  ]
});
</script>

動的ルーティングを使用している場合

nuxt/contentなどを使用している場合は動的ルーティングを行っている場合があると思いますがpagesにおいてもApp.vueのように動的な指定が可能です。

下記はnuxt/contentを使用している場合です。

[...slug].vue
<script lang="ts" setup>
import { useHead, useRoute } from '#app';
import { queryContent } from '#imports';

const route = useRoute();
const content = await queryContent(route.fullPath).findOne();

useHead({
  meta: [
    { property: 'og:title', content: content.title },
    { property: 'og:type', content: 'article' },
  ],
});
</script>
  1. useRouteで現在のパスを取得
  2. 現在のパスからqueryContentでmarkdownのコンテンツを取得
  3. content.titleでタイトルを取得

また、記事コンテンツの場合はog:typearticleに指定します。

まとめ

自分の環境では上記の設定でTwitterでのOGP表示が行えるようになりました。

https://dairoku-studio.com

https://github.com/ken7253/d6

GitHubで編集を提案

Discussion