💭
Next.jsパフォーマンス最適化:ナビゲーション遅延と"Failed to fetch"エラーの解決記録
問題発見
ポートフォリオサイトのナビゲーションで深刻なパフォーマンス問題を発見:
- ナビゲーションリンククリックからページ遷移まで9秒の遅延
- 時折発生する"Failed to fetch"エラー
- ユーザー体験の大幅な悪化
根本原因分析
1. ルーティング問題
// 修正前の問題コード
href="/#skills"
href="/#projects"
アンカーリンクに言語プレフィックス(/enなど)が含まれていなかったため、Next.jsが内部ルートとして認識せず、クライアントサイドナビゲーションが機能していませんでした。
2. バンドルサイズ問題
<mcfile name="page.tsx" path="app[locale]\page.tsx"></mcfile>で8つの大型コンポーネントを一度にインポート:
- Hero, Skills, ProjectsShowcase, Contact
- Statistics, Certifications, ReadingList, Blog
これにより:
- 初期コンパイル時間:3秒
- 初回リクエスト応答時間:4.3秒
- 合計ナビゲーション遅延:9秒
3. プリフェッチ問題
Next.jsのLinkコンポーネントがデフォルトでプリフェッチを有効にしており、アンカーリンク(/en#skillsなど)でプリフェッチが失敗し"Failed to fetch"エラーが発生していました。
解決策
ステップ1: ルーティング修正
<mcfile name="Header.tsx" path="components\Header.tsx"></mcfile>を修正:
// 修正後
href=`/${current}#skills`
href=`/${current}#projects`
// すべてのナビゲーションリンクに言語プレフィックスを追加
ステップ2: ダイナミックインポート導入
<mcfile name="page.tsx" path="app[locale]\page.tsx"></mcfile>を最適化:
// 静的インポートから動的インポートへ変更
const Hero = dynamic(() => import('@/components/Hero'), {
loading: () => <div className="h-screen" />
});
// 同様に他のコンポーネントも動的インポート
ステップ3: バンドルサイズ削減
非必須コンポーネントを削除:
- Statistics(統計表示)
- Certifications(資格証明)
- ReadingList(読書リスト)
- Blog(ブログ表示)
コアコンポーネントのみ保持:
- Hero(ヒーローセクション)
- Skills(スキル表示)
- ProjectsShowcase(プロジェクト展示)
- Contact(コンタクトフォーム)
ステップ4: プリフェッチ無効化
// すべてのLinkコンポーネントでプリフェッチを無効化
<Link href={`/${current}#skills`} prefetch={false}>
スキル
</Link>
学んだ教訓
- ルーティングの一貫性: 国際化サイトではすべてのリンクに言語プレフィックスを含める
- バンドル最適化: 大規模コンポーネントは動的インポートで分割読み込み
- プリフェッチ制御: 特殊なルートでは明示的にプリフェッチを制御する
- パフォーマンス計測: 実際のユーザー体験に基づいた最適化が重要
技術スタック
- Next.js 15.5.3
- TypeScript
- Tailwind CSS
- 国際化(i18n)対応
この最適化により、ポートフォリオサイトのユーザー体験が劇的に改善され、瞬時のナビゲーションと安定したパフォーマンスを実現しました。
Discussion