Next.jsでSSRの挙動を確認してまとめてみる
背景
実務ではReactを使っているのですがNext.jsのキャッチアップしておきたいと思ったので、その内容を整理したいと思います。
本記事では、Next.jsに関する情報をまとめています。
内容は易しめです。
プリレンダリング
Next.jsを本番環境で実行する場合、事前にビルド作業を行い、本番環境で実行するためのアプリケーションを生成します。
このとき、作成されたページは事前に表示内容をレンダリングして生成し、それを実際に表示するページとしてファイルに保存します。
これらの処理を「**プリレンダリング**
」と呼びます。
リアルタイム更新されないものは静的ページへ
Reactを利用したページは、基本的にすべてクライアント側で処理が動く動的ページになっています。
Next.jsでは、SSR(サーバーサイドレンダリング)とSSG(静的サイトジェネレーション)といった技術を活用することで、Reactで開発されたページでも静的ページに変換することが可能です。特に、変化がないものやあらかじめ決まっているものについては、静的ページに変換することで、サーバーとクライアントの負担を減らすことができます。
フレームワークごとの特徴
以下は、主な言語やフレームワークとそのページ生成手法、およびプリレンダリングが行われるかどうかについてまとめた表です。
言語・フレームワーク | 手法 | 特徴 | プリレンダリング |
---|---|---|---|
React | CSR | ブラウザでJavaScriptを実行し、動的にページを生成する。 | プリレンダリングされない。 |
Next.js | SSG、SSR、ISR | getStaticProps、getStaticPaths、getServerSidePropsなどのメソッドを使い分けることで、SSGやSSR、ISRを実現する仕組みになっている | 静的ページはプリレンダリングされる。動的なページは、ビルド時またはアクセス時にプリレンダリングされる。 |
Nuxt.js | SSG、SSR | asyncData、fetchなどのメソッドを使い分けることで、SSRやSSGを柔軟に実現することができる | Nextと同様 |
Vue.js | CSR、SSR | ブラウザでJavaScriptを実行し、動的にページを生成する。Vue.jsの公式ライブラリであるVue SSRを使えばSSRを実現できる。 | プリレンダリングをするにはvue-server-rendererなどのライブラリが必要 |
SSRでは、初期表示時にサーバー側でHTMLを生成し、クライアント側でのレンダリングを省略することができます。
一方、SSGでは、ビルド時に必要なページを事前に生成し、静的なHTMLファイルとして保存することができるためリクエスト毎にサーバーサイドでの処理を行う必要がなくなり、高速なページ表示が可能になります。
サーバー側から必要な情報を取得する関数 - Next.js
Next.jsには、サーバー側から必要な情報を取得するための仕組みとして以下の2つの機能が用意されています。
getServerSideProps関数 - リクエストごとにSSRを行う
動的なページを生成するための関数です。
リクエスト毎にサーバーサイドで実行され、外部データを取得してページを生成するための情報を提供します。
サーバーサイドでの処理が必要になるため、負荷が高くなる場合もあります。
getStaticProps関数 -
静的なページを生成するための関数です。
この関数はビルド時に実行され、外部データを取得してページを生成するための情報を提供します。
また、この関数はビルド時に一度だけ実行されるため、サーバーサイドでの処理を減らすことができますが、動的なページの生成には適していません。
プリレンダリングの実行タイミング - SSG
SSGの場合はアプリケーションをビルドする際にプリレンダリングが実行されて静的ファイルに変換されたものが保存・出力されます。
ビルドの際にgetStaticPropsが実行され外部データが取得されます。そうして得られたデータも含めて静的ファイルとして保存されます。
プリレンダリングの実行タイミング - SSR
SSRの場合、クライアントがアクセスすると、その度にgetServerSidePropsが実行され、サーバー側で取得したデータを使ってプリ・レンダリングが実行されます。
ビルド時にはまだデータは組み込まれておらず、クライアントからアクセスがあるとその場で静的コードが生成されます。
サーバー側で静的コードを生成して表示する点は同じですが、挙動はそれぞれ異なります
実際に触ってみる
下記の通り適当なJSONデータを作成しました。
public/ data.json
[ { "text": "This is an example text.", "author": "yano", "email": "yano@example.com" }, { "text": "これはサンプルのテキストです。", "author": "やの", "email": "ya@example.com" } ]
data.jsonからデータを取得し表示する
以下の例ではfetchメソッドの引数に、上で作成したJSONファイルのURLを指定して呼びだし、レスポンスをUIに反映させています。
import Head from 'next/head' type Data = { text: string; author: string; email: string; } type HomeProps = { data: Data[]; } export async function getServerSideProps(context) { const res = await fetch("http://localhost:3000/data.json"); const data = await res.json(); console.log(data); return { props: { data } }; } export default function Home(props: HomeProps) { return ( <div> <Head> <title>My Sample App</title> </Head> <main className="container"> <h2>Index page.</h2> <p>これは、サンプルで作成したページです。</p> {props.data.map((item, index) => ( <div key={index} className="alert alert-primary my-3"> <p className="h5">msg: "{item.text}".</p> <p className="h6">by {item.author}. ({item.email})</p> </div> ))} </main> </div> ) }
サーバーログを確認する
**getServerSideProps()**
でリクエストを実行しているため、サーバー側で関数内の処理が実行されて、画面のレンダリングが行われます。
以下はサーバーログです。
wait - compiling... event - compiled client and server successfully in 69 ms (169 modules) [ { text: 'This is an example text.', author: 'yano', email: 'yano@example.com' }, { text: 'これはサンプルのテキストです。', author: 'やの', email: 'ya@example.com' } ]
JavaScriptもサーバー側で実行されるため、console.log();はブラウザのコンソールではなくサーバーのログで確認することができます。
getServerSidePropsの処理内容
ここでは、fetch関数を使ってurlからJSONデータを取得しています。
// my-next-app/pages/index.js const result = await fetch(url) const data = await result.json()
fetchでデータを取得した後、jsonメソッドでJSONデータをオブジェクトとして取り出しています。そしてレスポンスのdataをreturnします。
return { props: { data } };
続く…
コメント
本記事の内容は以上になります!
続きのアウトプットも随時更新したいと思います。
間違いがありましたら修正いたしますので、ご指摘ください。
興味があれば他の記事も更新していきますので是非ご覧になってください♪
プログラミングスクールのご紹介 (卒業生より)
お世話になったプログラミングスクールであるRUNTEQです♪
こちらのリンクを経由すると1万円引きになります。
RUNTEQを通じて開発学習の末、受託開発企業をご紹介いただき、現在も双方とご縁があります。
もし、興味がありましたらお気軽にコメントか、TwitterのDMでお声掛けください。