Open7

Next.js 12.2で、On-Demand ISRのstableがリリース

概要

Next.js 12.2で、On-Demand ISRのstableがリリース

https://nextjs.org/blog/next-12-2?utm_source=next-site&utm_medium=banner&utm_campaign=next-website#on-demand-incremental-static-regeneration-stable
  • On-Demand ISRについて
    • 再度デプロイしなくても、サイトのコンテンツを更新可能
    • ヘッドレス CMSなどによるデータ更新時に、下記のAPIをコールしコンテンツを更新する
      - Vercelだと300msec程度でグローバル伝播するとのこと

※ ソースコードは公式ドキュメントから引用

// pages/api/revalidate.js

export default async function handler(req, res) {
  // Check for secret to confirm this is a valid request
  if (req.query.secret !== process.env.MY_SECRET_TOKEN) {
    return res.status(401).json({ message: 'Invalid token' });
  }

  try {
    await res.revalidate('/path-to-revalidate');
    return res.json({ revalidated: true });
  } catch (err) {
    // If there was an error, Next.js will continue
    // to show the last successfully generated page
    return res.status(500).send('Error revalidating');
  }
}

On-Demand ISRがいまいちパッとしない方向けに

そもそもOn-Demand ISRの前に遡って順に大枠を理解する。
下記はNext.js前提の説明。

  1. Pre-renderingについて
  2. Pre-renderingの種類について
  3. ISRについて

Pre-renderingについて

  • Next.jsは全てのページ(HTML)を、Backend側で事前に作成する
  • 生成された各HTMLは、そのページに必要な最小限のJavaScriptコードと関連づけられ、ページ読み込み時にインタラクティブになる
  • 事前に取得したいデータがある場合は、APIを事前にコールするように実装する必要あり(getServerSideProps)

No Pre-renderingについて

  • 読み込み時は空のページ
  • ページ読み込み後に、クライアントで全て描画する

Pre-renderingの種類について

Static Generation

  • ビルド時にHTMLを生成する

Server-side Rendering

  • リクエストごとにHTMLを生成する

参照

https://nextjs.org/docs/basic-features/data-fetching/incremental-static-regeneration

https://vercel.com/docs/concepts/next.js/incremental-static-regeneration

ISR(Incremental Static Regeneration)について

  • ビルド時に一定数のHTMLを生成する
    • ビルド時間長くなるので、人気コンテンツに絞り生成するとよい(getStaticPaths)
  • HTMLが生成されていれば、そのHTMLを表示する
    • クライアントにはキャッシュされたHTMLを返しつつ、キャッシュの時間が過ぎていれば、その後HTMLを再生成する
  • HTMLが生成されていなければ、HTMLを生成し、そのHTMLを表示する

※ ドキュメントから引用

function Blog({ posts }) {
  return (
    <ul>
      {posts.map((post) => (
        <li key={post.id}>{post.title}</li>
      ))}
    </ul>
  )
}

// This function gets called at build time on server-side.
// It may be called again, on a serverless function, if
// revalidation is enabled and a new request comes in
export async function getStaticProps() {
  const res = await fetch('https://.../posts')
  const posts = await res.json()

  return {
    props: {
      posts,
    },
    // Next.js will attempt to re-generate the page:
    // - When a request comes in
    // - At most once every 10 seconds
    revalidate: 10, // In seconds
  }
}

// This function gets called at build time on server-side.
// It may be called again, on a serverless function, if
// the path has not been generated.
export async function getStaticPaths() {
  const res = await fetch('https://.../posts')
  const posts = await res.json()

  // Get the paths we want to pre-render based on posts
  const paths = posts.map((post) => ({
    params: { id: post.id },
  }))

  // We'll pre-render only these paths at build time.
  // { fallback: blocking } will server-render pages
  // on-demand if the path doesn't exist.
  return { paths, fallback: 'blocking' }
}

export default Blog

On-demand Revalidationについて

  • 更新用APIを作成して、更新用APIが呼ばれなければキャッシュを更新しない様に変更
  • 上記の時間指定と組み合わせることも可能
https://<your-site.com>/api/revalidate?secret=<token>

補足

上記のISRで実現したいキャッシュ関連の機能は、SSRでも実現可能。
※ ただしISRはキャッシュだけではない。以前のデプロイ時のページにロールバックするなども可能

SSRでリクエストごとに生成したHTMLを、CDNのキャッシュに乗せる。
CDNの機能として、時間でキャッシュ破棄しても良いし、特定のタイミングでInstant Purge(即時削除)をしても良い。

ここで説明しているISRのキャッシュ機構に関しては、Next.jsとVercelを組み合わせることで、ものすごく簡単に実現できることが素晴らしい点。

作成者以外のコメントは許可されていません