Diary of a Perpetual Student

Perpetual Student: A person who remains at university far beyond the normal period

Next.js の Static Site Generation (SSG) = Static Exports だと思い込んでいたが違った

blog.arthur1.dev

上記エントリ公開時の原題は「【令和最新版】Next.js の Static Generation で i18n すると疲弊する【App Router 対応】」であったが、現在は表現を訂正し上記のようになっている。その経緯についてのまとめ。

すれ違いと気づき

先ほどのエントリを公開したところ、middleware でパスを置換すれば Static Site Generation (SSG) でも綺麗に書けそうというご指摘をいただいた。それを聞いた僕は「あれ待てよ?middleware 使うと静的ファイルに書き出せないよな?」と思ったのである。

実際にドキュメントにはこう書いてある。

Features that require a Node.js server, or dynamic logic that cannot be computed during the build process, are not supported:

  • Internationalized Routing

  • Middleware

https://nextjs.org/docs/pages/building-your-application/deploying/static-exports#unsupported-features

このやり取りのすれ違いの原因は、自分が SSG = Static Exports だと思い込んでいたことにあると後に気づいた。実際、先のエントリの訂正前の文章では Static Exports ではなくほとんど Static Generation という表現を用いて説明していた。

では Static Generation とは何か

試しに、next.config.js から output: 'export', の行を消して build してみると、静的な HTML ファイルを out/ ディレクトリに書き出さないのにも関わらず、SSG という文字列が現れていた。

Route (app)                                Size     First Load JS
┌ ○ /                                      0 B                0 B
├ ● /[lang]                                149 B          77.3 kB
├   └ /en
├ ● /[lang]/sample                         148 B          77.3 kB
├   └ /en/sample
├ ○ /favicon.ico                           0 B                0 B
└ ○ /sample                                0 B                0 B
+ First Load JS shared by all              77.1 kB
  ├ chunks/346-cf8b208bfc478e69.js         24.7 kB
  ├ chunks/3d471aef-9bd9359a60e55170.js    50.5 kB
  ├ chunks/main-app-a12cf6d5802ab2cc.js    207 B
  └ chunks/webpack-23701e5bacce31e3.js     1.65 kB

Route (pages)                              Size     First Load JS
─ ○ /404                                   179 B          83.9 kB
+ First Load JS shared by all              83.7 kB
  ├ chunks/main-7447017dc4365986.js        81.9 kB
  ├ chunks/pages/_app-a8c73752e3b5827f.js  191 B
  └ chunks/webpack-23701e5bacce31e3.js     1.65 kB

○  (Static)  automatically rendered as static HTML (uses no initial props)
●  (SSG)     automatically generated as static HTML + JSON (uses getStaticProps)

SSG はレンダリングモードの1つで、getStaticProps 関数を用い、ページ生成に必要なデータをビルド時にあらかじめリクエストしておく手法を指すということである。実際、Static Exports はしていないので out/ ディレクトリにファイルは生成されないが、.next/server の中に生成された HTML ファイルが埋め込まれていた。next start してサーバを動かした時にこの HTML ファイルが帰るという仕組みだろう。

一方で、Static Exports は、next.config.js に output: 'export', と書き、Node.js が動くサーバを必要としない環境向けに HTML などのリソースを out/ ディレクトリに書き出すようにすることを指すのである。

実際、レンダリングモードが SSR にならざるを得ないアプリケーションを Static Exports することはないだろうから、混同するのも仕方ないとは思う。

余談: SSG か SG か

Next.js のドキュメントの表現が一時期 Static Site Generation ではなく Static Generation だった時期があったはず。その頃の影響を受けて僕は頑なに Static Generation (SG) と呼んでいたのだけれど、App Router の色々でまた改められていて SSG と読んだ方が良さそうだった。SG 警察引退です。