LoginSignup
3
0

More than 3 years have passed since last update.

Next.js 10のnext/imageについて調査してみた

Posted at

概要

2020年10月27日にリリースされたNext.js 10ですが、画像表示が非常に便利になっていましたので、調査をしてみました。
※調査したバージョンは10.0.3です。

Next.js 10の画像表示とは

next/imageとしてReact Componentが用意されていて、自動的に最適化してくれます。

以前の書き方

<img src="/profile-picture.jpg" width="400" height="400" alt="Profile Picture">

Next.js 10の書き方

import Image from 'next/image'

<Image src="/profile-picture.jpg" width="400" height="400" alt="Profile Picture">

next/imageの機能について

リサイズ

ブラウザのビューポートによって最適なファイルサイズにします。

画像フォーマットの変換

ブラウザのサポート状況によって、次世代画像フォーマットにします。
次世代画像フォーマットとは、WebP、JPEG2000、JPEG XRのことで、従来のJPEGやPNGに比べ、ファイルサイズが小さく、表現力が高いです。
ただ、ブラウザのサポート状況がバラバラなため、開発者としては非常に扱いづらい状況でした。
しかし、next/imageがサポートしてくれるため、開発者がフォーマット変換する必要もなく、ユーザーは早く表示ができます。

画像フォーマットについて
https://websas.jp/column/developer-01

各フォーマットのサポート状況
https://caniuse.com/#feat=webp
https://caniuse.com/#feat=jpeg2000
https://caniuse.com/#feat=jpeg+xr

画像が別のURLにあっても、最適化可能

画像などのリソースは画像用のサーバーに置いておくこともあります。
そういう場合でも、next/imageは使えます。
next.jsの設定ファイルでホスティングされているURLパスを設定できます。

リクエスト時に最適化する

画像の最適化処理はビルド時ではなく、リクエスト時にします。
最適化された画像ファイルは、.next/cache/images ディレクトリに保存されます。

キャッシュ

最適化された画像ファイルは有効期限が設定され、期限内であれば再利用します。
期限を過ぎていた場合は、新しく最適化する前に削除されます。

有効期限は画像配信するサーバーのレスポンスヘッダーのCache-Controlを参照しているようで、s-maxageがあればその値を、なければmax-ageを、それもなければ60秒です。

next.js内で画像を管理する場合は、next.config.jsで有効期限を変更できます。

60秒から5分にする例

module.exports = {
 async headers () {
   return [
     {
      source: '/(.*).(jpg|png)',
      headers: [
        {
          key: 'Cache-Control',
          value:
            'public, max-age=300, s-maxage=300',
        },
      ],
     }
   ]
 }
}

遅延ロードがデフォルト

遅延ロードとは、ユーザーが画像を見える位置に近づいた時に、画像をダウンロードする方法です。
初期表示に見えない画像までダウンロードして、表示速度を遅くするのを避けられます。

※コードを見たところ、画像ファイルから200px以内になると、ダウンロードされるようになっていました。
https://github.com/vercel/next.js/blob/v10.0.3/packages/next/client/image.tsx#L246

サンプルコードの起動

サンプルコードが公式で用意されているので、こちらを使いました。
https://github.com/vercel/next.js/tree/v10.0.3/examples/image-component

ダウンロードしてローカルで起動するのもありですが、こちらでも確認できます。
https://image-component.nextjs.gallery/layout-fixed

用意されている画像

画像ファイル名 容量 サイズ
moutain.jpg 294KB 2800 x 1900

コード

import Image from 'next/image'
import ViewSource from '../components/view-source'

const Fixed = () => (
  <div>
    <ViewSource pathname="pages/layout-fixed.js" />
    <h1>Image Component With Layout Fixed</h1>
    <Image
      alt="Mountains"
      src="/mountains.jpg"
      layout="fixed"
      width={700}
      height={475}
    />
  </div>
)

export default Fixed

動作確認

起動時の.nextディレクトリを見ると、imagesディレクトリは作られていません。
image.png

ブラウザでアクセスすると、webpの画像ファイルができました。
image.png

開発者ツールのNetworkを見てみると、/image というエントリーポイントに対して、パラメータが渡されています。

パラメータ 説明
url 画像ファイルのURL。Imageのsrc。
w 最適化後の横幅。
ビューポートとImageに渡されたpropsを元に、deviceSizesから最適な横幅を選択。
q 最適化の品質。デフォルトが75で、Imageのpropsで設定も可能。

image.png

ダウンロードされているwebpのファイルサイズは6.7KBになっています。
macのプレビューツールで横幅750pxでjpegでリサイズした場合、27KBだったので、4倍も違うことになります。
画像を多く表示するサイトだと、ページ表示速度はかなり改善できますね。

各ブラウザの挙動

ブラウザごとに最適な画像を提供してくれるとのことなので、いろんなブラウザで試してみました。

ブラウザ 画像フォーマット 画像の横幅 ダウンロードサイズ 補足
iPhone11 Pro Safari webp 元の横幅 152KB
Android Chrome webp 元の横幅 156KB
mac Chrome webp 750px 18KB
mac Safari webp
※OSバージョンによってはjpegになる
1920pxと元の横幅 74KBと152KB 2回ダウンロードしてしまうバグがあるようです。
https://github.com/vercel/next.js/issues/19478
Windows IE11 jpeg 元の横幅 255KB
Windows Edge (Chromium) webp 750px 18KB
Windows Firefox webp 750px 18KB

widthを700で設定しているので、それに近い750pxがダウンロードされるはずですが、元の横幅でダウンロードされてしまうのは、バグでしょうか?

元の横幅でダウンロード時、パラメータのwは3840でしたが、これはdeviceSizesの最大値です。
バグが修正されるのが一番いいですが、一時的な対処方法としては、横幅が3840pxも必要なサイトはそこまで多くないと思うので、next.config.jsでdeviceSizesを変更するのが良さそうです。

元画像がpngの場合

webpの話になってしまいますが、pngも気になったので、いくつか画像を集めて最適化の効果を確認してみました。
画像の横幅は変えていません。

元サイズ webp後のサイズ
242KB 27KB
239KB 44KB
23KB 4KB
176KB 31KB
84KB 24KB

画像によりますが、約4分の1〜9分の1に減りました。
pngもかなりサイズダウンできますね。

なぜnext/imageが作られたのか

Next.js公式ドキュメントでCLSが触れられていることもあり、Core Web Vitalsを考慮している可能性が高いです。
Core Web VitalsとはLCP、FID、CLSという3つのパフォーマンス指標で、大きいサイズの画像ダウンロードや、画像が遅れて表示された時にレイアウト位置がずれると、悪い影響が出てしまいます。
Googleが2021年5月から検索ランキングの指標に含めると発表したこともあり、とても重要な指標になっています。

Core Web Vitalsについて
https://www.sakurasaku-labo.jp/blogs/core-web-vitals

まとめ

next/imageは機能豊富で便利ですが、Propsも多く少しだけ学習が必要になります。
2021年5月にはCore Web Vitalsの影響が出てきてしまうので、Next.jsを使っている場合、早めにバージョン10を取り込むのがいいと思います。

参考ページ

3
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
3
0