未分類
Nuxt 3のapp/dataとpublicディレクトリの使い分け
特にCloudflare Pagesにデプロイする場合のNuxt 3プロジェクトで、データファイルをどこに配置すべきかについて整理する。
結論(TL;DR)
| 配置場所 | 用途 | ビルド時の扱い |
|---|---|---|
app/data/ | TypeScript/JavaScriptでインポートするデータ | バンドルに含まれる |
public/ | fetch/APIで取得する静的ファイル | そのまま配信される |
現在のapp/data/japanese-quiz/は正しい配置。 TypeScriptファイルとしてインポートしているため、app/data/に置くのが適切。
詳細な比較
app/data/ディレクトリ
apps/web/app/data/
└── japanese-quiz/
├── index.ts
├── modification-order.ts
├── punctuation.ts
└── particles.ts
特徴:
- ビルド時にバンドルされる(JavaScriptにコンパイルされる)
- TypeScriptの型チェックが効く
import { data } from '~/data/...'でインポート- Tree-shakingにより未使用コードは除外される
- SSR/SSGでそのまま使える
適しているケース:
- TypeScriptの型定義を活用したい
- コード内で直接インポートして使う
- データ量が比較的小さい(数KB〜数十KB)
- ビルド時に確定するデータ
例:クイズの問題データ
// app/data/japanese-quiz/modification-order.ts
export const modificationOrderQuestions: QuizQuestion[] = [
{
id: 'mod-001',
category: 'modification-order',
question: '次の文で修飾語の順序が適切なものを選べ',
// ...
}
]
public/ディレクトリ
apps/web/public/
├── data/
│ ├── financial-data-20251202.json
│ └── raw/
│ ├── AAPL.json
│ └── ...
├── images/
└── audio/
特徴:
- そのまま静的ファイルとして配信される
- URLで直接アクセス可能(
/data/file.json) - ビルドプロセスを経由しない
fetch('/data/file.json')で取得- Cloudflare Pagesのエッジキャッシュが効く
適しているケース:
- ランタイムで動的にfetchしたい
- データ量が大きい(数百KB〜数MB)
- 画像、音声、PDFなどのバイナリファイル
- 外部ツールから生成・更新されるファイル
- クライアントサイドでのみ使用するデータ
例:財務データJSON
// コンポーネント内
const { data } = await useFetch('/data/financial-data-20251202.json')
Cloudflare Pagesでの動作
ビルド出力の構造
.output/
├── public/ # 静的ファイル(CDNから配信)
│ ├── data/ # public/からコピー
│ ├── images/
│ └── _nuxt/ # バンドルされたJS/CSS
└── server/ # サーバーサイドコード
└── chunks/ # app/data/はここに含まれる
パフォーマンスの違い
| 項目 | app/data/ | public/ |
|---|---|---|
| 初回ロード | JSバンドルに含まれる | 別リクエスト |
| キャッシュ | JSと一緒にキャッシュ | 個別にCDNキャッシュ |
| 更新時 | 再ビルド必要 | ファイル置換のみ可 |
| SSR | サーバーで直接利用 | fetchが必要 |
判断フローチャート
データを配置したい
│
├─ TypeScriptで型チェックしたい?
│ └─ Yes → app/data/
│
├─ import文で直接インポートする?
│ └─ Yes → app/data/
│
├─ ファイルサイズが大きい(100KB以上)?
│ └─ Yes → public/
│
├─ ランタイムで動的に取得する?
│ └─ Yes → public/
│
├─ 外部ツールで生成・更新される?
│ └─ Yes → public/
│
└─ バイナリファイル(画像/音声/PDF)?
└─ Yes → public/
このプロジェクトでの実例
app/data/に置いているもの
| パス | 理由 |
|---|---|
app/data/japanese-quiz/*.ts | TypeScriptでインポート、型チェック活用 |
public/に置いているもの
| パス | 理由 |
|---|---|
public/data/raw/*.json | 財務データ(大量、fetchで取得) |
public/images/ | 画像ファイル |
public/audio/ | 音声ファイル |
public/excel/ | Excelファイル |
まとめ
app/data/: コードの一部として扱いたいデータ(TypeScript推奨)public/: 静的ファイルとして配信したいデータ(JSON、画像、音声など)
TypeScriptファイルとしてインポートしており型安全性も確保されている現在のapp/data/japanese-quiz/は、この配置で正しい。public/に移動する必要はない。