追記(2022.05.21)
この記事の内容は既に古いです。
ReactやNext.jsのアップデートはとても早く、便利な機能が次々実装されています。
現時点でのNext.jsを使ったサイトアーキテクチャを詳しく知りたい場合は、以下のコースの受講をお勧めします。
この講師の方の他のコースを受講するとクーポンが発行されたり、またUdemyでは頻繁に値引きセールを行っているので、これらを利用して購入しましょう。(1500円程度で購入できます)
とはいえNext.jsの設計思想自体は変わりません。せっかくこの記事に訪れて頂いたので参考程度に読んでください。
概要
本記事は、Next.jsのSSGを利用した技術とサイトの設計指針についてまとめました。
※ 私自身、Next.jsについてはまだ勉強中で、その備忘録として書いています。
SSG(Static Site Generation|静的サイト生成)
Next.jsでは、**SSG(Static Site Generation|静的サイト生成)**という技術が標準サポートされていて、それを使用することが推奨されています。SSGを使用すると、SEOに有利で、高速に表示されるサイトを作ることができます。
また、SSGを利用してAPIなど外部との通信が発生する処理(時間のかかる処理)を、サイトのビルド時に行い(Pre-fetch)、そのデータを埋め込んだHTMLをあらかじめサーバー側で生成することができます。
詳しく知りたい方は、公式ドキュメントを参照してください。英語ですが図説されているのでわかりやすいです。
Pre-rendering and Data Fetching
日本語がいい!という方は、以下の動画シリーズがおすすめです。
Deploy Hooks
Next.jsを開発しているVercel社は、Hostingサービスも提供しています。
このサービスでは、GitHubに連携してリポジトリ(mainなど)の更新に応じてリビルドする機能や、API経由でリビルドするDeploy Hooksが提供されています。
ISR(Incremental Static Regeneration|段階的な静的サイト生成)
ユーザーがサイトに訪れたときにサイトをリビルドして、次に訪れたユーザーに最新のサイトを提供する機能です。
① ユーザーAが、Vercelサーバーにリクエストを送ります。
② Vercelサーバーは、レスポンスとしてホスティングされたサイト(HTML)を返します。
③ ②と同時に、Vercelサーバーは、更新のあるページ(ISRを指定したページ)だけをリビルドします。
④ ユーザーBが、Vercelサーバーにリクエストを送ります。
⑤ Vercelサーバーは、レスポンスとして③で更新したサイト(HTML)を返します。
revalidateは更新頻度で、コード内でこれを指定することでISR機能を使うことができます。
上図では、ユーザーBは最新のサイトを閲覧できますが、ユーザーAは古いサイトを閲覧することになります。このことから、ISRは、閲覧回数が多いサイト向けの機能です。
revalidateを指定することで、高頻度のサイトアクセスによる過剰な更新を防ぎ、サーバー負荷を減らします。(ゲームでいうところのスキルのクールダウンみたいな感じです)
コード例
export const getStaticProps: GetStaticProps = async () => {
const tasks = await getAllTasksData();
return {
props: { tasks },
revalidate: 3
};
};
getStaticProps
のreturnに、revalidateを指定することで、ISRに対応させたページにします。
Client side Fetching(CSF)
クライアントサイドで、効率よくAPIでデータを取得する方法として、SWRがあります。
キャッシュデータを使うことで過度なAPIリクエストを防ぎ、素早くサイトを表示させます。
これを使って何が嬉しいのかというと、ISRだけでは、ユーザーAは最新のサイトを閲覧できませんでした。
そこで、このSWRと組み合わせることによって、ユーザーAも最新のサイトを閲覧することができます。
下図は、**SSG + ISR + CSF(SWR)**を組み合わせた例です。
① 開発者がサイトをデプロイします。
②②´ Vercelサーバーは、SSGのPre-fetchによりビルド時にAPI経由でデータを取得します。
③③´ ユーザーAがサイトにアクセスします。
③″ クライアントサイドで、API経由で最新のデータを取得します(Client side Fetching)。
④④´ ③のリクエストをトリガーにして、ISRによってリビルドされます。このとき、②´同様にAPI経由でデータを取得します。
※③″と④´でAPIからデータを取得するタイミングはほぼ同じなので、同じでデータになるはずです。(秒単位で更新されるデータの場合は差異が生まれるかもしれません)
⑤⑤´ ユーザーBがサイトにアクセスします。
⑤″ ③″同様、クライアントサイドで、API経由で最新のデータを取得します(Client side Fetching)。
※ユーザーAがサイトに訪れてから、ユーザーBが訪れるまでに、サーバーのデータが更新されていなければ、⑤´の内容と⑤″で取得する内容は同じになります。
コード例
const fetcher = (url: string) => fetch(url).then<TaskType[]>(res => res.json());
type PropsType = {
tasks: TaskType[];
};
const TaskPage: VFC<PropsType> = ({ tasks }) => {
const { data, error } = useSWR(`${process.env.NEXT_PUBLIC_RESTAPI_URL}/api/list-task/`, fetcher, {
initialData: tasks, // ― 2
revalidateOnMount: true // ― 3
});
// 以降、得られた data を使った処理
・・・
}
export default TaskPage
export const getStaticProps: GetStaticProps = async () => {
const tasks = await getAllTasksData(); // ― 1
return {
props: { tasks },
revalidate: 3 // ― 4
};
};
① SSGのPre-fetchで、サーバーサイドでAPIデータを取得します。
② useSWR
のオプション、initialData
にサーバーサイド取得したAPIデータ(tasks)を渡します。
これによって、クライアントサイドでデータが取得できるまでは、サーバーサイドで取得したデータを表示させます。
※このとき、APIデータに更新があると、古いデータ → 新しいデータとレンダリングされるので一瞬だけ古いデータが表示されます。
③ useSWR
のオプション、revalidateOnMount
を指定することで、コンポーネントがマウントされたときに必ずデータを取得するようします。
④ ISRに対応させることで、次にサイトを表示したときに、②で発生していた古いデータが一瞬だけ表示される現象が発生しないようにします。
サイト アーキテクチャ
これらの技術を使うことで、API経由で取得するデータの更新頻度、APIの使用制限、サイトのアクセス頻度に併せてサイトを設計することができます。
※ 以下のモデルは、あくまで一例です。
手動でリビルドする
API経由で取得するデータの更新に併せて、サイトを手動でリビルドします。
条件・状況
・API経由で取得するデータの更新頻度が低い場合(半年に1回、不定期など)
・APIの使用制限が厳しい場合(1時間あたりのリクエスト回数が決まっている、リクエスト回数に応じて料金が発生する)
・サイトのアクセス頻度が低い場合
Deploy Hooks を使う
Deploy Hookに、**Cloud Functions(Cloud Functions for Firebase、 AWS Lambda など)**を組み合わせることで、定期的に自動でリビルドするようにします。(毎日24:00にリビルドするHookを作る)
条件・状況
・API経由で取得するデータの更新頻度がそこそこの場合(数周間に1回、1日に1回など)
・APIの使用制限が厳しい場合(1時間あたりのリクエスト回数が決まっている、リクエスト回数に応じて料金が発生する)
・サイトのアクセス頻度が低い場合
ISR を使う
ISRの項目で紹介した設計を使います。
条件・状況
・API経由で取得するデータの更新頻度が高い場合(数時間に1回、数分に1回など)
・APIの使用制限がそこそこ
厳しい場合(1時間あたりのリクエスト回数が決まっている、リクエスト回数に応じて料金が発生する)
・サイトのアクセス頻度が高い場合
ISR + Client side Fetching を使う
Client side Fetchingの項目で紹介した設計を使います。
条件・状況
・API経由で取得するデータの更新頻度が高い場合(数時間に1回、数分に1回など)
・APIの使用制限がゆるい場合(自社製のAPIサーバーを使うなど)
・サイトのアクセス頻度がそこそこ
高い場合
まとめ
Next.js 面白い。
参考
この記事は、以下のコースの受講に伴って、備忘録としてまとめました。
もっと詳しく知りたい方は、是非受講してみてください。