テクノロジー

【Next.js】On-Demand ISRが安定版になったよ!

Next.js 12.1よりBetaとなったOn-Demand ISRが、6/29にリリースされたNext.js 12.2より安定版となりました!

これでようやく外向けの環境で動作するサービスに使用できるようになったので、今回はこのOn-Demand ISRについて紹介しようと思います。

そもそもOn-Demand ISRとは

On-Demand ISRを説明するには、まずSSGとISRについて説明する必要があります。

SSGとは

SSGとは、Static Site Generationの略で、その名の通り静的サイトを生成する機能のことを指します。

旧来のRailsやLaravelのようなMPA、あるいはRemixのようなSSRフレームワークは、アクセスが発生した段階でサーバーサイドでサイトをレンダリングしますが、SSGはアクセスよりもはるか前、デプロイ前のビルド時 (記述したコードを実際の環境で動作するよう変換する段階) に返却するファイルを生成します。

これにより、SSGされているページではレンダリングの必要がないため、MPAなサイトやSSRのページと比較して高速な描画が期待できます。

欠点として、最新の情報を記載することを苦手としています。
記述内容が変わることのないページや、コードとともに掲載内容を管理している記事ページなどでは有効ですが、チケット販売や天気情報などのリアルタイム性が必要なもの、Headless CMSを用いて記事を管理しているケースでは使用することができません。

これを改善するための機能が、ISRです。

ISRとは

ISRとは、 Incremental Static Regenerationの略称で、SSGしたページを任意の秒数で再生成する機能です。
これを用いることで、天気情報サイトなどの変更頻度が低いものやHeadlessCMSを用いた記事などで気軽にSSGすることが可能になりました。

これは非常に便利なのですが、秒数による制御ではどうしても解決しづらい問題もありました。

記事をHeadlessCMS管理している情報掲載サイトを例として考えてみましょう。

記事には誤字脱字がつきものです。何人で確認しても、いかなツールを使おうとも、どうしても記事に誤字脱字が残ってしまうケースがあります。

そんな時、場合によっては早急に修正することが必要です。
その際、SSGを生かすために長い秒数を設定していると、修正したい内容を早期に反映するには再度デプロイする必要があります。アプリケーション上でいかな操作をしようと、基本的にはどうしようもありません。

これを解消するにはISRの秒数を短くすればよいですが、それではSSGの効果が薄くなります。

こういった状態に公式の機能で対応できるようになったのが、On-Demand ISRです。

On-Demand ISR

On-Demand ISRは、本当に任意のタイミングで再生成を行う機能です。
例えば、ISRの項目で挙げたような記事修正問題が生じた際に、こちらから再生成を指示できます。

この機能を使用する際、ISRの際に必須であった再生成のための秒数指定は必須ではないので、不要な再生成機会の抑制、ひいてはサーバーの負担軽減も期待できます。

On-Demand ISRを使用する

元のSSGのファイルを編集する必要はありません。
On-Demand ISRは元のファイルに一切手を加えずに実行できます。

例として、今回はhttp://example.com/isr/[id]に対象となるページが存在するとします。
このページを対象にISRを行いたい場合は、page/api/に任意の名前 (今回は例としてpage/api/[id].tsx) のファイルを作成し、以下のような処理を記載します

import { NextApiHandler } from "next";

const handler: NextApiHandler = async (req, res) => {
  const secret = req.query.secret ?? req.body.secret

  const id = req.query.id
  if (secret !== process.env.ON_DEMAND_SECRET_TOKEN) {
    return res.status(401).json({ message: 'Invalid token' })
  }

  if (!id) return res.status(404).json({message: 'Not Found'})

  try {
    await res.revalidate(`/isr/${id}`)
    return res.json({ revalidated: true })
  } catch (err) {
    return res.status(500).send('Error revalidating')
  }}

export default handler

内容は、http://example.com/isr/[id]に対してtokenを持たせてPOSTまたはGETを行うと、対象のIDのページを再生成するというものです。
上記のファイルのほとんどはresponseの中身に関するもので、再生成している箇所は以下のみとなっています。

 await res.revalidate(`/isr/${id}`)

この処理を実行させるだけで、対象のページが再生成されます。

注意点

getStaticPathsにおいてfallbackをfalseにしているとき、もともと存在していなかったURLを対象にしてOn-demand ISRを使用することはできません。
あくまで、ISRを任意のタイミングで実行するだけの機能なので、元々生成対象できない場合は対象外です。

終わりに

任意のタイミングで再生成できるようになったことも嬉しいですが、個人的にはrevalidateで秒数指定せずともISRできるようになったことが嬉しいです。
これは、ISRは確かに便利な機能ではあるのものの、秒数指定はそれほどスマートではない手法であると前々から感じていたためです。

この機能追加により、ヘルプや利用規約などの今まではHeadless CMSで管理していなかったようなテキストも管理するようになるかと思いますので、仕事がだいぶ楽になる人もいるかと思います。

この機能はまだまだ気が付けていない使い方などがありそうなので、色々と試してみるのが楽しみです。

※本記事は2022年07月時点の内容です。

テクノロジーの記事一覧
タグ一覧
TOPへ戻る