事の起こり
クライアント側でAPIを叩いて記事情報を取得しブログを作成したところ、GAでタイトルが取れなかったためプリレンダリングできるようにして解決を図りました。
microCMSのSDKを使う
getStaticPaths
内などでmicroCMSのAPIを叩くときに使います。cmsClient
と名前をつけて呼び出せるように設定用のファイルを用意します。
lib/microcms.ts
import { createClient } from 'microcms-js-sdk'
export const cmsClient = createClient({
serviceDomain: process.env.NEXT_PUBLIC_MICRO_CMS_SERVICE_DOMAIN || '',
apiKey: process.env.NEXT_PUBLIC_MICRO_CMS_API_KEY || ''
})
getStaticPaths
microCMSで作成した記事のコンテンツIDをurlに使う動的ルーティングのページなため、getStaticPaths
で静的に生成されるパスのリストを作成します。
[id].tsx
export const getStaticPaths = async () => {
const data = await cmsClient.get({
// microCMSで作成したAPIの「エンドポイント」の値です
endpoint: 'blog',
// limitを設定しないとデフォルトで10件取得なので、任意のlimit数を入れておきます
queries: { limit: 9999 }
})
const paths = data.contents.map(
// コンテンツIDをURLに使用します
(content: ArticleType) => `/blog/${content.id}`
)
return { paths, fallback: true }
}
-
endpoint
に入るのはmicroCMSで作成したAPIのエンドポイント
の値です。 -
queries
の指定もできます。limit
は何も指定しないと10件になってしまうので、任意の数を入れます。limitの上限はありませんが、レスポンスサイズが5MBを超えるとエラーになります。ここで使うのはpathに使うidだけなので、fields
で取得する要素を限定するのも良さそうです。
-
fallback
はgetStaticPaths
でパスが返されないときの挙動を指定します。-
false
:404ページになります。 -
true
:404になりません。空のフォールバックページが生成され、後述のgetStaticPaths
に値がある場合にはそれを使ってページアクセス時にレンダリングするようにすることが可能です。 -
blocking
:404になりません。trueのときにAPIからデータを取得する最中の表示をブロックします。
-
- ただしこのfallbackオプションは、
next export
で静的なHTMLを出力するようにしている場合には使用できません。
getStaticProps
APIからデータを取得した値をpropsとして渡し、ビルド時にプリレンダリングします。
[id].tsx
export const getStaticProps: GetStaticProps<StaticProps> = async (
context: GetStaticPropsContext
) => {
// getStaticPathsで用意した[id].tsxのid部分が入っています
const id = context.params?.id
// microCMSのAPIを叩きます
const data = await cmsClient
.get({
endpoint: 'blog',
// ページ用に1件取得するのでcontentIdを指定します
contentId: String(id)
})
.catch((err) => console.error(err))
if (!data) {
return {
// データがないとき404ページになります
notFound: true
}
}
return {
props: {
data
}
}
}
- returnの
props
でpagesのコンポーネントにdataを渡すことができます。 - returnの
notFound
はtrueのとき404ページになります。 -
revalidate
はISR用です。
[id].tsx
dataをpropsとして渡された残りのページ部分です。
[id].tsx
import React from 'react'
import {
NextPage,
InferGetStaticPropsType,
GetStaticPropsContext,
GetStaticProps
} from 'next'
import { useRouter } from 'next/router'
import type { ArticleType } from '@/rtk/services/cms'
import { LoadingPage } from '@/components/loading'
import { cmsClient } from '@/lib/microcms/microcms'
import { DetailsArticles } from '@/components/details'
type Props = InferGetStaticPropsType<typeof getStaticProps>
type StaticProps = {
data: ArticleType
}
const Article: NextPage<Props> = ({ data }) => {
const router = useRouter()
// フォールバック中であることをnext/routerのisFallbackで取得できるので、その間ローディング表示にできます
if (router.isFallback) {
return <LoadingPage />
}
return (
// dataを使ってコンポーネントの表示ができます(色々省略しています)
<DetailsArticles
data={data}
/>
)
}
export default React.memo(Article)
- 上の項目でしれっと書いていましたが、
getStaticProps
などで使っているtypescript用の型指定は色々用意してあるので適宜使います。 -
getStaticPaths
のfallbackオプションがtrueのときフォールバック中にisFallback
がtrueになるのでローディング表示などに利用できます。
まとめ
- SSGすることによってページが高速に表示できるようになりました。
- metaタグに入れる記事タイトルなどのデータを無事プリレンダリングするようになったので、GAでも正しく計測できるようになりました。
- SSGすると同じページでクライアントサイドでAPIを叩いてのプレビュー表示(URLパラメータにdraftkeyを入れるなどする)ができなくなるので、別の方法を検討する必要があります。Vercelを使用している場合はNext.jsのPreview Modeを使ったりできると思います(AWS Amplifyだとcookieとwebhookでの自動デプロイの兼ね合いで実現が難しく、諦めました)