6歳娘「パパ、SGしてみたらサイトが爆速になったよ！」

# とある休日
ワイ「あー、今日はヒマやな〜」
ワイ「ヒマやから、メールチェックでもしよか」
ワイ「パソコンでメールを受信して・・・っと」
ワイ「わ〜、また迷惑メールたくさん来とるわ〜」

娘「パパ、迷惑メールって何？」

ワイ「そのまんまや」
ワイ「迷惑なメールのことや」

娘「迷惑な・・・メール・・・」
娘「・・・あっ！」
娘「もしかして、パパみたいな男の人のこと！？」

ワイ「そうそう、もう存在そのものが迷惑な男性やから・・・コラッ！」
ワイ「誰が**迷惑male**やねん」

娘「そんなことよりパパ」

ワイ「なんや、娘ちゃん」

# ここから本題

娘「この前、私が日記を書くための**個人ブログ**のサイトを作ったんだけどね」
娘「Next.jsを使って、**SPA**として作ったの」

ワイ「ほうほう、**シングルページアプリケーション**やな」

娘「うん、それでね」
娘「**CSR**してたところを、**SG**するように変えたら」
娘「サイトにアクセスした時のロード時間が、だいぶ速くなったの！」

ワイ「CSR・・・SG・・・？」
ワイ「娘ちゃん、一体なんの話をしてんのや？」

娘「えっとね」

# CSRとは
娘「**CSR**っていうのはね」

1. ブラウザ上から、JavaScriptを用いてAPIを叩く
1. APIから取得したデータを、JavaScriptを用いて画面上に表示する

娘「↑こういうやつだよ！」

ワイ「ふーん、SPAでよくある普通の方法やな」
ワイ「`SWR`とかを使って、下記のようにやるんやろ？」

### ブログ記事の詳細ページの例
#### データ取得
```diff_tsx:/pages/articles/[id].tsx
  // URLクエリから id を取得
  const articleId = router.query.id
  // APIからブログ記事を1件取得
  const { data: article } = useSWR(`/api/articles/${articleId}`, fetcher)
```

#### データ表示
```diff_tsx:/pages/articles/[id].tsx
  // APIからデータが読み込み終わるまでは「ロード中...」と表示される。
  return (
    <section>
      {/* 記事のタイトル */}
      <h1>{article ? article.title : "ロード中..."}</h1>
      {/* 記事本文 */}
      <div>{article ? article.body : "ロード中..."}</div>
    </section>
  )
```

ワイ「↑これを**CSR**って呼ぶんやな」
ワイ「知らんかったわ」

娘「ブラウザ・・・つまりクライアント側で情報を描画するから」
娘「クライアントサイド・レンダリング」
娘「だから**CSR**だね」

ワイ「なるほどなー」
ワイ「レンダリングって、描画って意味やもんな」

娘「うん」
娘「**CSR**の場合はね」
娘「サーバからHTMLを取得した時点では」

```html:【CSR】サーバから返ってきたHTML（抜粋）
    <main>
      <section>
        <h1>ロード中...</h1>
        <div>ロード中...</div>
      </section>
    </main>
```

娘「↑こんな感じなの」

ワイ「ほー」
ワイ「この後、JavaScriptによって」
ワイ「記事のデータをAPIから取得してきて」
ワイ「`ロード中...`の部分が書き換わるわけやな」

娘「そうなの」

ワイ「つまり、一連の流れで言うと・・・」

1. ブラウザのアドレスバーにブログ記事のURLを打ち込む
1. 閲覧者さんのパソコンに、HTMLの内容が届く
（この段階では、記事のタイトルや本文などは表示されていない）
1. JavaScriptが読み込まれ、API通信が起こる
1. APIから記事のデータが届く
1. JavaScriptによって、画面上に記事のタイトルや本文が描画される

ワイ「↑こんな感じか」
ワイ「まさにクライアントサイドでレンダリングしとるわけやな」

娘「うん」

ワイ「ほな、**SG**ってのはどんな感じなん？」

# SGとは
娘「SGの場合はね」
娘「事前にHTMLの内容を静的生成しておくの」
娘「サイトをサーバにデプロイする前[^1]にね」

ワイ「へぇ〜」

娘「静的生成は、英語で言うと**Static Generation**」
娘「だから**SG**っていうんだよ」

ワイ「ふーん」
ワイ「その**SG**とやらをすると」
ワイ「ブラウザからサイトにアクセスした時のロード時間が速くなるん？」

娘「そうだよ」
娘「**SG**の場合は」
娘「サーバからHTMLを取得した時点で」

```html:【SG】サーバから返ってきたHTML（抜粋）
    <main>
      <section>
        <h1>初投稿</h1>
        <div>これは初めての記事です。</div>
      </section>
    </main>
```

娘「↑こんな風に」
娘「記事の内容もちゃんとHTML内に書かれてるの」
娘「だから、記事の内容が即座に画面に表示されるの」

ワイ「そうか、記事の内容も含めて**事前に生成**されたHTMLを」
ワイ「ダウンロードしてくるだけって感じなんやな」

娘「そう」
娘「だから、SGしておく方が爆速なの」

ワイ「なるほどなー」
ワイ「SGが良さそうなのは分かったけど、具体的にどうやってSGするん？」

娘「えっとね」

# `getStaticProps`と`getStaticPaths`を使う
娘「Next.jsを使っている場合、**SG**をするには」
娘「`getStaticProps`と`getStaticPaths`を使うの」

ワイ「ほえ〜、なんか聞いたことあるな」
ワイ「ページのtsxファイルに」
ワイ「`getStaticProps`と`getStaticPaths`っていう関数を書いて」
ワイ「`export`してやればええんやっけ？」

娘「そう」
娘「さっきの例だと・・・」

### getStaticProps
```diff_tsx:/pages/articles/[id].tsx
type StaticProps = { article: Article }

export const getStaticProps: GetStaticProps<StaticProps, { id: string }> = async (context) => {
  // 記事詳細APIからデータを取得
  const id = context.params!.id
  const article = await fetch(`https://api.example.com/articles/${id}`).then<Article>(res => res.json())

  return {
    props: {
      article,
    },
  }
}
```

娘「↑こんな感じで`getStaticProps`を書いてやればいいの」

ワイ「へー」
ワイ「APIを叩いて、ブログ記事の詳細情報を取得する感じか」

娘「うん」

ワイ「こう書いておくことで」
ワイ「デプロイ前の、**ビルドの段階**で」
ワイ「APIから記事データを取得して」
ワイ「HTMLの内容を埋めておいてくれるってわけか」

娘「そうだよ」
娘「ブログ記事が5件ある場合なら」

- /articles/1.html
- /articles/2.html
- /articles/3.html
- /articles/4.html
- /articles/5.html

娘「↑こう、5つのファイルをビルド時に生成してくれるよ」

ワイ「なるほどな〜」
ワイ「でも・・・」

> 記事が5件あって、5つのファイルを生成しなければならない

ワイ「↑この事は、どうやってNext.jsに伝えるんや？」

娘「いい質問だね」
娘「そのために`getStaticPaths`を書くの」

- /articles/1
- /articles/2
- /articles/3
- /articles/4
- /articles/5

娘「↑この5つのパスがあるってことをNext.jsに伝えるために」

```diff_tsx:/pages/articles/[id].tsx
const paths = [
  {
    params: {
      id: "1",
    },
  },
  {
    params: {
      id: "2",
    },
  },
  {
    params: {
      id: "3",
    },
  },
  {
    params: {
      id: "4",
    },
  },
  {
    params: {
      id: "5",
    },
  },
]
```

娘「↑こういう、`paths`っていう配列を作ってあげないといけないの」

ワイ「ほうほう」
ワイ「`paths`に入れておいた分だけ」
ワイ「HTMLファイルが生成されるってことかいな？」

娘「そうだよ」
娘「今回の例だと`getStaticPaths`関数に書く内容は・・・」

### getStaticPaths
```diff_tsx:/pages/articles/[id].tsx
export const getStaticPaths: GetStaticPaths = async () => {
  // 記事一覧APIからデータを取得
  const articles = await fetch("https://api.example.com/articles").then<Article[]>(res => res.json())

  const paths = articles.map((article) => ({
    params: {
      id: String(article.id)
    },
  }))
  return { paths }
}
```

娘「↑こんな感じだね」

ワイ「ほー」
ワイ「記事一覧のデータをAPIから取得して」
ワイ「その一覧データを元に、`paths`の配列を作ってやるんやね」

娘「そう」
娘「そうしておくと、全記事ぶんのHTMLファイルが静的生成されるの」

ワイ「なるほどなー」

1. ビルド時に、APIからデータを取得する
1. そのデータをもとに、記事の内容が書かれたHTMLを生成する  
  （全記事ぶん生成する）

ワイ「↑これをビルドの時にやっておくから」
ワイ「閲覧者さんがブログ記事にアクセスしてくれた時には」
ワイ「爆速でHTMLをご提供することができるんやな」

娘「そうだね」
娘「閲覧者さんは、API通信を待たずに」
娘「すぐにブログ記事の内容を読むことができるね」

ワイ「なるほどなー」
ワイ「ワイもSGしてみたくなってきたな」

# SGが向いていないケースもある

ワイ「今度、**Twitter**みたいなサイトを自作するんやけど」
ワイ「そのサイトにも**SG**を導入してみよかな！」
ワイ「そうすれば、閲覧者さんが爆速でタイムラインの情報を見れるやろ？」

娘「うーん、無理そうじゃない？」

ワイ「へ、なんで・・・？」

娘「例えば、タイムラインのURLが」

`https://example.com/home`

娘「↑こういうURLだったとしてさ」
娘「ログインしているユーザーさんによって」
娘「タイムラインに表示されるツイートは違うでしょ？」

ワイ「せやで」
ワイ「そのユーザーさんがフォローしてる人達のツイートが」
ワイ「タイムラインに一覧表示されるわけやから」
ワイ「同じURLでも、ページの内容は人それぞれ違うで」

娘「そうだよね」
娘「じゃあ・・・」

> サーバ「HTMLファイルは事前に用意してあるから」
> サーバ「アクセスが来たら、生成済みのHTMLを返すだけ！」

娘「↑こんなことできないじゃん」

ワイ「あ、そっか・・・」
ワイ「誰がアクセスしてきたかによって」
ワイ「違った内容のHTMLを返さなアカンわけやもんな」

娘「そうそう」

ワイ「じゃあ、こんな場合はどうや？」
ワイ「今度、**会員制のショッピングサイト**を作る予定なんやけ」

娘「（食い気味に）無理だね」

ワイ「そうなんか・・・」

娘「だって、会員制サイトっていうことは」
娘「ログインしてないと、商品のページとか見れないんでしょ？」

ワイ「せや」

娘「じゃあ」

> サーバ「ログイン済みの人がアクセスしてきた場合には」
> サーバ「商品の内容が書かれたHTMLを返すで！」
> サーバ「ログインしてない人がアクセスしてきた場合には」
> サーバ「ログインボタンが表示されたHTMLを返すで！」

娘「↑こういう処理が必要でしょ？」

ワイ「そうか・・・」
ワイ「ってことは」

> サーバ「アクセスが来たら、生成済みのHTMLを返すだけ！」

ワイ「↑こうはできないわけやな・・・」

# まとめ

### SGとは
- Static Generation → 「静的生成」の略
### SGするメリット
- ユーザーがサイトに訪れた際に、爆速でHTMLを提供できる
    - ビルド時にAPIと通信して、事前にHTMLの中身を作成しておくため
### SGが向かないケース
- アクセスが来るまで、返すべきHTMLの内容が確定しないページ
    - 例
        - Twitterのタイムラインとか
            - 閲覧するユーザーによって、HTMLの内容が変わるため
        - ログインが必要なサイト
            - ログインしているかどうかによって、HTMLの内容が変わるため
### SGのやり方（Next.jsの場合）
- ページのtsxファイルに`getStaticPaths`や`getStaticProps`という関数を書いて`export`する[^2]


ワイ「↑こんな感じやな！」

娘「そうだね！」
娘「ほかにも、Next.jsを使っていると」

- ページ単位で「SGする or SGしない」を選択できる
- SGするページでも「一部だけCSR」ということもできる
    - 例
        - 記事の内容は、SGしておくことで爆速表示
        - コメントの内容は、CSRすることで最新のものを反映

娘「↑こんなことも、割と簡単にできるよ」

ワイ「へ〜、**SG**と**CSR**を組み合わせることもできるんや」

娘「そうだよ〜」

# OGPの表示にも有利
娘「SGは、**OGP**の表示にも有利だよ」
娘「HTMLを生成するときに、`meta`タグのOGP情報も全部書いておけば」
娘「**SPAでよくあるOGP問題**も回避できるじゃん？」

ワイ「そうなんや」
ワイ「そういえば、SPAでOGP画像をいい感じに表示するには」
ワイ「**SSR**をしないと、上手く行かなかったりするもんな」

娘「そうだね」
娘「その辺りのことは、[パパが素性を隠して書いたZennの記事](https://zenn.dev/tokumoto/articles/0098b3e850676f)を読み返してみるといいかもね」
娘「とにかく、事前に静的生成ができるケースなら」
娘「できるだけSGしておいた方がいいと思う！」
娘「[Next.jsの公式ドキュメント](https://nextjs.org/docs/basic-features/pages#static-generation-recommended)にも」

> Static Generation (Recommended)

娘「↑こう`推奨`って書いてあるんだ」

ワイ「ほぇ〜、勉強になるわ」

# その日の夜
ワイ「あー、今日も娘ちゃんのおかげで」
ワイ「またひとつ賢くなったで」
ワイ「もう少しでワイも**チーフ・エンジニア**になれるんちゃうか？」
ワイ「へへっ」

娘「パパ、すご〜い！」
娘「**シーフ・エンジニア**になるの？」

ワイ「いや**シーフ**[^3]ちゃうわ」
ワイ「誰が**給料泥棒エンジニア**やねん」


**〜おしまい〜**

# おまけ：誤解しそうなポイント
- 全ページを静的生成しても、MPA（マルチページ・アプリケーション）になるわけではありません
    - 初回ロードした後のページ遷移は、SPA的な動作になります

# 続編はこちらやで！
- [6歳娘「パパ、静的生成は色んな場面で使えるんだよ？」](https://qiita.com/Yametaro/items/3363b1f996714af1b451)

[^1]:静的生成後、自動的にサーバにデプロイすることが多いと思うので、実際にはほぼ同時に行われます。
[^2]:ページコンポーネント側で、それを`props`として受け取る必要があります。
[^3]:「泥棒」「盗人」を意味する言葉