はじめに#
Nuxt 4でStatic Site Generation (SSG) を行う際、ローカルのJSONファイルからデータを読み込んで静的ページを生成したいケースがあります。しかし、Next.jsのgetStaticPropsのようにシンプルにはいかず、いくつかのハマりポイントがあります。
本記事では、試行錯誤の末に見つけた正しいアプローチを紹介します。
問題:なぜ単純なfsの読み込みでは動かないのか#
最初に試したアプローチ(失敗)#
このアプローチには以下の問題があります:
process.cwd()がビルド環境で異なる: ローカル開発とVercel等のビルド環境では作業ディレクトリが異なる- Nitroのプリレンダリング時にファイルが見つからない : SSG時、Nitroは独自のコンテキストで動作する
- useAsyncDataなしでは、クライアントサイドでも実行される : SSGの意味がなくなる
解決策:Nitro Storage API + Server APIルート + useAsyncData#
アーキテクチャ#
Step 1: nuxt.config.tsでserverAssetsを設定#
Step 2: Server APIルートを作成(Nitro Storage + fsフォールバック)#
Nitro Storage APIを使うメリット:
- Vercel等のビルド環境で安定動作
- OSごとのパスセパレータ問題を回避
- Nitroが環境に応じてファイルアクセスを最適化
fsフォールバックが必要な理由:
開発モード(npm run dev)ではserverAssetsが完全に機能しないケースがあるため、fs直接読み込みをフォールバックとして追加しています。ビルド時にはStorage APIが優先されます。
Step 3: Composableでラップ#
クライアントサイドフォールバックが重要な理由:
SSGで生成した静的サイトをS3やNetlify等にデプロイする場合、Server APIルートは存在しません。そのため、クライアントサイドナビゲーション時には/data/から直接JSONを取得する必要があります。
Step 4: ページコンポーネントでuseAsyncDataを使用#
重要なポイント#
1. useAsyncDataは必須#
useAsyncDataなしでawaitすると、クライアントサイドでも実行されてしまいます。
2. キーはユニークに#
useAsyncDataの第一引数のキーは、ページ/コンポーネント間でユニークにする必要があります。
3. computedで安全にアクセス#
useAsyncDataの戻り値はRefなので、テンプレートやロジックで使う際はcomputedでラップすると安全です。
4. 変数スコープに注意#
useAsyncDataのコールバック内で定義した変数は、コールバック外では使用できません。
この方法で生成された静的サイトでは:
- HTMLにデータが埋め込まれる : 初回表示が高速
- _payload.jsonにデータが保存される : クライアントサイドナビゲーション時に使用
- 元のJSONファイルへのリクエストは発生しない : ネットワーク負荷が軽減
0
別のアプローチ#
小さなJSONファイルの場合: 直接import#
ファイルサイズが小さく(50KB以下)、動的なパスが不要な場合は、直接importが最もシンプルです。
1
コンテンツ管理が主目的の場合: Nuxt Content#
マークダウンやJSONコンテンツを扱うサイトの場合は、Nuxt Contentモジュールが適しています。
2
まとめ#
Nuxt 4でSSGとローカルJSONを組み合わせるには:
- Nitro Storage API を使ってServer APIルートでJSONを読み込む
- useAsyncData で必ずラップする
- computed で安全にデータにアクセスする
- クライアントサイドフォールバック を忘れずに実装する
この方法により、ビルド時にすべてのデータがプリフェッチされ、クライアントサイドでの追加のAPI呼び出しを防ぐことができます。
参考リンク#