Next.js 10のnext/imageによる画像最適化を試してみた
概要
Next.js 10が発表されたのでnext/imageによる画像最適化を試してみました。
試し方
npx create-next-app
next dev
します。
10.0.0になってました!
こちらを見ながら試してみます。
画像はフリー素材のこちらを使います。
next/images
画像はpublic/free.jpgに入れています。
widthやheightを書かずにただ書くとエラーになります。
import Image from 'next/image';
<Image src={"/free.jpg"} />
両方書くと動きます。片方だけだとエラーになります。
<Image src={"/free.jpg"} width={1920} height={1281} />
アスペクト比を無視すると画像が歪みます。
<Image src={"/free.jpg"} width={1000} height={100} />
unsizedだと、1200px * 801pxになっていました。(元画像は1920 * 1281)
<Image src={"/free.jpg"} unsized />
中身
こんな感じになっていました。width、heightで指定したサイズ以下の複数サイズで、適切なサイズのものが自動で提供されるようになっていました。
unsizedだと1200px以下で設定されます。
幅はnext.config.jsのdeviceSizesで変えられます。
画像のサイズなどはURLのクエリパラメータで制御しているようです。
例えばqの値を上下させると画質、ファイルサイズも上下します。
http://localhost:3000/_next/image?url=%2Ffree.jpg&w=1200&q=75
WebPフォーマットに対応、が
元画像のサイズは695KBでjpgです。
Chromeで表示した場合は image/webp
としてファイルサイズは130KBになっていました。
Safari(webP非対応)で表示した場合は image/png
としてファイルサイズは1.6MBになっていました。
なぜpngでサイズ倍にした!!
safariの開発者ツール詳しくないですが見方間違ってますかね??
追記:
10.0.1で直ってました!
がんがんjpg使いましょう。
外部ファイルの読み込み
外部ソースもいけるのかなと思いやってみたところ、エラーになってしまいました。
Unhandled Runtime Error
Error: Invalid src prop (https://hogehogehoge.net/hogehoge/) on `next/image`, hostname is not configured under images in your `next.config.js`
next.conig.jsにloaderとpathを設定するといけそうなのですが、現時点ではVercel、Imgix、Cloudinary、Akamaiしか対応してなさそう?
対応できても、path: '/_next/image',
の部分も上書きすることになってしまうので、完全に外部に出すか、内部のみでのどちらかしかできないんですかね?
追記:
と思っていたらdomains指定で普通にできました。
公式に対応しているとどう違うのかなどもわかったら追記しますー
遅延ロード
ビューポートが近づくと画像をロードする機能で、正常に動いています。
画像の上200pxぐらいから反応してダウンロードしてました。
初期のぼかし画像表示
なさそうです。gatsby-imageのようにインライン化したぼかし画像が欲しかったですね。
小さい画像はインライン化される?
800バイトのsvg画像で試した限りではされないようです。
結論
なんでwebp非対応ブラウザだとjpgがpngでサイズ2倍になるの?
他は大丈夫そうです。
next-optimized-imagesがいまいちだったので、不思議サイズ問題だけ解決してくれれば。
追記:
10.0.1でjpgのサイズがおかしくなる問題が直ったので使っていきます!
Discussion
WebP未対応のSafariでJPEGがPNGになってしまう問題、ちょっと調べてみました。
下記の部分が原因っぽいですね。
(
next/image
コンポーネントではURLを生成しているだけで、実際の画像の生成はnext-server/server/image-optimizer.ts
で行われています。)この
image-optimizer
では、クライアントから送られてきたAccept
ヘッダーに従ってContent-Type
を決めて画像を生成します。iOS13以前だと画像のAcceptヘッダーはデフォルトで
image/png, image/svg+xml...
から始まるようで(参考)それによりPNG画像が返ってきてしまうと。とりあえずの対処方法がないか調べてみます。
おお、流石…!
ありがとうございます!