💭

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>

学んだ教訓

  1. ルーティングの一貫性: 国際化サイトではすべてのリンクに言語プレフィックスを含める
  2. バンドル最適化: 大規模コンポーネントは動的インポートで分割読み込み
  3. プリフェッチ制御: 特殊なルートでは明示的にプリフェッチを制御する
  4. パフォーマンス計測: 実際のユーザー体験に基づいた最適化が重要

技術スタック

  • Next.js 15.5.3
  • TypeScript
  • Tailwind CSS
  • 国際化(i18n)対応

この最適化により、ポートフォリオサイトのユーザー体験が劇的に改善され、瞬時のナビゲーションと安定したパフォーマンスを実現しました。

Discussion