120
47

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 1 year has passed since last update.

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

Last updated at Posted at 2022-07-03

6歳娘「パパ、SGしてみたらサイトが爆速になったよ!」の続編です。

とある日、我が家にて

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

娘「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(抜粋)
    <main>
      <section>
        <h1>ロード中...</h1>
        <div>ロード中...</div>
      </section>
    </main>

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

娘「そうだね」

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

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

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

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

getStaticPaths

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

  return {
    paths,
+   fallback: true,
  }
}

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

ワイ「へぇ〜」

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

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

それって、静的生成じゃなくてCSRじゃない?

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

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

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

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

ワイ「あ、そうなんや」

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

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

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

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

娘「そうだね!」

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

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

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

でも、記事の内容が編集された場合にはどうなる?

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

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

ワイ「ISR?」

ISRとは

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

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

娘「そうだよ」

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

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

getStaticProps

/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. 投稿者さんが記事を編集する
  2. その5秒後に、読者さんが記事ページにアクセスする
  3. 投稿者さんが、また記事を編集する
  4. その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ファイルを再生成してくれる
        • タイムラグあり

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

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

娘「そうだね!」

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

娘「ちなみに、青い技術記事投稿サイトでも、以前ISRを使っていたみたいだよ」

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

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

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

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

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

〜おしまい〜

参考文献

こちらの記事もよろしくやで!

  1. Qiitaさんはそんなことしません。

120
47
5

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
120
47

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?