猫でもわかるWebプログラミング

試行錯誤しながらエンジニア(プログラマー)として働く猫のブログ。技術的な話や、働き方の話、読書録とか、試行錯誤している日常の話。

Next.js で React の Server-side Rendering と Static Generation をやる #3

f:id:yoshiki_utakata:20210215170842p:plain

前回の記事

この記事は第3回の記事です。

今までの記事

今回の概要

今回は、Server-side Rendering (SSR) や、 Static Site Generation (SSG) の説明をします。

SSR と SSG はまとめて Pre-rendering と呼ばれます。

引き続き、Next.js のチュートリアルをベースにやっていきます。今回はこのページからやっていきます。

https://nextjs.org/learn/basics/data-fetching/pre-rendering

Pre-rendering とは

Pre-rendering は、 Server-side Rendering みたいなやつの総称です。 SEO のために必要だったりします。

ただ、最近は、Server-side Rendering しなくても、SEO的には問題なし、ということもあるようです。

https://www.ey-office.com/blog_archive/2019/10/15/react-seo-current-status/

https://www.suzukikenichi.com/blog/you-can-use-angular-react-and-vue-for-google-seo/

話は Next.js に戻って、 Next.js だとデフォルトで Pre-rendering ができるようになっています。

Pre-rendering が動いているかどうか確認する方法として、ブラウザで JavaScript を無効にする、という方法があります。サーバーからサーブされるのは、完全な形の HTML なので、 JavaScript が無効になっていても動きます。

ただし、手元でdevモードで試す場合、JSを無効化するとCSSが読み込まれなくなります。それでも、ページは表示できているので、HTMLで送られてきているのはわかります。

2種類の Pre-rendering

Pre-rendering には 2種類あります。

  • Static Generation: JSのビルド時にページを生成する方法
  • Server-side Rendering: HTTPリクエストが来た時にページを生成する方法

ただし、npm run dev のような、developmentモードの場合、 Static Generation を使っているページでも、 Server-side Rendering になります。手元で変更した差分を、すぐに反映させるためです。

Static Generation を使うか、 Server-side Rendering を使うかは、ページごとに設定可能です。

Static Generation vs Server-side Rendering

レスポンスが早いため、可能な限り Static Generation を使うのを推奨します。

Static Generation with Data を行う

Static Generatin には2種類あります。

  • Static Generation without Data: 外部のデータを必要としない
  • Static Generation with Data: APIとか叩いた結果のデータを使って表示する

Static Generation with Data をする場合は、 getStaticProps 関数をを使います。

ページのコンポーネントを export すると同時に getStaticProps という名前の async な function を export します。

export default function Home(props) { ... }

export async function getStaticProps() {
  // ここにデータ取得処理とかを書く

  // props の値がコンポーネントの props に渡される
  return {
    props: ...
  }
}

試しに getStaticProps を使ってみます。

ルートにpostsというディレクトリを作って、そこに pre-rendering.mdssg-ssr.md を作ります。(pages/posts ではないので注意!!!)

差分は GitHub を見てください: https://github.com/yoshikyoto/nextjs-blog/commit/f374309cb30f69994fd54e7c86a128305ae19c05

markdown ファイルからデータを取得して、 getStaticProps で渡してみようと思います。

まずは、 index.js で記事一覧を表示します。

必要なデータは

  • ファイルの title と date
  • ファイル名(ファイル名を記事のIDとする)

ですので、これらを取得して、Reactコンポーネントに渡してやります。

まずは、markdown をパースするためのライブラリ gray-matter をインストールします。

npm install gray-matter

npm install をしたら、npm を再起動させるために、docker の再起動をします。

docker-compose down
docker-compose up -d

ファイルからデータを取得するJSを書きます。トップディレクトリに lib というディレクトリを作成し、posts.js というファイルを作成します。

コードは長いので、 GitHub の差分を見てください: https://github.com/yoshikyoto/nextjs-blog/commit/f374309cb30f69994fd54e7c86a128305ae19c05

pages/index.jsで、getStaticPropsを追加し、中身は、lib/posts.jsgetSortedPostsData を呼びます。

import { getSortedPostsData } from '../lib/posts'

export async function getStaticProps() {
  const allPostsData = getSortedPostsData()
  return {
    props: {
      allPostsData
    }
  }
}

さらに、Homeコンポーネントで引数として受け取るようにし、中身を表示します。実装は GitHub の差分を見てください: https://github.com/yoshikyoto/nextjs-blog/commit/f374309cb30f69994fd54e7c86a128305ae19c05

index ページに記事一覧が表示されるようになったかと思います。

getStaticProps について

今回はファイルからデータを取得しましたが、APIでもよいです。

export async function getSortedPostsData() {
  const res = await fetch('..')
  return res.json()
}

ちなみに、fetch は Next.js にいい感じに入っているので、import しなくても使えます。

getStaticProps はサーバーサイドでのみ動作するので、SQLを直接書いても問題ありません。ブラウザから見られるJSには含まれません。

import someDatabaseSDK from 'someDatabaseSDK'

const databaseClient = someDatabaseSDK.createClient(...)

export async function getSortedPostsData() {
  // Instead of the file system,
  // fetch post data from a database
  return databaseClient.query('SELECT posts...')
}

Server-side Rendering を行う

リクエスト時にページを生成する必要があるなら、サーバーサイドレンダリングを使うしかありません。

getStaticProps の代わりに getServerSideProps を使うだけです。

今回のサンプルだと Server-side Rendering は不要なので、詳しくは触れません。

Client-side Rendering を行う

Pre-rendering する必要がない場合は Client-side Rendering も使えます。 user-private な SEO の不要なページなどに使います。

SWR(React Hooks)

swr は varcel が作っているReat hookのライブラリです。Client-side Rendering を使うならこれが推奨されています。

https://swr.vercel.app/

import useSWR from 'swr'

function Profile() {
  const { data, error } = useSWR('/api/user', fetch)

  if (error) return <div>failed to load</div>
  if (!data) return <div>loading...</div>
  return <div>hello {data.name}!</div>
}

Server-side Rendering の意義

途中でも触れた通り、SEOの観点で言うと、 Client-side Rendering だとしても、Google は正しく解釈してくれるようです。

つまり、SSR の恩恵はほぼ無いでしょう。

第一回で述べた通り、最近の Next.js は、Server-side Rendering よりも、 Statuc Generation に重きを置いています。つまり、 Gatsby.js のような立ち位置になってきています。

さて、次回以降も引き続きこの React チュートリアルはやっていきます。

このチュートリアルが終わったら、僕が Next.js を触って、SSR、SSGなどについて思ったことをまとめたいと思います。

次回

次回はルーティングの話をやっていきます。

www.utakata.work