Next.js 13のnext/imageは、Next.js 12では「next/future/image」と呼ばれていたものです。Next.js 12で使われていたnext/imageは、Next.js 13では「next/legacy/image」となっています。
※以後、区別しやすいように next/future/image、next/legacy/image と表記します。
Next.js 12から13へ移行する場合、next/imageに関しては2つの選択肢があります。
ここではnext/future/imageに合わせて、Imageコンポーネントを書き換える方法をまとめます。
next/future/imageでは、next/legacy/imageでレスポンシブイメージのために用意されていたものを自前で用意する形になっています。ある意味わかりやすくなりましたが、面倒になったとも言えます。
ただ、どちらにしてもレスポンシブイメージに対する理解は必要です。
※レスポンシブイメージについての基本的な考え方は書籍『作って学ぶ Next.js/React Webサイト構築』のChapter 5にまとめていますので、参考にしてください。
next/future/imageでの主な変更点は以下のとおりです。(※()内は書籍の当該ページです)
以上の変更点を踏まえた上で、next/future/imageへの置き換えを進めていきます。置き換えはlayout属性に応じて次のように行います。
layout="responsive" の場合は、layout属性を削除し、sizes属性を追加します。sizes属性の値はどのようなサイズで画像を表示するかに応じて指定します。
さらに、画像を可変にするCSSも用意されていないので、追加します。
// legacy
<Image
src="/rocket.jpg"
alt="空飛ぶロケット"
layout="responsive"
width={1980}
height={1150}
/>
▼
// future
<Image
src="/rocket.jpg"
alt="空飛ぶロケット"
width={1980}
height={1150}
sizes="100vw"
style={{
width: '100%',
height: 'auto',
}}
/>
<!-- 生成コード -->
<img
alt="空飛ぶロケット"
sizes="100vw"
srcset="
/_next/image?url=%2Frocket.jpg&w=640&q=75 640w,
/_next/image?url=%2Frocket.jpg&w=750&q=75 750w,
/_next/image?url=%2Frocket.jpg&w=828&q=75 828w,
/_next/image?url=%2Frocket.jpg&w=1080&q=75 1080w,
/_next/image?url=%2Frocket.jpg&w=1200&q=75 1200w,
/_next/image?url=%2Frocket.jpg&w=1920&q=75 1920w,
/_next/image?url=%2Frocket.jpg&w=2048&q=75 2048w,
/_next/image?url=%2Frocket.jpg&w=3840&q=75 3840w
"
src="/_next/image?url=%2Frocket.jpg&w=3840&q=75"
width="1980"
height="1150"
decoding="async"
data-nimg="1"
loading="lazy"
style="color: transparent; height: auto; width: 100%;"
/>
layout="fill" の場合は、layout属性とobjectFit属性を削除し、fill属性を追加します。さらに、CSSでobject-fitを指定します。
sizes属性は必要に応じて指定します(標準では100vwで処理されます)。
// legacy
<figure style={{ position: 'relative', width: '100%', height: '150px' }}>
<Image
src="/rocket.jpg"
alt="空飛ぶロケット"
layout="fill"
objectFit="cover"
/>
</figure>
▼
// future
<figure style={{ position: 'relative', width: '100%', height: '150px' }}>
<Image
src="/rocket.jpg"
alt="空飛ぶロケット"
fill
style={{
objectFit: 'cover',
}}
/>
</figure>
<!-- 生成コード -->
<figure style="position: relative; width: 100%; height: 150px">
<img
alt="空飛ぶロケット"
sizes="100vw"
srcset="
/_next/image?url=%2Frocket.jpg&w=640&q=75 640w,
/_next/image?url=%2Frocket.jpg&w=750&q=75 750w,
/_next/image?url=%2Frocket.jpg&w=828&q=75 828w,
/_next/image?url=%2Frocket.jpg&w=1080&q=75 1080w,
/_next/image?url=%2Frocket.jpg&w=1200&q=75 1200w,
/_next/image?url=%2Frocket.jpg&w=1920&q=75 1920w,
/_next/image?url=%2Frocket.jpg&w=2048&q=75 2048w,
/_next/image?url=%2Frocket.jpg&w=3840&q=75 3840w
"
src="/_next/image?url=%2Frocket.jpg&w=3840&q=75"
decoding="async"
data-nimg="fill"
loading="lazy"
style="
position: absolute;
height: 100%;
width: 100%;
left: 0;
top: 0;
right: 0;
bottom: 0;
object-fit: cover;
color: transparent;
"
/>
</figure>
layout="fixed" の場合はlayout属性を削除するだけです。
// legacy
<Image
src="/rocket.jpg"
alt=" 空飛ぶロケット"
layout="fixed"
width={1024}
height={595}
/>
▼
// future
<Image
src="/rocket.jpg"
alt=" 空飛ぶロケット"
width={1024}
height={595}
/>
<!-- 生成コード -->
<img
alt="空飛ぶロケット"
srcset="
/_next/image?url=%2Frocket.jpg&w=1080&q=75 1x,
/_next/image?url=%2Frocket.jpg&w=2048&q=75 2x
"
src="/_next/image?url=%2Frocket.jpg&w=2048&q=75"
width="1024"
height="595"
decoding="async"
data-nimg="1"
loading="lazy"
style="color: transparent"
/>
layout="intrinsic" の場合は、layout="fixed" のときと同じようにlayout属性を削除します。その上で、縮小を可能にするCSSを適用します。
// legacy
<Image
src="/rocket.jpg"
alt=" 空飛ぶロケット"
layout="intrinsic"
width={1024}
height={595}
/>
▼
// future
<Image
src="/rocket.jpg"
alt="空飛ぶロケット"
width={1024}
height={595}
style={{
maxWidth: '100%',
height: 'auto',
}}
/>
<!-- 生成コード -->
<img
alt="空飛ぶロケット"
srcset="
/_next/image?url=%2Frocket.jpg&w=1080&q=75 1x,
/_next/image?url=%2Frocket.jpg&w=2048&q=75 2x
"
src="/_next/image?url=%2Frocket.jpg&w=2048&q=75"
width="1024"
height="595"
decoding="async"
data-nimg="1"
loading="lazy"
style="color: transparent; max-width: 100%; height: auto"
/>
上記のような置き換えを行う codemod も用意されています。
Migrate to the new Image Component (next-image-experimental) - Experimental
https://beta.nextjs.org/docs/upgrade-guide/codemods#migrate-to-the-new-image-component-next-image-experimental---experimental
この codemod は next/legacy/image からインポートする形にした上で使用する必要があります。さらに、「Dangerously(危険な)」と書かれているように、layout属性の削除やCSSの追加が行われるため、実行後は問題が出ないかどうかをしっかりと確認する必要があるでしょう。
※『作って学ぶ Next.js/React Webサイト構築』で作成したプロジェクトでは、このcodemodですべての画像の置き換えが可能でした。
next/imageで外部サイトの画像を使う場合、next.config.js のdomains(P.232)でドメインを設定していましたが、remotePatternsを使うとパスなどを含めたより詳細な設定ができるようになっています。
たとえば、microCMSの画像は「https://images.microcms-assets.io/assets/…/…/photo.jpg」となっていますので、* または ** で次のように指定できます。* は単一のセグメント、** は複数のセグメントを指定します。
module.exports = {
images: {
remotePatterns: [
{
protocol: 'https',
hostname: 'images.microcms-assets.io',
port: '',
pathname: '/assets/*/*/*',
},
],
},
}
module.exports = {
images: {
remotePatterns: [
{
protocol: 'https',
hostname: 'images.microcms-assets.io',
port: '',
pathname: '/assets/**',
},
],
},
}
ここではlayout属性に応じて置き換える形で見てきましたが、Next.js 13 の next/image の一番のポイントは、
「Imageコンポーネントのsizes属性の有無より、出力されるsrcset属性の画像セットの構成が変わる」
ことです。画像のレイアウトに合わせて画像セットを切り替え、必要なCSSを適用することで、最適化されたレスポンシブイメージを柔軟に利用できるようになっていると言えるでしょう。