Next.js と Gatsby.js の比較
リーディングリスト消化
このサイトを作るときに Next.js と Gatsby.js を比較してどっちにしようか迷っていて、結局 Next.js を使うことにした上で「Gatsby.js 使わなくても Next.js でカバーできそうだな」と思っていた。
実際 Gatsby.js を使って何かを作ったことがあるわけではないので、こういう記事を読めるのはありがたい。
Gatsby.js で実装する場合
サンプルコードを見ると、各記事のページごとに forEach でcreatePages
とブログ記事一覧のページで 1 度createPages
を呼んでいるっぽい。
Next.js ではgetStaticProps
とgetStaticPaths
が分かれているけど、Gatsby.js は関数ひとつで path と props(というかページを構成するためのデータ)を一度に作れるみたい。
Next.js で実装する場合
記事の各ページの path はgetStaticPaths
、内容はgetStaticProps
がページ数分あり、記事一覧ページはパスが動的ではないのでgetStaticProps
が 1 回呼ばれる。
比較
Gatsby.js は API へのリクエストは一度で済む。
Next.js は path と props で別々にリクエストするため、リクエスト数が多い。が、ISR という便利な機能がある。
ISR
ISR のサンプルコードを読んだときにあれ?となったので調べた。
以下、記事内のサンプルコード引用
export async function getStaticPaths() {
- const res = await fetch('https://.../blogs')
- const blogs = await res.json()
- const paths = blogs.map((blog) => `/blogs/${blog.id}`)
return {
- paths,
+ paths: [],
fallback: true,
}
}
export async function getStaticProps({ params }) {
const res = await fetch('https://.../blogs')
const blogs = await res.json()
const blog = blogs.find(blog => params.id === blog.id)
return {
props: {
blog,
},
+ revalidate: 15 * 60,
}
}
getStaticPaths
でpaths: []
にして大丈夫なんだっけ?と思って、昔の自分が書いた投稿を読み直した。
getStaticProps
でrevalidate
を指定することで ISR することができる。
まずビルド時にはgetStaticPaths
では空配列を返しているから、記事ごとのパスは生成されていない。
fallback: true
を指定しているから、データを取得する必要がある部分以外がレンダリングされた HTML を返すはず。
いったんフォールバック用のページを表示するが、そのページに対応したデータがあればデータ取得が走り、その後はキャッシュされて 2 回目以降のリクエストで SSG と同じ挙動になる、はず。
ここらへん理解したと思ったけど意外と曖昧だ……。
こうすることでビルド時のリクエストは 0(paths に何も指定してないから?)になり、記事ページへの最初のリクエストでfallback: true
の挙動によりデータ取得が走って、その後のリクエストではキャッシュが返されて、revalidate
に指定された時間後のリクエストでは再びリクエストが走る、という感じ?
強みと弱み
Gatsby.js はビルド時のページ生成が細かく設定でき、リクエストも少ないが、ページ数に応じてビルド時間が増えていくのと、静的サイトの作成目的しか利用できない。
Next.js は、ISR やフォールバックがあるけどビルド時に ISR を使わないと N+1 リクエストになる。
ISR の Next.js、SSG の Gatsby.js として棲み分けできる。
その他
nextjs の ISR を使うときの fallback 指定について理解するまでの話
サンプルコードだとうまく動かなそう?
router.isFallback
の間はローディングを表示するなどしないといけないっぽい。