【JS】Next.js11で画像が表示されなくなったので各種設定を解説
こんにちは!Next.jsのここ数年間の成長に驚いているMizutani(@sirycity)です。最初のころはSSRするだけのフレームワークだったのに…
今日はバージョン11になってから画像の読み込みが色々変わったNext.jsの話です。
v11になったNext.js
詳しくはこちら。簡単に言うと画像に関する機能が便利になりました。
- width書かなくて良くなったり
- 軽量な画像を生成できたり
です。ただ、細かいことはともかくいきなりv11にすると画像が突然消えたりするので、nextの画像に関する各種設定をしっかり知っておこう!という趣旨の記事です。
画像の設定に関する前提知識
nextの画像表示方法は3種類ある
nextで画像を表示しようってなった時にとれる方法は大きく3種類あります。
- ふつうの
<img>
を使う - nextオリジナルの
<Image>
を使う <div>
とかでbackground-image: url()
として使う
ただしImageは一部環境でしか使えない
ここで大事なのが、nextオリジナルの<Image>
は使える環境が限られるということです。たとえばGatsby.jsの画像最適化なんかは別にどんなサービスでも使えますが、nextの画像最適化は(設定をしなければ)vercelでしか使えません。loaderっていう設定を使えば他でも使えますが、基本的にはvercel専用の機能です。firebaseとかnetlifyでは使えません。囲い込み。
言い方を変えればvercelを使ってないなら<Image>
のことは忘れてもいいかも。
nextのwebpackは2種類ある
nextで使われてるwebpackは2種類あります。v4とv5です。nextではこんな感じでv4とv5を使ってました。
- ずっとv4を使ってた
- nextv10からはデフォルトv4だけどv5も使えてた
- nextv11からはv5になった
なお、v10ではnext.config.js
にこうやって書くことでv5を使えてました。
module.exports = {
future: {
webpack5: true,
},
}
nextの画像ローダーは3種類ある
nextにおける画像のローダー、つまりwebpackを経由して画像を読み込む仕組みは大きく3種類あります。
- webpackv4でよく使われてた
url-loader
- webpackv5の新機能の
asset/inline
- nextv11の新機能(勝手に組み込まれるやつ)
前者2つは別にnext特有じゃないです。これらを使うことでこんな感じで画像がimportできるようになるんですね。
import foo from './foo.png'
なお、url-loader
とasset/inline
はそれぞれnext.config.js
にこんな感じで設定を書きます。
module.exports = {
webpack: config => {
config.module.rules.push({
test: /\.(png|jpg|gif|svg)$/,
type: 'url-loader',
})
return config
},
}
module.exports = {
webpack: config => {
config.module.rules.push({
test: /\.(png|jpg|gif|svg)$/,
type: 'asset/inline',
})
return config
},
}
んでv11で入る方は特に何も書かなくてokです。逆に言えば↑のやつはv11にしたら消してOK。
v11で突然画像が消える原因
原因をズバリ言うと画像のローダーがv11からnext特有のものになり、その他のローダーとの互換性がなくなったからです。
実際に見てみると分かりやすいです。まずはurl-loader
もしくはasset/inline
を使った場合の<img>
、<Image>
、background-image
それぞれの画像表示方法を見てみます。
import foo from './foo.png'
import Image from 'next/image'
<img src={foo}/>
<Image src={foo}/>
<div style={{backgroundImage: `url(${foo})`}}/>
次にnextv11から使われている特有のローダーの場合。こう。
import foo from './foo.png'
import Image from 'next/image'
<img src={foo.src}/>
<Image src={foo}/>
<div style={{backgroundImage: `url(${foo.src})`}}/>
そう、書き方が微妙に違うんです。しかもimgとbackgroundは変わってるのにImageはそのまま。んでもってv11になるとこの独自ローダーは勝手にオンになり、さらにその独自ローダーの設定が他のローダーの設定より優先される。この辺りが混乱のもとですね。
結論
分かってしまえば対策は簡単で、v11からはimgとbackgroundには.srcをつけるだけです。
…もうちょい丁寧なアナウンスが欲しい気がしたけど機能として強化されてるからまあいっか!(next信者並の感想)以上。