Next.js Image optimizationエラーの原因と解決方法|実装ガイド

React / Next.js

Next.js Image optimizationエラーの原因と解決方法

Next.jsを使用してWeb開発を行う際、Image optimizationに関連するエラーに直面することがあります。このエラーは初心者にとって特に戸惑いやすい問題です。本記事では、Next.jsのImage optimizationエラーが発生する原因から、具体的な解決手順、そしてよくある間違いまで、詳しく解説していきます。

Next.js Image optimizationエラーの原因

Next.jsは、<Image>コンポーネントを提供しており、自動的に画像を最適化します。このImage optimizationは非常に強力な機能ですが、適切に使用しないとエラーが発生します。主な原因を以下に説明します。

1. 必須プロパティの不足

<Image>コンポーネントを使用する際、srcaltwidthheightプロパティは必須です。これらのいずれかが欠けると、エラーが発生します。特に初心者は、HTML標準の<img>タグと混同しやすい点です。

2. 外部URL画像の設定不足

外部URLから画像を読み込む場合、next.config.jsで許可するドメインを登録する必要があります。設定がないと、セキュリティエラーが発生します。

3. 画像サイズの不一致

widthheightで指定したサイズが実際の画像サイズと大きく異なる場合、レイアウトシフトが発生し、最適化が機能しません。

4. next/imageのインポート漏れ

<Image>コンポーネントをインポートし忘れると、参照エラーが発生します。

エラー解決の実装手順

ステップ1:next/imageからImageコンポーネントをインポート

まず、Next.jsの公式Image コンポーネントを正しくインポートします。

'use client';

import Image from 'next/image';

export default function MyComponent() {
  return (
    <Image
      src="/images/sample.jpg"
      alt="サンプル画像"
      width={400}
      height={300}
    />
  );
}

このステップで重要な点は、from 'next/image'という正確なインポート文を使うことです。他のImage コンポーネントライブラリと混同しないよう注意してください。

ステップ2:ローカル画像の配置

プロジェクト内の公開フォルダ(publicフォルダ)に画像を配置します。

project/
├── public/
│   └── images/
│       ├── sample.jpg
│       └── logo.png
├── pages/
├── components/
└── next.config.js

publicフォルダに配置した画像は、ブラウザから直接アクセス可能になります。srcプロパティには、/images/sample.jpgのようにスラッシュから始まるパスを指定します。

ステップ3:外部URLの場合、next.config.jsを設定

外部URLから画像を読み込む場合は、next.config.jsでドメインを許可する必要があります。

/** @type {import('next').NextConfig} */
const nextConfig = {
  images: {
    remotePatterns: [
      {
        protocol: 'https',
        hostname: 'example.com',
        port: '',
        pathname: '/images/**',
      },
      {
        protocol: 'https',
        hostname: '*.unsplash.com',
        port: '',
      },
    ],
  },
};

module.exports = nextConfig;

remotePatternsは複数のドメインをサポートしており、ワイルドカード(*)を使用したパターンマッチングも可能です。

ステップ4:width と height を適切に指定

静的な画像の場合、widthheightを実際の画像サイズで指定します。

import Image from 'next/image';
import sampleImage from '@/public/images/sample.jpg';

export default function ImageComponent() {
  return (
    <Image
      src={sampleImage}
      alt="最適化された画像"
      // staticインポートを使用する場合、widthとheightは自動推定される
      priority
    />
  );
}

静的インポートを使用すると、Next.jsが自動的に画像のサイズを検出するため、エラーを避けられます。

実践的なコード例

例1:ローカル画像の基本的な使用

'use client';

import Image from 'next/image';

export default function ProfileCard() {
  return (
    <div style={{ display: 'flex', alignItems: 'center', gap: '1rem' }}>
      <Image
        src="/images/profile.jpg"
        alt="プロフィール画像"
        width={100}
        height={100}
        style={{ borderRadius: '50%' }}
      />
      <div>
        <h2>ユーザー名</h2>
        <p>ここに説明文が入ります</p>
      </div>
    </div>
  );
}

例2:動的なURL画像の読み込み

'use client';

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

export default function DynamicImage() {
  const [imageUrl, setImageUrl] = useState('https://example.com/image1.jpg');

  return (
    <div>
      <Image
        src={imageUrl}
        alt="動的画像"
        width={500}
        height={400}
        loader={({ src }) => src}
      />
      <button onClick={() => setImageUrl('https://example.com/image2.jpg')}>
        画像を変更
      </button>
    </div>
  );
}

動的なURLの場合、loaderプロップを使用してカスタムローダーを定義できます。

例3:レスポンシブ画像の実装

'use client';

import Image from 'next/image';
import { useState, useEffect } from 'react';

export default function ResponsiveImage() {
  const [isLarge, setIsLarge] = useState(false);

  useEffect(() => {
    const handleResize = () => {
      setIsLarge(window.innerWidth > 768);
    };

    handleResize();
    window.addEventListener('resize', handleResize);
    return () => window.removeEventListener('resize', handleResize);
  }, []);

  return (
    <Image
      src="/images/responsive.jpg"
      alt="レスポンシブ画像"
      width={isLarge ? 1200 : 600}
      height={isLarge ? 800 : 400}
      sizes="(max-width: 768px) 100vw, (max-width: 1200px) 50vw, 33vw"
    />
  );
}

例4:複数画像を管理する場合

'use client';

import Image from 'next/image';

const images = [
  { id: 1, src: '/images/img1.jpg', alt: '画像1' },
  { id: 2, src: '/images/img2.jpg', alt: '画像2' },
  { id: 3, src: '/images/img3.jpg', alt: '画像3' },
];

export default function ImageGallery() {
  return (
    <div style={{ display: 'grid', gridTemplateColumns: 'repeat(3, 1fr)', gap: '1rem' }}>
      {images.map((image) => (
        <Image
          key={image.id}
          src={image.src}
          alt={image.alt}
          width={300}
          height={300}
          style={{ objectFit: 'cover' }}
        />
      ))}
    </div>
  );
}

よくある間違いと対策

間違い1:HTMLのタグを使い続ける

誤ったコード:

// ❌ 避けるべき
export default function MyComponent() {
  return <img src="/images/sample.jpg" alt="サンプル" />;
}

正しいコード:

// ✅ 推奨
import Image from 'next/image';

export default function MyComponent() {
  return (
    <Image
      src="/images/sample.jpg"
      alt="サンプル"
      width={400}
      height={300}
    />
  );
}

HTMLの標準<img>タグは最適化されないため、Next.jsの利点を活かせません。

間違い2:外部URLを許可なく使用

誤ったコード:

// ❌ エラーが発生します
export default function MyComponent() {
  return (
    <Image
      src="https://external-domain.com/image.jpg"
      alt="外部画像"
      width={400}
      height={300}
    />
  );
}

正しいコード:

// next.config.jsで許可を追加
const nextConfig = {
  images: {
    remotePatterns: [
      {
        protocol: 'https',
        hostname: 'external-domain.com',
      },
    ],
  },
};

module.exports = nextConfig;

間違い3:fill propsの誤解

レスポンシブ画像でfillプロップを使用する際、親要素にposition: relativeが必要です。

誤ったコード:

// ❌ レイアウトが崩れる
export default function MyComponent() {
  return (
    <div>
      <Image
        src="/images/sample.jpg"
        alt="サンプル"
        fill
      />
    </div>
  );
}

正しいコード:

// ✅ 正しいレイアウト
export default function MyComponent() {
  return (
    <div style={{ position: 'relative', width: '100%', height: '500px' }}>
      <Image
        src="/images/sample.jpg"
        alt="サンプル"
        fill
        style={{ objectFit: 'cover' }}
      />
    </div>
  );
}

間違い4:widthとheightの型エラー

誤ったコード:

// ❌ 文字列を指定するとエラー
<Image
  src="/images/sample.jpg"
  alt="サンプル"
  width="400"
  height="300"
/>

正しいコード:

// ✅ 数値で指定
<Image
  src="/images/sample.jpg"
  alt="サンプル"
  width={400}
  height={300}
/>

間違い5:優先度の設定忘れ

ページ上で最初に見える重要な画像にはpriorityプロップを追加するべきです。

推奨コード:

// ✅ ヒーロー画像には priority を付与
<Image
  src="/images/hero.jpg"
  alt="ヒーロー画像"
  width={1200}
  height={600}
  priority
/>

トラブルシューティング

エラー:”Cannot find image file”

原因:画像ファイルがpublicフォルダに存在しない、またはパスが間違っています。

解決方法:

  • ファイルがpublicフォルダ内に実際に存在することを確認
  • パスがスラッシュで始まることを確認:/images/sample.jpg
  • ファイル名の大文字小文字を区別するOSの場合、正確に一致していることを確認

エラー:”Domain not configured”

原因:外部URLを使用しているが、next.config.jsに許可されていません。

解決方法:next.config.jsremotePatternsを追加します。

エラー:”Image with src \”..\” must use width and height”

原因:widthまたはheightが指定されていません。

解決方法:必ず両方のプロップを数値で指定してください。

まとめ

Next.jsのImage optimizationエラーは、正しい使用方法を理解すれば簡単に解決できます。本記事では以下の重要なポイントをカバーしました:

  • 必須プロップの理解:srcaltwidthheightはすべて必須です
  • インポート方法:from 'next/image'から正確にインポート
  • ローカル画像:publicフォルダに配置し、スラッシュから始まるパスを使用
  • 外部URL画像:next.config.jsでドメインを許可
  • レスポンシブ対応:fillプロップまたはsizes属性を活用
  • よくある間違い:HTMLの<img>タグとの混同、型エラー、親要素のスタイル設定

これらのガイドラインに従うことで、Next.jsの画像最適化機能を最大限に活用でき、高速で効率的なWebアプリケーションを構築できます。エラーが発生した場合は、まず本記事のトラブルシューティングセクションを参照し、段階的に問題を解決してください。

Next.jsを継続的に学習し、最新のドキュメントを確認することも重要です。公式ドキュメントは常に更新されており、新機能や改善内容が追加されています。

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