SuperJSONでNext.js 12以降のgetServerSidePropsやgetStaticPropsをスマートに書く


Next.jsのgetServerSidePropsgetStaticPropsとJSON

Next.jsでSSRやSSRをする際に使うgetServerSidePropsgetStaticPropsでは、戻り値をJSONでシリアライズ可能な型に制限しなくてはならない制約があります。例えばデータベースから取得したデータがDate型を含む場合はエラーになってしまいます。

  • getStaticPropsでMongoDBデータベースから取得したデータがDate型の値を含む場合:
export const getStaticProps:GetStaticProps = async (ctx) => {
  const client = await new MongoClient("mongodb://127.0.0.1:27017");
  await client.connect();
  const db = client.db("DATABASE");
  const col = db.collection("COLLECTION");
  const posts = await col.find({}).toArray(); #created_atなどDate型を含んでいるとする 
  return {
    props:{
      posts
    }
  }
}

エラー

Server Error
Error: Error serializing `.data[0].date` returned from `getStaticProps` in "/".
Reason: `object` ("[object Date]") cannot be serialized as JSON. Please only return JSON serializable data types.
This error happened while generating the page. Any console logs will be displayed in the terminal window.
  • undefinedを含む場合:

コード

export const getStaticProps:GetStaticProps = async (ctx) => {
  return {
    props:{
      data: undefined
    }
  }
}

エラー

Server Error
Error: Error serializing `.data` returned from `getStaticProps` in "/".
Reason: `undefined` cannot be serialized as JSON. Please use `null` or omit this value.
This error happened while generating the page. Any console logs will be displayed in the terminal window.

これを回避するためには、Date型をString型に変換するなど、JSONとしてシリアライズ可能な形式に変換する必要がありますが、毎回変換処理を書くのは面倒です。

そこで登場するのがSuperJSONです。SuperJSONとNext.js用のBabelプラグインを使えば明示的な変換なしにgetServerSidePropsgetStaticPropsでJSON範囲外の型が扱えます。

Next.js 12以降でのSuperJSON

しかしながらNext.js 12では標準のトランスパイラがBabelからSWCに変更され、blitz-js/babel-plugin-superjson-nextが標準では使えなくなりました。

SWC以降のNext.jsでもこれまでと同じようにSuperJSONを使えるようにしたのが、2021年12月に登場したremorses/next-superjsonです。

インストール

npm install superjson (未インストールの人)
npm install next-superjson

設定

next.config.jsnext-superjson用の設定を追加します。

const { withSuperjson } = require('next-superjson')

module.exports = withSuperjson()({
  reactStrictMode: true,
})

アプリ側の処理

特に何も記述する必要はありません。SuperJSONを使わない場合はシリアライズが必要ですが自動でシリアライズしてくれます。

注意

  • SuperJSONがSWC対応してくれるのが望ましいですが、未対応のためワークアラウンドとして使っています。将来SuperJSONがSWCに対応したらそちらに移行しましょう。
  • 楽だからといってデータベースから取得したデータをNext.jsにそのまま投げるのはやめましょう。