RemixでmicroCMSを使ったブログサイトを構築してみた〜プレビュー画面〜

RemixとmicroCMSで作成したブログにmicroCMSのプレビュー機能を実装してみました。
2022.02.06

はじめに

こんにちは、CX事業本部MAD事業部の森茂です。

こちらの記事でRemixとmicroCMSを使った簡単なブログを構築してみました。ただ実際に運用する場合はブログに記事を投稿する際あらかじめプレビュー画面で確認したいことが多いと思います。microCMSには記事を書く際に下書き保存している記事を確認するためのプレビュー機能があるので、今回はその機能をRemixで実装してみました。

microCMSの設定

microCMSでは下書き状態のコンテンツにdraftKeyというユニークなキーが発行されます。コンテンツ取得時にこのdraftKeyを付与することでまだ公開されていない下書き状態のコンテンツを取得できます。microcms-js-sdkを利用している場合は、queriesdraftKeyを付与するだけ取得できるようになります。

const content = await client
  .get({
    endpoint: 'blog',
    contentId: params.postId,
    queries: { draftKey: '下書き状態の記事のdraftKey' } // draftKeyを渡す
  });

まずmicroCMS側の設定を確認していきます。

API設定の画面プレビュー設定画面で遷移先URLを登録します。公開するサイトのURLにあわせて設定を記載します。今回はlocalhostでのテストを行いたいので下記のように登録をしました。CONTENT_IDDRAFT_KEYにはアクセス時に自動的に付与される値が入ります。

http://localhost:3000/posts/{CONTENT_ID}?draftKey={DRAFT_KEY}

microCMSの記事詳細画面から画面プレビューを押下するとここで登録したURLへ遷移するので、受け取り側では通常通りCONTENT_IDの記事を取得するロジックを動かし、その際にDRAFT_KEYを付与してあげることで本来取得できない下書き状態の記事が取得できるという仕組みです。

Remixでの実装

前回作成した記事ページをベースに、記事の詳細画面をプレビュー画面としても利用できるように実装します。クエリーパラメーターに付与されたdraftKeyがある場合はその値を追加してAPIからコンテンツを取得します。

今回の実装では`draftKey`が漏洩した場合誰でも対象の下書き情報が閲覧できる状態となります。機密性の高い情報を扱う場合は、認証が必要な別のページを用意するもしくは別のプレビュー用環境を用意するといった方法が必要です。またCDN下での意図しないキャッシュについても注意する必要があります。

RemixではLoaderFunctionで生成したデータをHeadersFunctionで受け取ることができます。今回はdraftKeyがあり、プレビュー画面と判断した場合はヘッダーのCache-Controlの値を変更することでプレビュー画面をキャッシュさせないようにしています。

app/routes/posts/$postId.tsx

// ...

// stale-while-revalidateの設定
export const headers: HeadersFunction = ({ loaderHeaders }) => {
  const cacheControl =
    loaderHeaders.get('Cache-Control') ??
    'max-age=0, s-maxage=60, stale-while-revalidate=60';
  return {
    'Cache-Control': cacheControl,
  };
};

// ...

// microCMS APIから記事詳細を取得する
export const loader: LoaderFunction = async ({ params, request }) => {
  // 下書きの場合
  const url = new URL(request.url);
  const draftKey = url.searchParams.get('draftKey');

  const content = await client
    .get<Content>({
      endpoint: 'blog',
      contentId: params.postId,
      queries: { draftKey: draftKey ?? '' },
    })
    // 記事が404の場合は404ページへリダイレクト
    .catch(() => {
      throw new Response('Content Not Found.', {
        status: 404,
      });
    });

  // 下書きの場合キャッシュヘッダを変更
  const headers = draftKey ? { 'Cache-Control': 'no-store, max-age=0' } : undefined;

  return json(content, { headers });
};

// ...

draftKeyの有無を判断してヘッダー情報を変更するという仕組みを追加するのみで記事ページをプレビュー画面として利用できるようになりました。

一点、現時点でRemix(v1.1.3)のHeadersFunction部分にはバグが有り上記のみではヘッダーの変更を行うことができません。下記root.tsxLoaderFunctionを追記することによって回避できます。(もちろんroot.tsxLoaderFunctionを別の用途で利用していれば問題はありません)

app/root.tsx

// ...

export const loader: LoaderFunction = async () => {
  return null;
};

// ...

なお、こちらのバグについてはRemix開発チームも認識しており修正中とのことです。

動作の確認

ここで動作を確認していきます。Remixをローカルサーバーで起動しておきます。

$ npm run dev

microCMS上で下書き状態のコンテンツを作成して画面プレビューを押下してプレビュー画面へ遷移します。

URLにdraftKeyが付与された状態で下書き状態のコンテンツの確認ができました。ヘッダーのCache-Controlの値もno-storeとなっています。

念の為draftKeyがない状態ではNot Foundとなることも確認しておきます。

これでプレビュー機能の実装が完了です。
Vercelなど外部でデプロイする場合はmicroCMSの遷移先URL設定を変更しておくことをお忘れなく。

さいごに

RemixでmicroCMSのプレビュー機能を実装してみました。プレビュー機能というと何か複雑なものを想像してしまうところがありますが、実際試してみると比較的簡単に用意することができました。

Remixではヘッダーも動的に変更することができるためヘッダーを利用したキャッシュのコントロールも簡単です。LoaderFunctionLoaderHeadersなどLoaderと呼ばれる機能が複数あり記載量も多くなりがちですがカスタマイズ性は非常に高いと思います。

次回はOG画像の自動生成を実装していきます:)

参考ソースファイル