EY-OfficeサイトもJamstackブームに乗ってみようと思う(2) で発生していたブログ記事が上手く生成出来ないという本質的な問題が解決し、まだ問題はありますが、だいぶ進歩してきました。
そこで、Next.jsのSSR(Server Side Rendering)機能の解説を書いてみました。
SSR(Server Side Rendering)
通常のReactアプリ
まずは、SSRを使ってない普通のReactアプリの動作を説明します。
- Reactのサイトをアクセスすると通常index.htmlがブラウザーに取り込まれます
- そこにリンクされている、ReactアプリのJavaScriptも取り込まれ実行されます。この時点では表示すべきデータがないのでデータのない画面が表示されます。ただしこの画面は一瞬過ぎて見えない、またはアプリで表示しないようにしている場合もあります
- Reactアプリがサーバーにデータをリクエストし、データ取得後に完成した画面が表示されます。
通信回線が遅い場合やPC/スマフォの処理能力が低い場合は2,3に時間がかかり、ユーザー体験(UX)を悪くします。またSEO的にも良くないと言われてきました(詳しくはここを読んでください)。
Next.jsを使ったReactアプリ
Next.jsを使ったReactアプリでは以下のように動作します。
- ReactのサイトをアクセスするとNext.jsが動作し、アクセスしたURLに対応したReactコンポーネントをサーバー側で実行し生成されたHTMLを戻します。そのさいReactコンポーネント内にgetStaticProps関数があるとデータ取得等をサーバー側で行い、完成した画面のHTMLを生成できます。
- 1で作られたindex.htmlにはNext.js独自の小さなJavaScriptが入っていて、index.html表示後にReactアプリのJavaScript取り込み、Reactの実行が開始されます
- ここからは通常のReactアプリになります
このように、Next.jsのようなSSGを使うと、初期画面が完成形で、しかもHTMLなので高速に表示さます。ユーザー体験(UX)は良くなりますし、SEO的に良くなります。
Next.js用のコード
SSRは素晴らしいですが、そのために大量のコードを書かなくては行けないのでは困ります。以下のコードは今回のブログ生成ページのReactコンポーネントです。
通常のReactコンポーネント追加されているのは、getStaticPaths、getStaticProps関数のみです。
getStaticPathsは動的に作成されるページ用のパス(URL)一覧をNext.jsに伝える関数なのでここでは説明は省略します→Next.jsドキュメント。
getStaticPropsはSSR処理の時のみ呼び出せる関数で、ReactコンポーネントにSSR処理時のみ独自のpropsを渡す事ができます。ここではURL(params.slug)で指定されるブログコンテンツ・ファイルをgetBlogContent関数で読み出しPropsのcontentに渡しています。
このコードはSSG(Static Site Generator)でしか使わないので、ブラウザー上でReactコンポーネントが動く事を考えていませんが、もし考慮するとしたらcontent等が無ければサーバーからfetchしてくるようなコードにするでしょうか。
import React from 'react'
import { getBlogInformations, getBlogContent, BlogInformations, getBlogUrls } from '../../lib/blog_posts'
import MDX from '@mdx-js/runtime'
import BlogLayout from '../../components/blog_layout'
type BlogArchiveProps = {
blogs: BlogInformations
index: number
content: string
}
const BlogArchive: React.FC<BlogArchiveProps> = ({blogs, index, content}) => {
return (
<BlogLayout blogs={blogs} index={index}>
<MDX>{content}</MDX>
</BlogLayout>
)
}
export const getStaticPaths = async () => {
const paths = await getBlogUrls()
return { paths, fallback: false }
}
export const getStaticProps = async ({params}) => {
const blogs = await getBlogInformations()
const ix = blogs.findIndex(blog => blog.url.match(params.slug.join("/")))
const content = await getBlogContent(blogs[ix].path)
return {
props: {
blogs: blogs,
index: ix,
content: content
}
}
}
export default BlogArchive
ブログ記事の生成出来ない問題点の解決
EY-OfficeサイトもJamstackブームに乗ってみようと思う(2) で発生していたブログ記事が上手く生成出来ないという問題は、検索したらNext.jsのIssues Module not found: Can’t resolve ‘fs’ #7755に解決方法が書いてありました。
このコードではブログファイル読み出しで Node.jsのFile ssystem APIを利用しているのですが、これがブラウザー用JavaScript作成時にwebpackでエラーになっているのでした。
対応はnext.config.jsに以下のコードを追加することで動くようになりました。
module.exports = {
webpack: (config, { isServer }) => {
// Fixes npm packages that depend on `fs` module
if (!isServer) {
config.node = {
fs: 'empty'
}
}
return config
}
}
まだ、いくつかの問題が残っていますが本質的な問題ではないので、近々にEY-OfficeブログのNext.js対応できるのではないかと思います。 😀