Next.js Image Optimizationエラーの原因と解決方法 | 完全ガイド

React / Next.js

Next.js Image Optimizationエラーの原因と解決方法 | 完全ガイド

Next.jsを使用していると、Image Optimizationに関連するエラーに遭遇することがあります。「画像が表示されない」「ビルドに失敗する」「動作が遅い」といった問題は、多くの開発者が経験します。本記事では、これらのエラーの原因から解決方法まで、初心者向けに詳しく解説します。

Next.js Image Optimizationとは

Next.jsのImageコンポーネントは、自動的に画像を最適化し、WebP形式への変換、遅延ロード、レスポンシブ対応などを行う強力な機能です。ただし、正しく設定しないと様々なエラーが発生します。

原因の説明

1. サイズ属性の未指定

最も一般的なエラーの原因は、widthheight属性を指定していないことです。Next.jsのImageコンポーネントでは、レイアウトシフト(Cumulative Layout Shift)を防ぐため、画像のサイズを事前に指定する必要があります。

2. 不正な画像ソース

外部ドメインからの画像を使用する場合、next.config.jsで許可されていないドメインから画像を読み込もうとするとエラーが発生します。また、相対パスが正しくない場合もエラーの原因となります。

3. バージョン互換性の問題

Next.jsのバージョン更新に伴い、Imageコンポーネントの仕様が変更されることがあります。古いバージョンのコードを新しいバージョンで使用すると、エラーが発生する可能性があります。

4. 静的生成時の画像処理

静的生成(Static Generation)時に外部ドメインからの画像を使用すると、ビルド時にタイムアウトエラーが発生することがあります。

解決手順

ステップ1: Next.jsのバージョン確認

まず現在のNext.jsバージョンを確認しましょう。

npm list next

バージョン13以降と12以前では、Image コンポーネントの使用方法が異なります。

ステップ2: 画像ソースの確認と設定

外部ドメインから画像を読み込む場合は、next.config.jsで設定が必要です。

// next.config.js
module.exports = {
  images: {
    remotePatterns: [
      {
        protocol: 'https',
        hostname: 'example.com',
        port: '',
        pathname: '/images/**',
      },
      {
        protocol: 'https',
        hostname: '**.example.com',
      },
    ],
  },
}

ステップ3: コンポーネント実装の修正

Imageコンポーネントの使用方法を確認し、必須属性を全て指定します。

ステップ4: テストとデバッグ

ローカル環境で動作確認を行い、エラーメッセージを確認します。

npm run dev

ブラウザの開発者ツールでコンソールを確認し、エラーメッセージを確認しましょう。

コード例

基本的な使い方(正しい実装)

import Image from 'next/image'

export default function MyComponent() {
  return (
    <Image
      src=\"/images/profile.jpg\"
      alt=\"プロフィール画像\"
      width={200}
      height={200}
      priority
    />
  )
}

外部ドメインからの画像読み込み

import Image from 'next/image'

export default function ExternalImage() {
  return (
    <Image
      src=\"https://example.com/image.jpg\"
      alt=\"外部ドメインの画像\"
      width={500}
      height={300}
      unoptimized={false}
    />
  )
}

レスポンシブ画像の実装

import Image from 'next/image'

export default function ResponsiveImage() {
  return (
    <div style={{ position: 'relative', width: '100%', height: '300px' }}>
      <Image
        src=\"/images/banner.jpg\"
        alt=\"レスポンシブバナー\"
        fill
        style={{ objectFit: 'cover' }}
      />
    </div>
  )
}

複数の外部ドメイン設定例

// next.config.js
module.exports = {
  images: {
    remotePatterns: [
      {
        protocol: 'https',
        hostname: 'images.example.com',
      },
      {
        protocol: 'https',
        hostname: 'cdn.example.com',
        pathname: '/public/**',
      },
      {
        protocol: 'https',
        hostname: '**.example.co.jp',
      },
    ],
    // 外部URLの最適化を無効にする場合(開発段階)
    unoptimized: process.env.NODE_ENV === 'development',
  },
}

next/legacy/imageの使用(互換性重視の場合)

// Next.js 12以前の記法で使用する場合
import Image from 'next/legacy/image'

export default function LegacyImage() {
  return (
    <Image
      src=\"/images/sample.jpg\"
      alt=\"レガシー画像\"
      width={400}
      height={300}
      layout=\"responsive\"
    />
  )
}

エラーハンドリング付きの実装

import Image from 'next/image'
import { useState } from 'react'

export default function ImageWithErrorHandling() {
  const [error, setError] = useState(false)

  const handleError = () => {
    setError(true)
    console.error('画像の読み込みに失敗しました')
  }

  if (error) {
    return <div>画像が読み込めませんでした</div>
  }

  return (
    <Image
      src=\"/images/photo.jpg\"
      alt=\"フォト\"
      width={300}
      height={200}
      onError={handleError}
      placeholder=\"blur\"
      blurDataURL=\"data:image/jpeg;base64,...\"
    />
  )
}

よくある間違い

間違い1: widthとheightを文字列で指定

// ❌ 間違い
<Image
  src=\"/image.jpg\"
  alt=\"画像\"
  width=\"300\"
  height=\"200\"
/>

// ✅ 正しい
<Image
  src=\"/image.jpg\"
  alt=\"画像\"
  width={300}
  height={200}
/>

間違い2: next.config.jsの設定忘れ

// ❌ 間違い: next.config.jsで許可していない外部ドメイン
<Image
  src=\"https://unauthorized-domain.com/image.jpg\"
  alt=\"画像\"
  width={300}
  height={200}
/>

// ✅ 正しい: next.config.jsで設定を追加してから使用
// next.config.js
module.exports = {
  images: {
    remotePatterns: [
      {
        protocol: 'https',
        hostname: 'unauthorized-domain.com',
      },
    ],
  },
}

間tradicional違い3: altテキストの省略

// ❌ 間違い
<Image
  src=\"/image.jpg\"
  width={300}
  height={200}
/>

// ✅ 正しい
<Image
  src=\"/image.jpg\"
  alt=\"説明的で意味のあるテキスト\"
  width={300}
  height={200}
/>

間違い4: fillプロパティ使用時のサイズ指定

// ❌ 間違い: fillとwidth/heightを同時に使用
<Image
  src=\"/image.jpg\"
  alt=\"画像\"
  fill
  width={300}
  height={200}
/>

// ✅ 正しい: fillを使う場合はwidth/heightは不要だが、親要素は相対配置が必要
<div style={{ position: 'relative', width: '100%', height: '300px' }}>
  <Image
    src=\"/image.jpg\"
    alt=\"画像\"
    fill
    style={{ objectFit: 'cover' }}
  />
</div>

間違い5: 過度な最適化の無効化

// ❌ 本番環境で最適化を完全に無効化
module.exports = {
  images: {
    unoptimized: true, // すべての環境で無効化
  },
}

// ✅ 開発環境のみ無効化
module.exports = {
  images: {
    unoptimized: process.env.NODE_ENV === 'development',
  },
}

デバッグのヒント

コンソールエラーの確認

ブラウザの開発者ツール(F12)を開き、コンソールタブでエラーメッセージを確認します。エラーメッセージには解決の手掛かりが含まれていることが多いです。

ネットワークタブの確認

「Network」タブで画像ファイルが正しく読み込まれているか、ステータスコードを確認します。404エラーであれば、パスが間違っている可能性があります。

next.config.jsの再読み込み

next.config.jsを修正した場合は、開発サーバーを再起動する必要があります。

npm run dev

パフォーマンス最適化のベストプラクティス

priorityプロパティの活用

ページの最初に表示される画像には、priority属性を付与してLCP(Largest Contentful Paint)を改善します。

<Image
  src=\"/hero-image.jpg\"
  alt=\"ヒーロー画像\"
  width={1200}
  height={600}
  priority
/>

placeholderの使用

画像読み込み中のUIを改善するため、placeholder=\"blur\"を使用します。

<Image
  src=\"/image.jpg\"
  alt=\"画像\"
  width={300}
  height={200}
  placeholder=\"blur\"
  blurDataURL=\"data:image/jpeg;base64,/9j/4AAQSkZJRg...\"
/>

まとめ

Next.js Image Optimizationエラーは、適切な設定と実装により確実に解決できます。重要なポイントは以下の通りです:

  • width/height属性は必須 – 数値型で指定すること
  • 外部ドメイン設定 – next.config.jsで許可したドメインのみ使用可能
  • altテキストの記述 – アクセシビリティとSEO対策に必須
  • 適切なプロパティ選択 – fillかwidth/heightかを使い分ける
  • 本番環境での最適化 – unoptimizedは開発時のみ有効化

これらのガイドラインに従うことで、Next.jsのImage Optimizationの恩恵を最大限に受けることができます。画像はWebサイトのパフォーマンスと視認性に大きく影響するため、正しい実装が重要です。

今後のプロジェクトで同様のエラーに遭遇した場合は、本記事を参考にして素早く解決してください。不明な点がある場合は、Next.js公式ドキュメントも合わせて参照することをお勧めします。

タイトルとURLをコピーしました