エンジニア転職して、早いもので半年が経過しようとしています。
最近業務ではNext.jsで実装をしていますが、アウトプットも兼ねて学んだことを簡単にまとめていこうと思います。
Next.jsとは
Next.jsとは、Reactの機能を拡張するためのJavaScriptフレームワークです。
2016年にVercel社によりバージョン1.0がリリースされ、現在も開発が継続されています。
Next.jsの特徴
SSR(Server Side Rendering)とSSG(Static Site Generator)
Reactは**SPA(Single Page Application)**として単一の巨大なJavaScriptを生成します。
SPAはブラウザによるページ遷移を行わずにコンテンツの切り替えなどを行うことで、ユーザー体験(UX)を大きく向上させることができますが、今までサーバー側で行っていたHTML生成をブラウザ側で行うことになるため、
- 初期ローディングの時間がかかったり、
- 通常のWebページと比べSEOの面で不利になる
というデメリットがあります。
それに対して、Next.jsはアプリケーションを事前にページ単位でレンダリングします。
クライアント側からのリクエスト時にレンダリングするのが**SSR(Server Side Rendering)と呼ばれる機能です。
また2020年3月リリースのv9.3より、ビルド時にレンダリングするSSG(Static Site Generation)**と呼ばれる機能も追加されました。
これらの機能により、各ページ読み込み時のダウンロードファイルサイズを削減できます。
またURLごとに個別のHTMLが生成されるので、SEOに有利です。
ちなみに、SSRとSSGの切り替えはビルド時にNext.jsが自動的に判断します。
getServerSidePropsなどSSR用のメソッドが使われていればビルド時には静的ファイルを作成しません。
反対に、それらが使われていなければビルド時に自動で静的ファイルの生成までやってくれます。(素晴らしい・・・)
Next.jsはSSRのためのフレームワークではない
Next.jsはSSRのためのフレームワークという印象がありましたが、現在(v11.0)、下記のとおりStatic Site Generation(SSG)が推奨されています。
We recommend using Static Generation over Server-side Rendering for performance reasons. Statically generated pages can be cached by CDN with no extra configuration to boost performance.
Basic Features: Pages | Next.js
SSGは、ビルド時にすべてのページを生成するため、リクエストごとにページ生成するSSRよりも高速です。
Next.jsはこのパフォーマンスをウリにしていて、**「どや、ウチの速いやろ・・・ええからSSG使ってみ」**と言ってるわけなんですね。
ISG(Incremental Static Generation)
SSGでは、getStaticProps関数により、ビルド時にデータを取得してページにデータを渡すことができます。
export async function getStaticProps(context) {
return {
props: { 渡したいデータ },
}
}
また、getStaticPaths関数により、一覧ページ→詳細ページのような動的な(臨機応変な、柔軟な)ページ遷移にも対応しています。
export async function getStaticProps(context) {
const postId = context.params.id // context.paramsによりpathsで指定したparamsを参照
const post = postIDによるpostデータ取得処理
return {
props: { postId, post },
}
}
export async function getStaticPaths() {
return {
paths: [ // 生成されるページのURLのパス一覧
{ params: { id: 'my-first-post' } },
{ params: { id: 'my-second-post' } },
{ params: { id: 'my-third-post' } },
],
fallback: false
}
}
上記コードでは、https://example.com/posts/選んだid
にアクセスすると、idに対応したデータ内容が表示されたページを取得することができます。
getStaticPaths関数には必ずfallbackキーを記述します。
pathsにないパスに対してリクエストがあったときに、fallbackキーの値によって挙動の違いがあります。
false
:404ページを返す
true
:まずはデータ取得が必要な部分以外を返してからデータ取得が行われる
blocking
:”データ取得が必要な部分以外を返す”という動作をブロックして(=行わず)、データ取得が終わってからページ全体を返す(v10より追加)
getStaticPaths関数の例のように、段階的に(クライアント側からのリクエストにより)ページが静的に生成される機能の総称を**ISG(Incremental Static Generation)**といいます。
SSGの問題点
SSGは前述のとおりビルド時にデータを取得してページに表示します。
ここで問題が発生します。
ビルド以降、データが更新されたらページに反映されないのです。
(例:一覧データが増えても反映されない)
外部データの取得をクライアント側で行うと、結局CSRによって成り立っているのと同じ。
なるべくSSGを使いたいが、規模が大きくなるほど使い勝手が悪くなる・・
そこでv9.4より登場したのがISRです!
ISR(Incremental Static Regeneration)
直訳すると"段階的静的再生成"とあるように、
ISRはクライアント側のリクエストに対しビルド時に生成された静的ページを返し、かつバックグラウンドで一定期間ごとに静的ページの再生成をサーバー側で行います。
これにより、SSGの問題点に対応できます!
getStaticProps関数にrevalidateを追加
具体的にコードで見ます。
export async function getStaticProps(context) {
const postId = context.params.id
const post = postIDによるpostデータ取得処理
return {
props: { postId, post },
revalidate: 30, // ここを追加
}
}
getStaticProps 関数から return するオブジェクトの中で、revalidateというキーに対して秒数を指定します。ここでは30秒を指定しています。
つまり30秒経過後クライアント側からリクエストがあったら、
クライアントには既に生成されたページを見せつつ、バックグラウンドでデータの再取得及び再レンダリングを行いページを再生成し、次のリクエストに対しては再生成されたページを返します。
これによって、データの変化も反映することができます。
おわりに
最近はもっぱらNext.jsでの開発です。
ふだんはNotionにまとめてますが、第三者に見える形でのアウトプットも大切ですね。
なにか内容に誤りがあればご指摘ください。