パフォーマンス無関心で作ったサイトのパフォーマンスチューニング番外編 Nextjs AppRouter(fetch)
はじめに
こんにちわ!こんばんわ!ご観覧ありがとうございます。
定期的に雑色な記事を投稿します。(タイトルは記事のメインの内容にしてますが)
基本的には抱えている問題を改善し、改善方法を記事にしてアップしようと考えています。
お題と経緯
NextjsのPageRouterからAppRouterに乗り換えてみてパフォーマンスを測ってみたいし、使ってもみたいなってことで、
今回はFirebaseのhostingでAppRouterがどこまで機能するかを、パフォーマンス向上の一環として試そうと思います!
まずはAppRouterでサンプルのAppを作成しつつ、備忘録で説明を書いていこうと思います。
今回の内容
AppRouterで色々なfetchしていきたいと思います!
使用した技術
Category | Technology Stack |
---|---|
Frontend | Nextjs,React,Typescript |
Backend | Typescript,Node,CloudFunction |
Database | Firestore |
Design | XD |
前回の内容
前回記事
パフォーマンス無関心で作ったサイトのパフォーマンスチューニング番外編 Nextjs AppRouter - zare926のブログ
NextjsのAppRouterで静的コンテンツを表示するところまでやってみました。
AppRouterでfetchする
SGやだとgetStaticProps、SSRだとgetServerSidePropsを定義し、propsでJSXに値を渡していましたが、AppRouterのfetchはJSX内に直接書くことができます。
import { Squares } from "@/components/Squares"; import Link from "next/link"; export default async function Home() { const response = await fetch("https://jsonplaceholder.typicode.com/users/1"); // ここ const data: { name: string } = await response.json(); return ( <div className="p-8 relative"> <h1 className="text-gradient-blue-green" data-content="TopPage"> TopPage </h1> <Link href="/sample" className="text-sky-600"> Sampleページへ </Link> <p>{data.name}</p> // 定義したデータをそのまま使える <Squares /> </div> ); }
バケツリレーがなくなりますね。
ちなみにこの実装だとSGになり、ビルド時に1回だけfetchをしてくれます。
サーバーコンポーネントでSG,SSR,ISRの書き方
SSRの場合は以下の様に書きます。
import { Squares } from "@/components/Squares"; import Link from "next/link"; export const fetchCache = "default-no-store"; export default async function Home() { const number = Math.floor(Math.random() * (10 - 1 + 1)) + 1; const response = await fetch( `https://jsonplaceholder.typicode.com/users/${number}` ); const data: { name: string } = await response.json(); return ( <div className="p-8 relative"> <h1 className="text-gradient-blue-green" data-content="TopPage"> TopPage </h1> <Link href="/sample" className="text-sky-600"> Sampleページへ </Link> <p>{data.name}</p> <Squares /> </div> ); }
build後もサーバーサイドでやり取りしてくれるので、動的な表示が可能になります。
他にも、Dynamic Functionというものがあり、Server Component 内で使える cookies(), headers()のことを指します。
cookies(), headers()を定義するとSSRになります。
import { Squares } from "@/components/Squares"; import Link from "next/link"; import { cookies } from "next/headers"; // export const fetchCache = "default-no-store"; export default async function Home() { const cookieStore = cookies(); const number = Math.floor(Math.random() * (10 - 1 + 1)) + 1; const response = await fetch( `https://jsonplaceholder.typicode.com/users/${number}` ); const data: { name: string } = await response.json(); return ( <div className="p-8 relative"> <h1 className="text-gradient-blue-green" data-content="TopPage"> TopPage </h1> <Link href="/sample" className="text-sky-600"> Sampleページへ </Link> <p>{data.name}</p> <Squares /> </div> ); }
ISRの説明をするためにapiを用意。
src/app/sample-date-get/route.ts
import { NextResponse } from "next/server"; export async function GET() { return NextResponse.json({ data: new Date().toISOString() }); }
時間でCacheの設定をするのでわかりやすいAPIを準備します。
import { Squares } from "@/components/Squares"; import Link from "next/link"; export const revalidate = 10; // ここ export default async function Home() { const response = await fetch(`http://localhost:3000/sample-date-get`); const data = await response.json(); return ( <div className="p-8 relative"> <h1 className="text-gradient-blue-green" data-content="TopPage"> TopPage </h1> <Link href="/sample" className="text-sky-600"> Sampleページへ </Link> <p>{data.data}</p> <Squares /> </div> ); }
上記の場合はコンポーネント全体で10秒キャッシュとしています。
もしくはfetch関数単位でも設定可能です。
const response = await fetch(`http://localhost:3000/sample-date-get`, { next: { revalidate: 10 }, });
こちらに関してyarn devだとうまくいきますが、yarn buildだとうまくいきません・・・、原因がわかったら記事に追加しておきます。
.next/cache/fetch-cache ここにcacheで下記の様にjsonができているので、機能して欲しいのですが・・・
"status":200,"url":"http://localhost:3000/sample-date-get"},"revalidate":10,"tags":[]}
最後に
少しクセはありますが、cacheが楽に書けるなと思いました。
またページによってSG、ISRなど機能を振り分けしやすいと感じます。
ただISRだけはbuild後、期待通りのcacheではないので、調べないと・・・
果たしてFirebaseでhostingはできるのか・・・?
次回はクライアントコンポーネントから動的な関数を呼ぶ方法を書いてみたいと思ってます。
ここまでみていただきありがとうございました!!!