私がISR にした理由は、ユーザー体験ではない。
SEO対策として、Google Bot が、ページの本文を HTML として読めるようにしたかった。
- 対象は、公開中の 新商品お菓子まとめ
- 目的は Google Bot が商品名を HTML で読めること。速さや「使いやすさ」が先ではない
- ISR は、一度作った HTML を出しておき、あとから背景で作り直すやり方
- 人の画面が速くなる可能性はある。ただし今回は測っていないので、「体験が良くなった」とは書かない
- 手順のコピペはしない。公開中のサイトで、なぜ ISR を選んだかだけ書く
Tomoya個人開発を始めたころ、ISR という略語だけが先に来た。
知りたかったのは「自分の公開中サイトで、何が変わるか」だった。
表示のやり方としての方法として「ISR」を採用した。
初めて聞く言葉だったが、AIに説明してもらいながら理解し、採用に至った。
なぜ変えたか。Google Bot に本文を読ませたかった
TomoyaSnackサイトは、お菓子の新商品だけを横断するサイトだ。
トップに「今週の新作」があり、週次・月次のページもある。
読者は人だけではない。検索から来る前に、Google Bot がページを読む。
Bot が読むのは、ブラウザで見たきれいな画面そのものではない。HTML に書いてある文字だ。JavaScript が後から商品名を描く作りだと、人が見えているのに Bot 側は空、ということが起きうる。
今回 ISR にしたのは、ここを避けるためだった。
一度 HTML として商品名が入ったページを出しておき、新商品が増えたら背景で作り直す。
変更前は、商品一覧をブラウザ側で丸ごとレンダリングしていた(CSR)。ページの骨組みだけが先に届き、そのあとJavaScriptが商品名を描き足す作りだったので、人の目には見えていてもBotが読むタイミングによっては空、ということが起きていた。
Tomoyaユーザー体験を良くしたくて選んだのではない。
読者は、表示速度や内容そのものに不満を感じない限り、裏側のレンダリング方式の違いを意識することはない。だから「体験が良くなるから変えた」とは言えない。今回変えた動機は、あくまでBot側からどう見えるか、その一点だった。

ISRとは何か。SSG・SSR・CSRとの違い
略語が並ぶと、個人開発を始めた人ほど置いていかれる。
公開したサイトで、何が起きるかの違いだけ書く。
| 呼び方 | 公開したサイトで起きること | 向いていること | 今回やらなかった理由 |
|---|---|---|---|
| CSR/Client Side Rendering(ブラウザ側で生成) | 最初に届くHTMLはほぼ空の骨組みで、JavaScriptが動いてから商品名などを描き足す | ログイン後のマイページなど、Botに読ませる必要がない画面 | 実際にこの状態で公開していて、Botが商品名を読めていない可能性があったため、ここからは抜け出したかった |
| SSG/Static Site Generation(静的生成) | 公開する前にHTMLを作っておく。Googleも人も、そのHTMLを読む | ほとんど変わらない説明ページ | お菓子の新商品は、公式側が後から増える。作った時点で止まる |
| SSR/Server Side Rendering(毎回生成) | 見に来るたびに、サーバーがHTMLを作る | その瞬間の本人だけのデータ | 一覧を、来る人ごとに毎回作り直す必要はなかった |
| ISR/Incremental Static Regeneration | 一度作ったHTMLを出す。時間が経ったら、裏側で作り直す | 一覧はHTMLで見せたい。中身は後から増える | 今回これを選んだ |
Tomoyaいちばん短い言い方にすると、こうなる。
- CSR: ブラウザが作る
- SSG: 先に作って、止める
- SSR: 来るたびに作る
- ISR: 先に作って、あとで作り直す
普段の生活で見かける「一瞬あとから文字がフワッと出てくる」動き、あれがCSRだ、と気づければ十分。
Google Bot にとって大事なのは、「HTML に商品名があるか」だ。
CSRはここが弱く、SSGは更新に追いつけない。ISRは、先にHTMLを持っておきつつ、新商品が出たあとの再生成で追いつける。
Tomoyarevalidateは、一定時間ごとに再生成するtime-based方式にした。
ただし設定したのはページそのものではなく、Firestoreから商品データを取ってくる関数の方だった。unstable_cacheでその関数を包み、revalidate: 21600(秒。つまり6時間)を指定している。
週次・月次・テーマ・サイトマップなど、複数のページで同じFirestoreデータを使い回すので、ページ単位ではなくデータ単位でキャッシュを共有する作りにした。


余談だが、このキャッシュ関数の名前はunstable_cacheという。
「unstable」という文字を見た瞬間は事故ったのかと身構えたが、App Routerで公式に用意されているキャッシュの仕組みの一つで、名前の通り「まだ実験的なAPI」というだけの意味。動き自体は普通に使えている。
ユーザー体験にもつながるのか
Tomoya繋がる可能性はあるが今回の目的ではなかった。
人がページを開いたとき、HTML に最初から商品名があれば、文字は先に読める。
JavaScript が終わるのを待たなくていい。結果として、体験に寄ることがある。
ただし今回は、そこを測っていない。
- 表示が速くなった、とは書かない
- 検索順位が上がった、とは書かない
- 「ISR にすれば UX も上がる」とも書かない
Tomoya書けるのは、ここまでだ。
- Google Bot 用に HTML を先に置いた。
- 人の画面にも、同じ HTML が届く。
- 体験の改善は、その副作用になりうる。検証はしていない。
今回は行った事を記事にしたまでであって確実な検証結果としては薄い。しかし目的を持ってシステムを変える事を行った事がポイントになっている。


丸投げしなかった判断
「ISR にして」とだけ AI に渡すと、略語の実装に寄って、Bot に何を読ませるかが抜けやすい。
- 目的は Google Bot が HTML で商品名を読むこと。体験の改善は後回し
- 対象は公開中の snack。新しいデモは作らない
- 人向けの見た目を先に直さない。ソースに文字があるかを先に見る
- 速度の点数で成功扱いにしない
個人開発で、この話が役に立つとき
- 向いている:
-
- もう公開している
- 一覧の中身が、外から増える(公式の新商品など)
- 検索から来てほしい。Bot が空の HTML を読むのが怖い
- 向いていない:
-
- まだ「誰に読ませるか」が口頭のまま
- 速さの点数を上げたくて ISR を探している(今回の理由ではない)
- 手順をコピペして終わりにしたいとき
TomoyaSSG か SSR か ISR かで正解を探す必要はない。
先に決めるのは、「Google に読ませたい文字が、HTML に入っているか」だ。
今回では、その入れ方として ISR を選んだ。
まとめ
- ISR にした理由は、Google Bot が本文を HTML で読めるようにすること
- ユーザー体験が目的ではなかった。同じ HTML が人にも届くので、副作用にはなりうる。測っていない
- SSG は先に作って止める。SSR は来るたびに作る。ISR は先に作って、あとで作り直す
次に略語で迷ったら、実装の名前より先に、ソースを開いて文字があるかを見ればいい。
※本記事は公開中 snack への適用記録です。Next.js の仕様は変わります。順位や速度の保証ではありません。
よくある質問
ISR にすれば検索で上がりますか?
分からない。今回やったのは、Bot が読む HTML に商品名を入れることまで。順位は書いていない。
ユーザー体験は良くなりますか?
目的ではない。HTML が先にあるので、人の画面にも効く可能性はある。測っていないので、良くなったとは書かない。
SSG や SSR の解説記事ではありませんか?
違う。公開中の snack で、なぜ ISR を選んだかの記録。コードの貼り付けはしない。

コメント