yasutomogのブログ

Software Engineerの雑記

【Next.js & microCMS】SSGのビルドパフォーマンスチューニング

前提

  • Next.jsとmicroCMSを使用し、数百ページのWebサイトを構築している
  • App Routerは使用していない(Next.jsの採用時にApp Routerがまだ正式採用されていなかったため)
  • ISRも使用していない(業務要件の兼ね合いから使っていない)
  • Amplify上で、SSGして静的サイトを構築している

課題

  • ページ数が増えることで、ビルドのパフォーマンスが気になってきた
  • 当初から想定していたが、想定よりも遅いことが気になってきた

microCMSの簡単なデータ構造

  • microCMSでは下図にある通り、各ページからヘッダーとフッターのデータを参照している。また、ヘッダーとフッターからは、グローバルナビゲーションやフッターメニューで表示する、各ページのデータを参照している。

microCMSのデータ構造
microCMSのデータ構造

アプローチ

  • ページ生成時のmicroCMS API通信処理の回数を減らす、もしくは、通信データサイズを減らすことを検討。
  • 基本的には、Webページに合わせてデータ登録しているので、通信回数を減らすことは難しそう。
  • 通信データサイズを減らすための工夫を検討。

各ページの getStaticProps からmicroCMS APIを呼び出しているレスポンス内容を解析すると、想定しているよりもデータサイズが大きいことが分かりました。これは、ヘッダーとフッターで設定しているページ内容を取得するために、microCMS APIのdepthパラメータに 2 を設定しているからでした。

depthは、API単位で設定するもので、各階層に対して個別設定はできないので、depthの値を 1 に変更し、ヘッダーとフッターのデータは個別に取得するように変更しました。また、ヘッダーとフッターの値は、各ページで同じものを使用することが多いため、キャッシュできるような仕組みを用意しています。

具体的には、以下のような共通関数を1つ作成し、一度取得したヘッダーまたはフッターであれば、通信処理を介さずにデータを返すようにしています。

import client from '@/lib/client';
import { FooterData } from '@/types/footerData';
import { HeaderPcData, HeaderSpData } from '@/types/headerData';

const globalCache: Record<string, HeaderPcData | HeaderSpData | FooterData> =
  {};

const getHeaderFooterCachedData = async (
  endpoint: string,
  contentId: string,
): Promise<HeaderPcData | HeaderSpData | FooterData> => {
  const key = `${endpoint}-${contentId}`;
  if (globalCache[key]) {
    // console.log('cache hit');
    return globalCache[key];
  }

  const data = await client.get<HeaderPcData | HeaderSpData | FooterData>({
    endpoint,
    contentId,
  });
  globalCache[key] = data;
  return data;
};

export default getHeaderFooterCachedData;

まとめ

元々8分くらい掛かっていたビルド処理から30秒くらいの削減が見込まれることを確認できました。今回は一例ですが、Webサイト全体で扱う共通コンポーネントがあれば、同様のアプローチでキャッシュ化することも検討できるので、地道に積み重ねていくともう少し改善できそうです!