6歳娘「パパ、静的生成は色んな場面で使えるんだよ？」

[6歳娘「パパ、SGしてみたらサイトが爆速になったよ！」](https://qiita.com/Yametaro/items/678824fe3e3bcf4a88f5)の続編です。

# とある日、我が家にて
ワイ「こないだ娘ちゃんが作った**個人ブログ**のサイト」
ワイ「アクセスしたときの表示速度がメッチャ速かったなぁ」

> 娘「HTMLファイルを事前に**静的生成**してあるおかげで爆速なんだよ！」

ワイ「って言ってたな」
ワイ「ワイも**静的生成**ってやつ、やってみたいなぁ」
ワイ「Next.jsを使えば、割と簡単にできるって言ってたけど・・・」

娘「なに？パパもSG（静的生成）してみたいの？」

ワイ「せやねん」
ワイ「でも、一つ問題があってな」

娘「なに？」

# 個人ブログではなく、記事投稿サイトを作りたい

ワイ「今度ワイが作ろうとしているのは」
ワイ「**個人ブログ**やなくて、**記事投稿サイト**なんや」

娘「それのどこが問題なの？」

ワイ「え、だって問題やろ？」
ワイ「**個人ブログ**のサイトなら」
ワイ「自分しか記事を投稿しないから」
ワイ「自分で記事を投稿した後に」
ワイ「ビルドをしてHTMLを静的生成し直して、サーバにデプロイし直せば」
ワイ「新しい記事がサイトに反映されるやろ？」
ワイ「全て、**自分のタイミング**でできるやん？」

娘「うん」

ワイ「でも、今度ワイが作るのは**記事投稿サイト**やで？」
ワイ「色んな人が記事を投稿するサイトなんや」
ワイ「せやから、**いつ誰が新しい記事を書くのか分からへん**のや」

娘「そうだね」

ワイ「ほな、いつHTMLを静的生成すればいいか分からへんやん」

> ワイ「新しい記事を投稿したら、ワイに一報お願いしますやで！」

ワイ「って、投稿者さん達にお願いしておく訳にも行かんし」
ワイ「だから今度のサイトでは、静的生成するのは無理なんかな〜って・・・」

# しかし、ワイ閃く

ワイ「・・・せや！」
ワイ「投稿者さん達が新しい記事を投稿したら」
ワイ「ワイに**通知メール**が来るようにしておけばええんや！」
ワイ「そんで、通知メールが来るたびに、ビルドしてデプロイし直せばええやんけ！」

娘「パパ、そんなに頑張る必要ないんだよ？」

ワイ「娘ちゃん、心配してくれてありがとうな？」
ワイ「でも、ワイは頑張るで！」

娘「いや、そうじゃなくて」
娘「そんな風に**自分で再ビルドする必要はない**ってこと」
娘「自動でできるよ」

ワイ「マジか」

娘「そう、**ISG**をすればいいの」

ワイ「**ISG**？」

# ISGとは
娘「ISGっていうのは**Incremental Static Generation**の略で」
娘「**インクリメンタル静的生成**って意味だね」

ワイ「インクリメンタル・・・**増分**って意味やな？」

娘「そう」
娘「その名の通り、**増えた記事のぶん**のHTMLファイルを」
娘「サーバ側で自動的に生成してくれる機能なの」

ワイ「へぇ〜」
ワイ「投稿者さん達が新しい記事を投稿したら」
ワイ「サーバ側で、Next.jsが自動的にHTMLを生成してくれるってことかいな？」

娘「うーん・・・」

> 投稿者さん達が新しい記事を投稿したら

娘「↑このタイミングではないね」
娘「新しい記事が投稿されて、データベースに追加されたとしても」
娘「そこで即座にHTMLファイルを自動生成してくれる訳じゃないの」

ワイ「そうなんや」
ワイ「ほな、いつHTMLファイルを生成してくれるん？」

娘「新しい記事のURLに、アクセスがあったときだね」
娘「パパの好きな関西型言語で説明すると・・・」

> サーバ「おっ！」
> サーバ「新しい記事のURLに対して、アクセスが来たで！」
> サーバ「でもまだ、そのページのHTMLファイルは生成してへんわ！」
> サーバ「いったん、**ローディング画面**のHTMLを返すで！」
> サーバ「そして、記事内容が入った**JSON**も返すで！」

娘「↑こんなイメージだね」

ワイ「ふーん」
ワイ「まだ新しい記事のHTMLファイルが生成されてないから」
ワイ「とりあえず**ローディング画面**のHTMLが返ってくる」
ワイ「そして、新しい記事のJSONも返ってくる」
ワイ「ってことはつまり・・・」

```html:サーバから返ってくるHTML（抜粋）
    <main>
      <section>
        <h1>ロード中...</h1>
        <div>ロード中...</div>
      </section>
    </main>
```

ワイ「↑こんなHTMLがサーバから返ってくるから」
ワイ「記事のタイトルや本文は、最初はブラウザ上に表示されなくて」
ワイ「その後で、JavaScriptによって」
ワイ「JSONの内容・・・つまり記事の内容が、画面に反映される感じか」

娘「そうだね」

ワイ「へ〜、そうすることで」
ワイ「新しい記事にアクセスがあっても、`404`表示になってしまうことはないんやな」

娘「そう」
娘「**ちゃんと設定をしておけばね**」

ワイ「それは、どこで設定するん？」

娘「`getStaticPaths`関数の、戻り値の中だよ」

### getStaticPaths
```diff_tsx:/pages/articles/[id].tsx
export const getStaticPaths: GetStaticPaths = async () => {
  /* 〜省略〜 */

  return {
    paths,
+   fallback: true,
  }
}
```

娘「こう、`fallback: true`を設定するの」

ワイ「へぇ〜」

娘「こうすることで、新しい記事のページ・・・」
娘「つまり**まだHTMLファイルが生成されてないページ**にアクセスがあっても」
娘「`404`表示にならないようにできるの」

ワイ「ほぇ〜、簡単やな」
ワイ「でも・・・」

# それって、静的生成じゃなくてCSRじゃない？
ワイ「それって、静的生成じゃなくて」
ワイ「クライアント側でHTMLの内容を描画してるやん？」
ワイ「静的生成の旨味がなくなってへんか？」

> 娘「HTMLファイルを事前に**静的生成**してあるおかげで爆速なんだよ！」

ワイ「↑こうじゃなくなってるやん」

娘「えっとね、その新しい記事ページに対して」
娘「二人目以降にアクセスした人は、爆速でHTMLを受け取れるの」

ワイ「あ、そうなんや」

娘「そう」
娘「つまり・・・」

1. 新しい記事が投稿される
    - この時点ではHTMLファイルは生成されない
1. その記事のURLにアクセスが来る
    - ここでHTMLファイルが生成される
1. それ以降のアクセスでは、`2.`で生成されたHTMLが返される

娘「↑こういうことだね」

ワイ「なるほどな〜」
ワイ「新しい記事に、最初にアクセスした人の場合は」
ワイ「ローディング画面を挟んでから記事の内容が反映される感じやけど」
ワイ「その後にアクセスした人たちは、完成済みのHTMLを爆速で受け取れるんやな」

娘「そうだね！」

ワイ「お〜、そうだったんやな」
ワイ「ワイは、記事が投稿されるたびにビルドとデプロイをせなアカンのかと思ってたわ！」
ワイ「増えた記事の分だけ、サーバ側で自動的にHTMLを生成してくれるんやな！」

娘「そうだよ」
娘「まさに**インクリメンタル静的生成**って感じだね」

ワイ「おお、ほんまやね」

# でも、記事の内容が編集された場合にはどうなる？
ワイ「娘ちゃん、まだ気になることがあるんやけど」
ワイ「投稿者さんが、記事の内容を**編集**した場合にはどうなるん？」
ワイ「自動的にHTMLファイルを**生成し直してくれる**ような機能はないんかい？」

娘「あるよ」
娘「**ISR**をすればいいの」

ワイ「**ISR**？」

# ISRとは
娘「**ISR**はね」
娘「**Incremental Static Regeneration**の略で」
娘「インクリメンタル静的**再**生成って意味なの」

ワイ「**再**生成か」
ワイ「記事が編集された場合に、HTMLを生成し直してくれるってこと？」

娘「そうだよ」

ワイ「便利なもんやな〜」

娘「ね」
娘「それでね、ISRしたい場合は」
娘「`getStaticProps`関数の戻り値のところで設定するんだよ」

### getStaticProps
```diff_tsx:/pages/articles/[id].tsx
export const getStaticProps: GetStaticProps<StaticProps, { id: string }> = async (context) => {
  /* 〜省略〜 */

  return {
    props: {
      article,
    },
+   revalidate: 30,
  }
}
```

娘「↑こうだね」

ワイ「おお、これまた簡単やな」

娘「`30`ってのは、秒数だよ」

ワイ「へー、これを設定しておくと、30秒後に何か起こるん？」

娘「うーん」
娘「30秒後に何か起こるっていうか」

> サーバ「最大でも、30秒間に1回しかHTMLの再生成をせえへんで」

娘「↑こうなる感じかな」
娘「あまり頻繁にHTMLの再生成をしたら、サーバさんが大変でしょ？」

ワイ「最大でも、30秒間に1回しかHTMLの再生成をしない・・・」
ワイ「どういうこと？」

娘「えっとね」

1. 投稿者さんが記事を編集する
1. その5秒後に、読者さんが記事ページにアクセスする
1. 投稿者さんが、また記事を編集する
1. その5秒後に、読者さんがまた記事ページにアクセスする

娘「↑こんなことが繰り返された場合でも」
娘「30秒に1回しか、HTMLの再生成はされないってこと」

ワイ「ああ、なるほどな」
ワイ「タイミングによっては、**少し前の状態の記事**を読むことになってしまうんやな」

娘「そうそう」
娘「だから、**常に最新の情報を、必ず読んでもらう必要がある**・・・」
娘「そんなページには、**ISR**は向いてないかもね」

ワイ「そうなんやね」

# ISG/ISRに対応したホスティング先が必要
ワイ「Next.jsが、こんなに気の利いた感じでHTMLファイルを追加生成をしてくれるのは分かったんやけど」
ワイ「これって、サーバ側が**ISG**とか**ISR**に対応してる必要があるんちゃうの？」

娘「そうだよ」
娘「Next.jsの開発元のVercel社が運営してる、**Vercel**っていうホスティングサービスとか」
娘「あとは**AWS Amplify**なんかも、ISG/ISRに対応してるみたいだよ」

ワイ「なるほどなぁ」
ワイ「デプロイ先は多少限られてくるけど、自動でHTMLファイルを追加生成してくれるのはありがたいから」
ワイ「是非とも使ってみたいもんやなぁ」

娘「そうだね」
娘「もしISG/ISRっていうものがなくて、手動での再ビルドが必要だったら」
娘「めっちゃ面倒だし、個人ブログくらいでしか静的生成を使えなさそうだよね」

ワイ「せやな」
ワイ「誰かが記事を書くたびに、ビルドして、デプロイして・・・」
ワイ「そんなこと現実的やないしな」

娘「うん」

ワイ「でも、ISGやISRなんていう仕組みがなくても」
ワイ「新しい記事が投稿されたことを、何かしらの通知で受け取って」
ワイ「それをトリガーにして自動で再ビルドするくらいの設定なら」
ワイ「なんか、ワイでもできそうやけどな」

娘「でも、それだとサーバが大変そうじゃない？」
娘「記事が増えて、通知が来るたびにビルドし直すなんてさ」

ワイ「ああ、そうか」
ワイ「全部ビルドし直すのは大変そうやな」

娘「うん」
娘「でも、ISGやISRを使えば」
娘「増えた記事とか、編集された記事のぶんだけ」
娘「インクリメンタルにHTMLを生成してくれるし」
娘「サーバの負荷も少ないと思うよ」

ワイ「た、確かに」

# まとめ
- SGとは
    - 静的生成
        - 各記事のHTMLファイルを事前に生成しておくこと
            - サーバにアクセスがあった際、爆速でHTMLを返せる
- ISGとは
    - インクリメンタル静的生成
        - 増えた記事のぶんのHTMLファイルを、サーバ側で自動的に生成してくれる
            - タイムラグあり
- ISRとは
  - インクリメンタル静的**再**生成
    - 記事が更新された場合にも、自動的にHTMLファイルを再生成してくれる
        - タイムラグあり

※対応したホスティング先が必要

ワイ「↑こういうことやな！」

娘「そうだね！」

# あのサイトでも使われている

娘「ちなみに、[青い技術記事投稿サイト](https://zenn.dev/)でも、以前**ISR**を使っていたみたいだよ」

ワイ「こら、娘ちゃん」
ワイ「**青い技術記事投稿サイト**の話はアカンで」
ワイ「それはQiita内ではタブーなんや」
ワイ「そんな話をしたら、この記事が削除されてしまうかもしれんで？[^1]」

娘「そんな訳ないでしょ」
娘「Qiitaの運営さん達は、みんな寛大な人たちなんだから」
娘「**青い技術記事投稿サイト**ってぼかしておけば大丈夫だよ」

ワイ「そ、そうか」
ワイ「大丈夫ならええわ」


娘「うん」
娘「**ZennZenn**大丈夫」

ワイ「いやハッキリ言うてもうてるがな」

**〜おしまい〜**

# 参考文献
- [Data Fetching: getStaticPaths - Next.js](https://nextjs.org/docs/basic-features/data-fetching/get-static-paths)
- [Data Fetching: getStaticProps - Next.js](https://nextjs.org/docs/basic-features/data-fetching/get-static-props)
- [Incremental Static Regeneration - Data Fetching - Next.js](https://nextjs.org/docs/basic-features/data-fetching/incremental-static-regeneration)

# こちらの記事もよろしくやで！
- [6歳娘「パパ、Vue3のComposition APIってどう使うの？」](https://qiita.com/Yametaro/items/5905f020acaf1f748d07)

[^1]:Qiitaさんはそんなことしません。