未分類
Nuxt SSRエラー対策: データ分割と<ClientOnly>
背景・問題
eps-per-scatter.vueページで以下のエラーが発生:
Error: worker exited with code 0
原因
actual-consensus-data.ts(約35MB)という大きな静的データファイルをインポート- Nuxtはデフォルトで**SSR(Server-Side Rendering)**を行う
- SSR時にサーバー側でこの大きなファイルを処理しようとしてワーカープロセスがメモリ不足でクラッシュする
解決策
推奨: データ分割(根本解決)
ページで必要なデータだけを抽出した軽量ファイルを生成する。
本プロジェクトでの実装例:
| ファイル | サイズ | 用途 |
|---|---|---|
actual-consensus-data.ts | 35MB | 全メトリクス(売上、利益、EPS、PER等) |
scatter-data.ts | 52KB | 散布図用(EPS成長率、PERのみ) |
# 散布図用データの再生成
cd apps/web
node scripts/generate-scatter-data.mjs
メリット:
- SSRが正常動作(ClientOnly不要)
- ページ読み込みが高速
- ブラウザのメモリ使用量削減
代替案: <ClientOnly>(応急処置)
ClientOnlyとは
Nuxtが提供するビルトインコンポーネントでクライアント側(ブラウザ)でのみレンダリングするよう指定できる。
<template>
<div>
<h1>タイトル(SSRされる)</h1>
<ClientOnly>
<!-- この中身はブラウザでのみレンダリング -->
<HeavyComponent :data="largeData" />
</ClientOnly>
</div>
</template>
なぜ安定するのか
| 処理 | SSR(サーバー側) | CSR(クライアント側) |
|---|---|---|
| 実行環境 | Node.jsワーカー | ブラウザ |
| メモリ制限 | 厳しい(ワーカー単位) | 緩い(ユーザーのPC依存) |
| 大きなデータ | クラッシュしやすい | 通常問題なし |
<ClientOnly>を使うと:
- SSR時: 中身をスキップ(空のプレースホルダーのみ)
- ブラウザ読み込み後: JavaScriptが実行されて中身をレンダリング
これにより、サーバー側で大きなデータを処理する必要がなくなり、クラッシュを回避できる。
実装例
Before(エラー発生)
<template>
<div>
<h1>散布図</h1>
<div class="chart">
<svg><!-- 大きなデータを使用 --></svg>
</div>
</div>
</template>
<script setup>
import { actualConsensusData } from '~/composables/actual-consensus-data' // 35MB
</script>
After(修正後)
<template>
<div>
<h1>散布図</h1>
<ClientOnly>
<div class="chart">
<svg><!-- 大きなデータを使用 --></svg>
</div>
</ClientOnly>
</div>
</template>
<script setup>
import { actualConsensusData } from '~/composables/actual-consensus-data' // 35MB
</script>
注意点
デメリット
- 初期表示が遅くなる可能性
- SSRされないため、JavaScriptが読み込まれるまで空白になる
- SEOへの影響
<ClientOnly>内のコンテンツは検索エンジンにインデックスされにくい- ただしチャートやインタラクティブなUIは元々SEO対象外なので問題なし
- フラッシュ(ちらつき)
- ページ読み込み時に一瞬空白が見える場合がある
フォールバック表示
読み込み中の表示を設定できる:
<ClientOnly>
<template #fallback>
<div class="loading">読み込み中...</div>
</template>
<HeavyComponent />
</ClientOnly>
いつ使うべきか
| ケース | ClientOnly使用 |
|---|---|
| 大きなデータファイルを使用 | ✅ 推奨 |
| ブラウザAPIを使用(window, document等) | ✅ 必須 |
| チャート・グラフ | ✅ 推奨 |
| テキストコンテンツ | ❌ SSRした方がよい |
| SEO重要なコンテンツ | ❌ SSRした方がよい |
参考
- Nuxt公式ドキュメント - ClientOnly
- 本プロジェクトでの使用例:
apps/web/app/pages/financial-quiz/eps-per-scatter.vue