Claude Media
Claude Codeのnext/image置換を差分レビューする観点

Claude Codeのnext/image置換を差分レビューする観点

imgタグをnext/imageへ一括置換するとき、width・sizes・preload・remotePatternsが差分で壊れやすい箇所です。Claude Codeへの頼み方と差分で確かめる観点を示します。

next/image は、HTMLの<img>要素を拡張して、画像の自動最適化・レイアウトシフトの抑制・遅延読み込みを担うNext.jsのコンポーネントです。<img>をこれに置き換えると、LCPの改善と転送量の削減が見込めます。Next.jsのエラーメッセージ集でも、<img>の使用は「LCPが遅くなり、帯域も多く使う」ものとして警告されています。

置換そのものはClaude Codeが得意な機械的作業です。難しいのは、置換後の差分をどう確かめるかです。<Image>は<img>と見た目が似ていても、width・heightが必須だったり、外部URLの許可をnext.configに書かないと400になったりします。コンポーネントを書き換えるだけでは終わらず、設定ファイルまで差分に入ってきます。

この記事では、Claude Codeに一括置換を頼むときの準備と、差分で確認する観点を、Next.jsのImageコンポーネントの仕様に沿ってまとめます。

置換を頼む前に、Next.jsのバージョンと画像の出どころを洗い出す

最初に確認するのは2点です。使っているNext.jsのバージョンと、画像がどこから来ているかです。

バージョンが先なのは、<Image>の仕様がメジャーバージョンで動くからです。Next.js 16では、priorityプロパティが非推奨になり、代わりにpreloadプロパティが入りました。preloadが追加されたのはv16.0.0です。v15以前のプロジェクトでClaude Codeがpreloadを使うコードを書くと、そのプロパティは存在しません。

画像の出どころは、次の3種類に分けて数えます。置換の難しさがまったく違うためです。

出どころ例置換で追加確認が要るもの
ローカルの静的ファイル例public/配下、importした画像置換で追加確認が要るもの静的インポートなら幅と高さが自動で入る
外部URLの画像例S3、外部CMS、CDN置換で追加確認が要るものremotePatterns、幅と高さの手書き
最適化に向かない画像例SVG、アニメーションGIF置換で追加確認が要るものunoptimizedの扱い

静的ファイルをimportしている場合、Next.jsは本来の幅・高さ・blurDataURLを自動で決めます。外部URLはビルド時にファイルへアクセスできないため、widthとheightを手で渡す必要があります。

洗い出しはClaude Codeに任せられます。ファイルを書き換えさせる前に、読み取りだけを依頼します。

app/ と components/ にある <img> を全件洗い出して。
各行について、src がローカルか外部URLか、親要素のCSSで幅が決まっているか、
ファーストビューに出るかどうかを表にして。まだ何も編集しないで。

この表がそのまま、あとのレビューで差分を照らし合わせる基準になります。

規約を.claude/rulesに置いて、置換の方針をぶらさない

Claude Codeは、.claude/rules/に置いたMarkdownを規約として読み込みます。pathsフロントマターでファイルパターンを指定すると、対象のファイルを触ったときだけ読み込まれます。画像の置換は.tsxファイルに集中するので、この仕組みと相性がよい作業です。

例えば、次のような規約ファイルを置いておきます。内容はプロジェクトに合わせて書き換える前提の例です。

---
paths:
  - "app/**/*.tsx"
  - "components/**/*.tsx"
---
 
# 画像の置換ルール
 
- `<img>` は `next/image` の `<Image>` に置き換える。SVG と GIF は `unoptimized` を付ける
- 幅と高さが決まらないレイアウトでは `fill` と `sizes` をセットで書く
- ファーストビューの1枚だけ、LCP対象として先読みを指定する
- 外部URLを使うときは `next.config.ts` の `images.remotePatterns` に追記する。`domains` は使わない
- `alt` は省略しない。装飾なら空文字にする

ルールの本文は、あとで差分レビューするときのチェックリストと同じ内容にしておくのがコツです。Claudeに守らせる基準と、人間が確認する基準が一致していれば、差分で見るべき箇所が明確になります。

plan modeで範囲を決め、少しずつ置換させる

Claude Codeには、ファイルを編集する前に計画だけを出させるplan modeがあります。claude --permission-mode planで起動するか、セッション中にShift+Tabで切り替えます。承認するまで編集は行われません。

claude --permission-mode plan

一括置換では、この段階で次の点を計画に含めさせます。

  • 置換の対象ファイルと、それぞれの画像の種類(静的・外部・SVG)
  • next.configへの追記が必要な外部ホスト名
  • ファーストビューに出るため先読みの対象になる画像の候補

リファクタリング全般について、Claude Codeの共通ワークフローには「小さく、テスト可能な単位で進める」という方針が書かれています。画像の置換にも同じ進め方が合います。ページ単位かコンポーネント単位に区切って頼み、区切りごとにビルドを通します。

計画のうち「トップページ配下」だけ実施して。
終わったら next build を実行して、エラーと警告を貼って。

next buildを各区切りで回すと、widthとheightの欠落や、next.configにない外部ホストの指定が早い段階で見つかります。一度に全ページを置換すると、原因の切り分けが難しくなります。

差分レビューで見る観点

ここからが本題です。差分に出てきやすい箇所を、壊れ方とあわせて並べます。

見る箇所壊れ方差分で探すもの
width・height・fill壊れ方ビルドエラー、画像が表示されない差分で探すもの数値の欠落、fillの親要素にpositionがない
sizes壊れ方大きすぎる画像をダウンロードする差分で探すものfillや可変幅のレイアウトでsizesがない
先読みの指定壊れ方LCPが改善しない、または逆効果差分で探すもの全画像に付いている、バージョンと名前が合わない
remotePatterns壊れ方外部画像が400になる差分で探すもの外部URLの追加に対して設定の追記がない
unoptimized壊れ方SVG・GIFの扱いが崩れる差分で探すものSVGやGIFに対する指定の有無
alt壊れ方アクセシビリティの退行差分で探すもの空文字にすべきでない画像のalt=""

widthとheightは、表示サイズではなく縦横比のために渡す

widthとheightは、画像の本来のサイズ(ピクセル)を示すプロパティです。ブラウザが領域を確保して、読み込み中のレイアウトシフトを避けるために使います。画面上の表示サイズはCSSが決めます。

この両方を必ず指定しなければならないのは、静的インポートした画像と、fillを指定した画像を除くすべての場合です。幅と高さがわからない場合、Next.jsはfillの使用を勧めています。

fillは親要素いっぱいに画像を広げるプロパティで、親要素にposition: relative・fixed・absoluteのいずれかが必要です。<img>をそのままfillに変えると、親にpositionがなく、画像が想定外の場所に出ることがあります。差分では、fillが付いた箇所の親要素のスタイルまで一緒に見ます。

落とし穴

表示サイズを width と height で決めたつもりになる

<Image width={500} height={500} />と書いても、画面上の大きさが500pxになるとは限りません。実際の表示サイズはCSSで決まります。元の<img>にCSSで幅が付いていたなら、そのCSSが<Image>にも効く構造かを確かめます。

sizesは、転送量を左右するプロパティ

sizesは、ブラウザが生成されたsrcsetから画像を選ぶときの手がかりです。fillを使うときや、CSSで画像をレスポンシブにしているときに指定するものとされています。

sizesがないとき、ブラウザは画像がビューポートと同じ幅(100vw)だと見なします。カードが3列で並ぶレイアウトでも、画面幅いっぱいの画像をダウンロードしてしまい、転送量を減らすはずの置換が逆効果になりえます。

sizesは、srcsetの作られ方も変えます。

  • widthを持つ画像でsizesがない場合、1x・2x程度の限られたsrcsetになる。固定サイズの画像向け
  • fillの画像でsizesがない場合、deviceSizesだけからsrcsetが作られる
  • sizesがある場合、640w・750wなどの完全なsrcsetが作られる
前と後

カード画像の置換例

BEFORE

置換前

<img src="/cards/hero.jpg" alt="商品の写真" className="card-image" />
AFTER

置換後(レビューで通す形の例)

<div className="card-image-wrap">
  <Image
    src="/cards/hero.jpg"
    alt="商品の写真"
    fill
    sizes="(max-width: 768px) 100vw, (max-width: 1200px) 50vw, 33vw"
  />
</div>

この例のsizesは、Next.jsのドキュメントにある書き方に沿った一例です。実際の値は、自分のレイアウトの列数とブレークポイントに合わせて決めます。差分レビューでは、sizesの数値がCSSのグリッド幅と食い違っていないかを見ます。Claude Codeに「このsizesはCSSのどのブレークポイントに対応するか」と説明させると、見落としを減らせます。

LCP画像の先読みは、1枚に絞る

LCP(最大コンテンツの描画)の対象になる画像は、先に読み込ませると効果が出やすくなります。ただし、Next.js 16のpreloadは「LCP要素の画像」「ファーストビューのヒーロー画像」「<body>で見つかる前に<head>で読み込みを始めたい画像」に使うものです。

使うべきでない場面も、ドキュメントに書かれています。

  • ビューポートによってLCP要素が変わり、複数の画像が候補になる場合
  • loadingプロパティを使う場合
  • fetchPriorityプロパティを使う場合

多くの場合はloading="eager"かfetchPriority="high"で足りる、ともあります。

Claude Codeに「全部の画像を速くして」と頼むと、すべての<Image>に先読みを付けてしまう形の差分が出ることがあります。先読みする画像が多いほど、本当に最優先すべき画像の読み込みと競合します。差分では、先読みが付いた箇所が各ページで1枚以内に収まっているかを確認します。

バージョンも見ます。Next.js 16ではpriorityが非推奨で、preloadに置き換わっています。v15以前ならpriorityが正しく、preloadは存在しません。先に洗い出したpackage.jsonのバージョンと照らし合わせます。

外部画像はremotePatternsに書かないと400になる

srcに外部URLを渡すには、next.configのimages.remotePatternsでURLのパターンを許可する必要があります。許可がないホスト、プロトコル、ポート、パスの画像は、400 Bad Requestになります。

// next.config.ts(ドキュメントにあるS3の例に沿った形)
import type { NextConfig } from 'next'
 
const config: NextConfig = {
  images: {
    remotePatterns: [
      {
        protocol: 'https',
        hostname: 's3.amazonaws.com',
        port: '',
        pathname: '/my-bucket/**',
        search: '',
      },
    ],
  },
}
 
export default config

差分では、コンポーネント側に外部URLが増えた分だけ、この設定にも行が増えているかを突き合わせます。Claude Codeが置換だけを済ませて設定を忘れると、ローカルのnext devで最初に画像を開いた時点で400が出ます。

設定の書き方にも注意点があります。

  • protocol・port・pathname・searchを省くと、ワイルドカード**が暗黙に入る。意図しないURLまで最適化の対象になるため、非推奨
  • **は、パスの末尾かホスト名の先頭でしか使えない。パターンの途中には書けない
  • 旧来のdomains設定はNext.js 14で非推奨になった。プロトコル・ポート・パスを制限できないため
  • 許可したホストがリダイレクトを返すと、リダイレクト先はremotePatternsで再検証されない

差分にdomainsが出てきたら、remotePatternsに直します。前節の規約ファイルに「domainsは使わない」と書いたのは、このためです。

認証が必要な画像にも注意が要ります。デフォルトのローダーは、画像を取得するときにヘッダーを転送しません。認証つきの画像は、unoptimizedで最適化を外す選択肢が示されています。

最適化に向かない画像はunoptimizedにする

unoptimizedは、最適化をしない指定です。1KB未満の小さい画像、SVGのようなベクター画像、アニメーションGIFに向くとされています。

SVGについては、srcが.svgで終わる場合に自動でunoptimizedになります。SVGにはHTML/CSSと近い機能があり、適切なContent Security Policyがないと脆弱性につながりうるため、既定では最適化されません。dangerouslyAllowSVGで配信を許す設定もありますが、名前のとおり慎重に扱う設定です。

アニメーション画像は、formatsの設定に関係なく元の画像形式のまま配信されます。GIFをWebPに変えて軽くする目的で置換しても、その効果は得られません。

qualityとaltも差分に出る

Next.js 16では、qualitiesの設定が必須になり、省略時の値は[75]です。quality={90}のような指定が既存コードにあると、許可リストにない値は最も近い許可値に丸められます。開発中は警告が出るので、next devのログも差分レビューの材料にします。

altは、Next.js 13以降で必須です。画像を説明するテキストで、装飾目的の画像だけ空文字(alt="")にします。機械的な置換では、元の<img>のaltが空だったものがそのまま空で残ります。内容のある画像で空になっていないか、差分で拾います。

置換後に残るimgタグと転送量の確認

置換が終わったら、取りこぼしがないかを検索で確かめます。

grep -rn "<img" app components --include='*.tsx'

残った<img>が意図的なもの(SVGなど)かを判定するのは、Claude Codeに任せられます。ESLintを設定済みのプロジェクトなら、<img>の使用を警告するルールも差分に効きます。

効果の確認は、ブラウザの開発者ツールで行います。ネットワークタブで画像リクエストの転送サイズを見て、置換前後を比べます。LighthouseのLCPの値も同じ条件で比べます。数値の改善幅は画像の内容とレイアウトで大きく変わるため、ここで目安を示すことはできません。

ホスティング先にも目を向けます。Next.jsのエラーメッセージ集には、マネージドなホスティングでは最適化された画像が元の画像と異なる課金になりうること、セルフホストではsharpのインストールと、最適化後の画像をキャッシュするための十分なストレージが必要なことが書かれています。転送量は減っても、サーバー側の負荷や料金が増える可能性があります。

レビューそのものをClaude Codeに分担させる

差分が大きくなったら、レビューを別の目に任せる方法があります。

PRを観点別にレビューする仕組みとして、pr-review-toolkitがあります。専門のエージェントがPRを観点ごとに見ます。多角的なレビューが必要なときは、code-reviewプラグインも選べます。

sizesの値がレイアウトに合うかや、先読みする画像の選び方は、前節の観点で人が最後に確認する部分です。

Next.jsプロジェクトの土台の作り方や、CLAUDE.mdとAGENTS.mdの連携は、Claude CodeでNext.js SaaS MVPを作る手順にまとめています。

まとめ

一括置換の難所は、コンポーネントの書き換えより、sizes・先読み・remotePatternsという周辺の指定にあります。最初にバージョンと画像の出どころを洗い出し、規約を.claude/rules/に置き、plan modeで区切って進めれば、差分レビューの焦点がはっきりします。

特にsizesの抜けは、転送量を減らすという置換の目的そのものを損ないます。見た目が崩れず、ビルドも通るため気づきにくいという点で、最も見落としやすい項目です。

参照した一次ソース

この記事の記述は、次の一次ソースと照合しています。更新時に参照先が変わった場合は一覧も更新します。

  1. nextjs.org/docs/app/api-reference/components/image
  2. nextjs.org/docs/app/getting-started/images
  3. nextjs.org/docs/messages/no-img-element
  4. code.claude.com/docs/en/common-workflows
  5. code.claude.com/docs/en/memory
この記事を共有:XはてブLinkedIn