Next.js静的生成(SSG)の基本

2025-08-13

はじめに

Next.jsの大きな特徴である「静的生成(Static Site Generation: SSG)」について、初心者の方にもわかりやすく解説します。SSGを理解することで、高速でSEOに強く、安全なWebサイトを構築できるようになります。

静的生成(SSG)とは?

静的生成とは、ビルド時にHTMLファイルを事前に生成する手法です。ユーザーがページにアクセスする前に、あらかじめページが準備されているため、以下のようなメリットがあります:

  • 超高速なページ表示
  • サーバー負荷が軽減
  • SEOに有利
  • CDNでの配信が容易
  • 高いセキュリティ(サーバーサイドコードが不要)

SSGの基本的な仕組み

ビルド時(npm run build)
↓
データ取得(getStaticProps)
↓
HTML生成
↓
ユーザーアクセス時に生成済みHTMLを配信

基本的なSSGの実装方法

1. データを必要としない静的ページ

最もシンプルなSSGページは、通常のReactコンポーネントと同じ書き方で実現できます。

// pages/about.js
function About() {
  return (
    <div>
      <h1>About Us</h1>
      <p>私たちの会社についての情報ページです</p>
    </div>
  );
}

export default About;

このページはビルド時に静的なHTMLとして生成されます。

2. 外部データを使用する静的ページ

外部データ(APIやデータベースなど)を使用する場合、getStaticProps関数を追加します。

// pages/blog.js
function Blog({ posts }) {
  return (
    <div>
      <h1>ブログ記事一覧</h1>
      <ul>
        {posts.map((post) => (
          <li key={post.id}>{post.title}</li>
        ))}
      </ul>
    </div>
  );
}

// ビルド時にデータを取得
export async function getStaticProps() {
  // 実際のアプリではAPIやデータベースからデータを取得
  const res = await fetch('https://api.example.com/posts');
  const posts = await res.json();

  return {
    props: {
      posts,
    },
  };
}

export default Blog;

getStaticPropsの詳細

getStaticPropsはNext.jsが提供する特別な関数で、以下の特徴があります:

  • ビルド時に実行される
  • サーバーサイドで実行される(クライアントバンドルに含まれない)
  • ページコンポーネントにpropsを渡せる

返却値のオプション

export async function getStaticProps() {
  // データ取得処理...

  return {
    props: {},      // ページコンポーネントに渡すprops
    revalidate: 10, // ISR(後述)を使用する場合の再生成間隔(秒)
    notFound: false, // 404ページを表示するか
    redirect: {     // リダイレクトする場合
      destination: '/other-page',
      permanent: false,
    },
  };
}

動的ルートの静的生成

動的ルート(例:[id].js)を使用する場合、getStaticPathsも併せて使用します。

基本的な実装例

// pages/posts/[id].js
function Post({ post }) {
  return (
    <div>
      <h1>{post.title}</h1>
      <p>{post.content}</p>
    </div>
  );
}

// ビルド時に生成するパスを指定
export async function getStaticPaths() {
  const res = await fetch('https://api.example.com/posts');
  const posts = await res.json();

  // プリレンダリングするパスを指定
  const paths = posts.map((post) => ({
    params: { id: post.id.toString() },
  }));

  return {
    paths,
    fallback: false, // 後述
  };
}

// 各パスに対してデータを取得
export async function getStaticProps({ params }) {
  const res = await fetch(`https://api.example.com/posts/${params.id}`);
  const post = await res.json();

  return {
    props: {
      post,
    },
  };
}

export default Post;

fallbackの3つのモード

getStaticPathsfallbackオプションには重要な3つの設定があります:

1. fallback: false

  • ビルド時に生成されていないパスは404ページになる
  • 全てのパスをビルド時に生成する場合に使用

2. fallback: true

  • ビルド時に生成されていないパスにアクセスすると、バックグラウンドでHTMLを生成
  • 初回アクセス時はローディング状態を表示する必要がある
function Post({ post }) {
  const router = useRouter();

  // 初回ロード中の表示
  if (router.isFallback) {
    return <div>Loading...</div>;
  }

  // 通常の表示
  return (
    <div>
      <h1>{post.title}</h1>
      <p>{post.content}</p>
    </div>
  );
}

3. fallback: 'blocking'

  • ビルド時に生成されていないパスに初めてアクセスした時にサーバーサイドでHTMLを生成
  • 生成が完了するまでユーザーは待機状態(ローディング表示不要)

インクリメンタル静的再生(ISR)

Next.js 9.5で導入されたISR(Incremental Static Regeneration)を使うと、ビルド後も定期的にページを再生成できます。

export async function getStaticProps() {
  const res = await fetch('https://api.example.com/posts');
  const posts = await res.json();

  return {
    props: {
      posts,
    },
    // 10秒ごとにページを再生成
    revalidate: 10,
  };
}

ISRの動作フロー:

  1. 初回アクセス:事前生成されたHTMLを表示
  2. 10秒後のアクセス:キャッシュされたHTMLを表示
  3. 10秒経過後の最初のアクセス:バックグラウンドで再生成
  4. 再生成完了後:新しいHTMLを表示

SSGの使用が適しているケース

  • ブログやニュースサイト
  • 製品紹介ページ
  • ドキュメンテーション
  • マーケティングページ
  • 更新頻度が低いコンテンツ

SSGのベストプラクティス

1. データ取得の最適化

// 悪い例(複数のAPI呼び出しが並列化されていない)
export async function getStaticProps() {
  const user = await fetchUser();
  const posts = await fetchPosts();

  return { props: { user, posts } };
}

// 良い例(Promise.allで並列処理)
export async function getStaticProps() {
  const [user, posts] = await Promise.all([
    fetchUser(),
    fetchPosts(),
  ]);

  return { props: { user, posts } };
}

2. エラーハンドリング

export async function getStaticProps() {
  try {
    const res = await fetch('https://api.example.com/data');

    if (!res.ok) {
      throw new Error('データの取得に失敗しました');
    }

    const data = await res.json();

    return {
      props: {
        data,
      },
    };
  } catch (error) {
    console.error(error);
    return {
      notFound: true, // 404ページを表示
      // またはエラーメッセージをpropsとして渡す
      // props: { error: error.message },
    };
  }
}

3. 環境変数の使用

APIエンドポイントや認証情報は環境変数で管理:

export async function getStaticProps() {
  const res = await fetch(process.env.API_URL);
  // ...
}

実際のプロジェクトでの使用例

ブログ記事一覧と詳細ページ

// pages/index.js
export default function Home({ recentPosts }) {
  return (
    <div>
      <h1>最新記事</h1>
      {recentPosts.map((post) => (
        <Link key={post.id} href={`/posts/${post.id}`}>
          <a>
            <h2>{post.title}</h2>
            <p>{post.excerpt}</p>
          </a>
        </Link>
      ))}
    </div>
  );
}

export async function getStaticProps() {
  const res = await fetch('https://api.example.com/posts?_limit=5');
  const recentPosts = await res.json();

  return {
    props: {
      recentPosts,
    },
    revalidate: 60, // 60秒ごとに再生成
  };
}
export default function Post({ post }) {
  return (
    <article>
      <h1>{post.title}</h1>
      <div dangerouslySetInnerHTML={{ __html: post.content }} />
    </article>
  );
}

export async function getStaticPaths() {
  const res = await fetch('https://api.example.com/posts');
  const posts = await res.json();

  const paths = posts.map((post) => ({
    params: { id: post.id.toString() },
  }));

  return {
    paths,
    fallback: 'blocking',
  };
}

export async function getStaticProps({ params }) {
  const res = await fetch(`https://api.example.com/posts/${params.id}`);

  if (!res.ok) {
    return {
      notFound: true,
    };
  }

  const post = await res.json();

  return {
    props: {
      post,
    },
    revalidate: 3600, // 1時間ごとに再生成
  };
}

まとめ

Next.jsの静的生成(SSG)について学びました。主なポイントは:

  1. SSGはビルド時にHTMLを生成するため、高速で安全
  2. getStaticPropsでビルド時にデータを取得
  3. 動的ルートにはgetStaticPathsを使用
  4. fallbackオプションで柔軟なページ生成が可能
  5. ISR(インクリメンタル静的再生)で定期的な再生成が可能

SSGはパフォーマンスと開発体験の両方を向上させる強力な機能です。ただし、ユーザーごとに内容が変わるページや、リアルタイム性が求められるページには不向きです。そのようなケースでは、次回解説する「サーバーサイドレンダリング(SSR)」が適しています。

Next.jsの公式ドキュメントも参考にしてください:
https://nextjs.org/docs/basic-features/data-fetching/get-static-props