Next.jsでSSR中にfs
を触ったらエラーが起きたので整理しておきます。
Next.jsのレンダリングの方法
Next.jsがサーバーサイドでページをレンダリングする方法にはSSG (Static Site Generation), SSR (Server Side Rendering), ISR (Incremental Static Regeneration), SSG (fallback)などがあります。
SSG
ビルド時にサーバーサイドでページをレンダリングします。動的パスの場合はgetStaticPaths
でパスを指定します。
SSR
リクエストがあったときにサーバーサイドでページをレンダリングします。
ISR
getStaticPaths
でrevalidate
を指定すると適用されます。リクエストがあったときは静的なページを返しますが、revalidate
で指定した期間が過ぎていたら裏で再度レンダリングします。
SSG (fallback)
getStaticPaths
でfallback: true
を指定すると適用されます。ビルドされていないページのパスにリクエストが来たら、その場でページをレンダリングします。
Next.jsのサーバーサイド環境は2つある
ビルド環境
next dev
, next build
, next start
などが動いている環境です。getStaticPaths
で指定されたページのレンダリングは常にこちらで行われます。
ここではプロジェクトに含まれるすべてのファイルにアクセスできます。
自前のサーバーやコンテナ、Herokuなどでnext start
で動かしている場合は常にビルド環境になります。
サーバーレスモード
next.config.js
でtarget: 'serverless'
が指定されていると、ビルド時にページごとに単一のjsファイル (lambda) が生成されます。SSR, ISR, SSG (fallback)など、リクエスト時のレンダリングはこのlambdaを動かすことで行われます。
Vercelのドキュメントに書かれているように、原則としてlambdaからはファイルシステムにアクセスできません。webpackの設定をいじればできないことはないですが、基本的にハックの範疇なので将来的に動かなくなる可能性があります。pages/api/
の下にあるAPI Routesについても、同じくファイルシステムは触ってはいけません。
サーバーレスモードはVercelやNetlifyで適用されます。
ビルド環境かサーバーレスモードかを判定するには
Vercelの場合は環境変数にCI=1
が設定されていればビルド環境、されていなければサーバーレスモードです。Netlifyについては把握していませんが、少なくとも自前で環境変数をセットしておけば判定できると思います。
サーバーレスモードからファイルにアクセスするには
まずはSSRでなくSSGで対応できないか、リソースをlambdaに含められないかを検討しましょう。JSONを読みたい場合はfs
から読まずにimport
するなどの方法があります。
どうしてもSSR中にファイルを読みたい場合はネットワークからフェッチする必要があります。public/
かS3などのストレージに置きましょう。
まとめ
VercelやNetlifyにデプロイされているNext.jsアプリケーションで、ビルド中以外にファイルシステムを触ってはいけない。