Gatsbyjs って SSG だよね?あれ、 SSG ってなんだっけ?

発端

このサイトは Gatsbyjs で生成されたファイル群を Netlify でホストしている。 ある日、自分のサイトの表示を確認していたら、リロード時に投稿日時の表示が GMT から JST に変わる様子が視認できた。

あれ?markdown では確かに GMT だけど、JST への変換は gatsby build 時に行われて「JST の文字列」が html に書かれるんじゃないの?

確認してみると gatsby build で生成された html の投稿日時は JST だった。 そして、*.html, *.css の他に *.js が生成されており、これは React/Vue/Angular などの CSR(Client Side Rendering) サイトの特徴だ。

え、「CSR するサイトを生成すること」も SSG(Static Site Generating) に含まれるの? と思ったのが発端。

それまでの私の認識は、SSG = *.html, *.css, *.png など、「古き良きホームページの構成要素」が出力されるもの、だったから。

最も有名は SSG といえば Jekyll だし、それは Markdown から *.html を生成するもので間違いはないだろうし。

最小のサンプルを作って試してみる

次のような「最小の gatsby の Hello world」を作った。

src/pages/index.js

import React from 'react'

const HomePage = () => {
  return (
    <div>Hello world!</div>
  )
}
export default HomePage

gatsby-config.js

module.exports = {
  siteMetadata: {
    title: 'My Gatsby Site',
    description: 'This is my Gatsby site.',
    author: 'My Name',
  },
  plugins: [],
}

package.json

{
  "name": "gatsbymini",
  "version": "1.0.0",
  "description": "",
  "main": "index.js",
  "keywords": [],
  "author": "",
  "license": "ISC",
  "dependencies": {
    "gatsby": "^5.7.0",
    "react": "^18.2.0",
    "react-dom": "^18.2.0"
  },
  "scripts": {
    "test": "echo \"Error: no test specified\" && exit 1",
    "develop": "gatsby develop",
    "build": "gatsby build",
    "serve": "gatsby serve"
  }  
}

これを gatsby build すると、 public/ ディレクトリに次のような index.html と、いくつかの *.js などが出力される。

public/index.html

<!DOCTYPE html>
<html>
  <head>
    <meta charSet="utf-8"/>
    <meta http-equiv="x-ua-compatible" content="ie=edge"/>
    <meta name="viewport" content="width=device-width, initial-scale=1, shrink-to-fit=no"/>
    <meta name="generator" content="Gatsby 5.7.0"/>
  </head>
  <body>
    <div id="___gatsby">
      <div style="outline:none" tabindex="-1" id="gatsby-focus-wrapper">
        <div>Hello world!</div>
      </div>
      <div id="gatsby-announcer" style="position:absolute;top:0;width:1px;height:1px;padding:0;overflow:hidden;clip:rect(0, 0, 0, 0);white-space:nowrap;border:0" aria-live="assertive" aria-atomic="true"></div>
    </div>
    <script id="gatsby-script-loader">/*<![CDATA[*/window.pagePath="/";/*]]>*/</script><!-- slice-start id="_gatsby-scripts-1" -->
    <script
      id="gatsby-chunk-mapping"
      >
      window.___chunkMapping="{\"app\":[\"/app-19037ddcfabde777febe.js\"],\"component---src-pages-index-js\":[\"/component---src-pages-index-js-b35072cae28043e05806.js\"]}";
    </script>
    <script>window.___webpackCompilationHash="3308ca4ed1aafa6ab63e";</script>
    <script src="/webpack-runtime-a34c0a0695f5c7266b7e.js" async></script>
    <script src="/framework-70758cb7368d39225c7b.js" async></script>
    <script src="/app-19037ddcfabde777febe.js" async></script><!-- slice-end id="_gatsby-scripts-1" -->
  </body>
</html>

index.js の body 内は確かに「古き良き HTML」として出力されているが、様々な *.js が読み込まれ CSR の準備がされているように見える。

が、残念ながら自分のブログで発生している「リロード時に投稿日時の表示が ISO形式 から YYYY/MM/DD HH:mm形式 に変わる」は再現できなかった、これは別な原因があるのだろう。

Gatsbyjs とは何であり、何でないか

消去法でいくと、gatsby 自体は(開発目的以外では)サーバー機能を提供しないので「Gatsbyjs は SSR ではない」というのは調べるまでもないと思ったのだが、

には、SSR について次のように記述されている。

Unlike SSG, Deferred Static Generation requires you to keep the build server running after the initial build (using the gatsby serve command). It implies a different deployment model and requires backend infrastructure. But don’t worry: Gatsby Cloud supports it out-of-the-box.

gatsby serve って gatsby develop の alias だと思ってたんだけど違くて、SSR 用のコマンドだったんだね。そして Gatsby Cloud というサービスもあるらしい。

そんな過程で「Gatsbyjs って結局いったい何なんだ?」となったので、一通りしらべてみた。

SSR vs SSG の文脈では

(リクエスト時にサーバーサイドで html を返却するのか、事前に html ファイルを生成するのか)

CSR vs Not CSR の文脈では

クライアントサイドで JavaScript 技術を使用して動的に DOM を書き換えるのか、JavaScript は基本的に使用せず "古き良き" HTML であるのか(これは gatsby build された結果に CSR 要素(React) が含まれる(=CSR)か否(Not CSR1)か、とも言える。)

  • CSR も Not CSR もできる
    • これは既定では Hybrid である模様
      • 前述の通り、最小の Hello World を build すると index.html<div>Hello World!</div> と共に、CSR のために使われそうな script(*.js) も出力されているため
  • 「CSR は局所的にしか使わない」場合は Partial Hydration という選択肢もある
    • Partial Hydration を有効にした場合、基本的には "Not CSR" になる
      • Client components であるとマーク(use client)した場合にのみ、Hydration が行われ "CSR" になる
        • gatsby@5.0.0 で加わった機能で(2023年3月)現在はBeta

今回分かったことは

  • Getsbyjs は基本的に、 「"CSR可能なサイト" を生成する SSG」 である
  • 生成されるサイトが CSR するかしないかは、SSG の構成要素ではない(どっちでもいい)
  • Gatsbyjs で Jekyll 相当の「CSR しないサイト生成」を強制するには「Partial Hydration」を使う(ただし現状BETA)
  • Gatsbyjs は SSG だけでなく SSR もできる

  1. CSR(Client Side Rendering) の対義語が SSR(Server Side Rendering) であるのが一般的なのだろうけど、本記事では SSG に主体を置いていることから SSG の対義語として SSR を使った。そのためそれと混同しないように CSR の対義語を "Not CSR" としている。