3@TECH BLOG

日々の業務で得た知見やノウハウ、技術情報などを発信します。

Next.js × microCMS でSSGサイトを構築する

2025-08-19 microCMS

今回はNext.jsとmicroCMSでSSGサイトを構築したとき、必要だった設定をまとめます。
結論から言うと、以下の3点を押さえる必要がありました。

  • 静的エクスポートを有効化する
  • 動的ページにgenerateStaticParams()を追加する
  • プレビューはクライアント側でデータを取得する

それぞれ詳しくみていきます。

静的エクスポートを有効化する

next.config.js に 下記の記述を追加します。

next.config.js
const nextConfig = {
  output: 'export',
};

しかし、この記述を追加すると以下のエラーが発生しました。
Unhandled Runtime Error
Error: Image Optimization using the default loader is not compatible with `{ output: 'export' }`.
Possible solutions:
- Remove `{ output: 'export' }` and run "next start" to run server mode including the Image Optimization API.
- Configure `{ images: { unoptimized: true } }` in `next.config.js` to disable the Image Optimization API.
Read more: https://nextjs.org/docs/messages/export-image-api

output: 'export'を利用する場合は画像最適化を無効化する必要があるようです。
next.config.js に最適化オフを設定します。

next.config.js
const nextConfig = {
  output: 'export',
  images: {
    unoptimized: true, // これを追加
  },
};

unoptimizedがtrueの場合、画像はサイズやフォーマットを変更しないでそのまま適用されます。
そのためビルド前に画像を事前に最適化しておく必要があるので、注意してください。

これで「npm run build」で /out 配下に静的ファイルが出力されるようになります。

動的ページにgenerateStaticParams()を追加する

「/blog/[slug]」のような動的ルートも、SSGではビルド時に静的ファイルとして生成しておく必要があります。
そのときに使う関数がgenerateStaticParams()です。
この関数は簡単に言うと、どのURL作るかをNext.jsに渡す関数です。
たとえばブログ詳細ページ「/blog/[slug]」の[slug]に入る値を事前に用意して渡すことで、ビルド時に静的なページが生成されます。

またmicroCMSの一覧取得は1リクエスト最大100件までです。
そこでgenerateStaticParams() でもlimit + offsetでページングしながら全件を集める必要があります。

たとえば記事詳細(/blog/[slug]/page.tsx)の generateStaticParams() はこんな感じです。
 

/blog/slug/page.tsx
import { getBlogList } from '@/app/_libs/microcms';

export async function generateStaticParams() {
  // limit を最大値に設定
  const queries = { fields: "id", limit: 100 };
  // 全記事を格納する配列
  let allArticles: { id: string }[] = [];
  let offset = 0;

  while (true) {
      // APIリクエストで記事を取得
      const articlesListResponse = await getBlogList({ ...queries, offset });
      const { contents: articles } = articlesListResponse;

      // 取得データが空の場合終了
      if (!articles || articles.length === 0) {
        break;
      }

      // 記事を配列に追加
      allArticles = [...allArticles, ...articles];

      // 最後のページに到達
      if (articles.length < 100) {
        break;
      }

      // 次のページへ
      offset += 100;
  }

  // 記事IDからパスを生成
  const paths = allArticles.map((article) => ({
    slug: article.id,
  }));

  return paths;
}

一覧ページ(/blog/page.tsx)は固定パスのためgenerateStaticParamsは不要です。
一覧のページ送り(/blog/p/[current]/page.tsx)はページがある場合にパスを生成するようにします。

/blog/p/current/page.tsx
import { getBlogList } from '@/app/_libs/microcms';

export async function generateStaticParams() {
  const paths = [];
  const data = await getBlogList({
    // 一覧ページの1ページあたりの記事数
    limit: 10,
  });

  // APIレスポンスの totalCount から総ページ数を計算
  const totalPages = Math.ceil(data.totalCount / 10);

  // 総ページ数ぶんだけパスを生成
  for (let page = 1; page <= totalPages; page++) {
    paths.push({ current: page.toString() });
  }

  return paths;
}

プレビューはクライアント側でデータを取得する

microCMSでプレビューを実装する場合、「draftKey」を使って記事の取得します。
しかし、ビルド時にデータを取得しようとするとエラーになってしまいます。
そこで、プレビュー専用ページは固定パスにして、データ取得処理はクライアントコンポーネント側に移しました。
詳細は下記の記事にまとめています。参考にしてみてください。
Next.js × microCMSのSSGサイトでプレビュー画面を実装する

Contact お問い合わせ

お気軽にお問い合わせください。

PageTop