Nuxt3でContentfulを使用する方法

nuxt3-contentful

2023.04.10

2023.04.17

ContentfulにてAPI keyを発行する

Contentful自体の登録方法については割愛します。
Settings > API keysからAPIsページに遷移し、Add API keyを押下する。

説明画像1 説明画像2

Nameに任意の名前を入力してSaveを押下します。
青枠で囲まれている部分の値は初めから入力されています。

Space ID:スペースID。
Content Delivery API:本番用APIトークン。公開状態(Published)のEntryのみが取得対象となります。
Content Preview API:プレビュー用APIトークン。下書き状態(Draft)のEntryも含め取得対象となります。

これらの値をのちに使用していく事になります。

説明画像3

.envに各種API Keyを設定する

Nuxt3からはdotenvがサポートされており、.envファイルをルートディレクトリ直下に置くだけで環境変数ファイルとして認識してくれます。(便利!)
それをnuxt.config.tsのruntimeConfigにて読み込んであげます。
今回はとりあえず本番用APIトークンのみ設定してみます。

.env

CONTENTFUL_SPACE_ID=先ほど発行したスペースID
CONTENTFUL_DELIVERY_ACCESS_TOKEN=先ほど発行した本番用APIトークン

nuxt.config.ts

export default defineNuxtConfig({
  runtimeConfig: {
    public: {
      contentfulSpaceId: process.env.CONTENTFUL_SPACE_ID || "",
      contentfulDeliveryAccessToken: process.env.CONTENTFUL_DELIVERY_ACCESS_TOKEN || "",
    }
  },
})
説明画像4

プラグインの作成

まずはcontentfulをインストールします

npm i contentful

pluginsディレクトリ内にcontentful.tsを作成します。

説明画像5

plugins/contentful.ts

import * as contentful from "contentful";

export default defineNuxtPlugin(() => {
  // 環境変数
  const $config = useRuntimeConfig();

  /* コンフィグ設定 */
  const config = {
    // 本番環境:公開コンテンツを取得
    space: $config.contentfulSpaceId,
    accessToken: $config.contentfulDeliveryAccessToken,
  };

  // 本番ではcontentful.default.createClientとなる
  const createClientFunc = contentful.createClient ? contentful.createClient : contentful.default.createClient;

  const client = createClientFunc(config);

  return {
    provide: {
      contentful: client
    }
  }
})

注意点がいくつかありまして、

import { createClient } from "contentful";

のように関数をインポートしてそれをdefineNuxtPlugin内で使用した場合、dev環境では上手くいくのですがbuild後本番環境となる.output/server層でエラーが発生してしまいました。
それを回避するためにまずは

import * as contentful from "contentful";

のように全体をcontentfulモジュール全体を読み込んであげてから使用するようにしました。

ではいざcreateClientメソッドでcontentfulクライアントを生成しよう!とした場合に更に問題が発生。
開発環境ではcontentful.createClientで関数が読み込めたものの、本番環境ではcontentful.default.createClientとなるみたい。。

const createClientFunc = contentful.createClient ? contentful.createClient : contentful.default.createClient;

色々試してみましたが、とりあえず上記で落ち着いています。
GitHubの方で同じような問題が上がっていましたのでこちらを参考にしました。
今後contentful側がNuxt3に対応してくれれば改善されるかもしれません。

実際に使用してみよう!

自分はutilsに関数を作って使用していますのでご参考までに。

const { $contentful } = useNuxtApp();

で先ほど作成したプラグインを呼び出してcontentfulクライアントを使用しています。
contentfulクライアントの使い方に関してはこちらにまとめていますのでご参考までに。(Nuxt2での記事ですが、導入部分以外使い方はほぼ変わりません)

utils/utils.ts

/**
 * ブログ情報の取得
 * @param {string} slug スラッグ デフォルト:空文字
 * @param {string} order ソート文字列 デフォルト:作成日降順
 * @param {number} page ページ デフォルト:1ページ目
 * @param {number} limit 取得件数 デフォルト:1000件
 * @returns {Array} ブログ情報
 */
export const getBlog = async ({
    slug = "",
    order = "-sys.createdAt",
    page = 1,
    limit = 1000
  }) => {

  let skip: number = page > 0  ? (page - 1) * limit : 0;

  const { $contentful } = useNuxtApp();

  const blogItems = await $contentful.getEntries({
    content_type: "blog",
    "fields.slug": slug,
    order: order,
    skip: skip,
    limit: limit,
  }).then( (items: any)  => {
    return items;
  }).catch(console.error);

  return blogItems;

};