自動で画像最適化してくれるのうれしいよね(Next.js)

f:id:yun8boo:20201130170457p:plain こんにちは。フロントエンドエンジニアの渡邉です。 普段はReactとTypeScriptを書いています。

今回の内容はタイトルにも記載されていますが、Next.jsを使った画像の最適化です。

画像の最適化でやるべきことは多々あります。 例えば、画像のサイズ・重さ調整や、フォーマット、遅延読み込みなどあります。

Next.js 10で発表されたnext/imageを使えば誰でも簡単に画像の最適化が行えるようになりました。

この記事では以下のような方が対象者となります。 - 画像の最適化?したことないや - 自動でやってくれるなら試してみたい

ただし、Next.jsの使い方などは今回は記載していないので、ご了承ください。

目次

  • 画像最適化するとなにがいいの?
  • 実際にnext/image使ってみる
  • まとめ

画像最適化するとなにがいいの?

以下のようなメリットがあります。 - 画像を最適化することによりページの読み込み速度を改善できる - SEOの改善

画像を最適化することによりページの読み込み速度を改善できる

画像を多用したページでは最適化してあるか、していないかで大きく読み込み速度に差が出てきます。 例えば、ECサイトであったり、ランディングページに置いて読み込み速度が遅いとユーザーが離脱して売上にもかなり影響出てきます。

以下の画像はGoogleがページ表示速度がユーザーにどのくらい影響するかを調査した内容です。

f:id:yun8boo:20201130165837j:plain

引用元: Find Out How You Stack Up to New Industry Benchmarks for Mobile Page Speed

1秒から3秒で32% 1秒から5秒で90% 1秒から6秒で106% 1秒から10秒で123% 直帰率が増加してしまいます。

SEOの改善

SEOの改善?と思われた方もいると思います。 どういうことかというと、Googleが、Webページの表示速度が遅いと検索のランキングに影響が出るよと言っています。 詳細はこちら

ということもあり画像の最適化がされていない表示速度が遅くなり検索ランキングが低下し、そもそもユーザーに見に来てもらえない可能性もでてきます。

上記の他にも最適化することによってのメリットは多々あります。 ただ、もちろん最適化するには工数もかかるうえに大変です。 そこで、Next.jsを使えば画像の最適化を自動で行ってくれるということです。

実際にnext/image使ってみる

nextのサンプルアプリケーションを作成し起動させます。

npx create-next-app image-pra
cd image-pra
yarn dev

アプリケーションが起動したらpublic配下に今回お試しで使用する画像を配置するのと、page/index.jsを以下のように書き換えます。

import Image from 'next/image'

function Home() {
  return (
    <>
      <h1>Image optimisation</h1>
      <Image
        src="/sample.jpg" // publicに配置した画像
        alt="sample picture"
        width={500}
        height={300}
      />
    </>
  )
}

export default Home

これだけで最適化された画像が表示されます。 f:id:yun8boo:20201130165942p:plain

基本的に使い方は既存の<img>と同じです。 ただ、heightwidthを設定しないとエラーが出ます。 f:id:yun8boo:20201130170013p:plain

ここでは、アスペクト比にあった数値をいれてもらえれば、あとはImageコンポーネントがレスポンシブに画像サイズを調整してくれます。

実際にImageコンポーネントは以下のように変換されています。

f:id:yun8boo:20201130170034p:plain

変換された<img>でsrc属性の/_next/imageというエンドポイントが気になったので説明していきます。

今回srcで指定されている/_next/imageはNext.js 10〜から予め用意されているエンドポイントです。

_next/imageのリクエストを受けるとnext-serverはimageOptimizerを実行しています。 https://github.com/vercel/next.js/blob/canary/packages/next/next-server/server/next-server.ts 抜粋

{
  match: route('/_next/image'),
  type: 'route',
  name: '_next/image catchall',
  fn: (req, res, _params, parsedUrl) =>
    imageOptimizer(server, req, res, parsedUrl),
},

image-optimizer.ts その呼び出されているimage-optimizer.tsで様々な最適化処理が行わています。 例えば、ブラウザがWebPに対応している場合にはWebPに変換するなどの対応がされています。

このように、コードの中を読むと実際にどのように最適化しているかがわかって面白いので是非お時間ある方は読んでみてください。

話がすこしそれてしまいましたが、Vercelにデプロイすれば特に設定する必要なく使えます。とても楽ですよね。

外部サービスで最適化する場合

imgixやCloudinaryの外部のサービスで画像の最適化を行う場合はnext.config.jsで設定します。 例えばimgix使う場合は以下のようになります。

module.exports = {
  images: {
    loader: 'imgix',
    path: 'https://example.com/myaccount/',
  },
}

詳しく知りたい方はimage-optimization#loaderを御覧ください。

<img>とImageコンポーネントの比較

上のsample.jpg<img>で表示している画像で、下のimage?url=~~のほうがImageコンポーネントで表示した画像です。 画像の読み込み時の詳細を見てみると、読み込み速度とサイズが大幅に改善されています。 f:id:yun8boo:20201130170406p:plain

デフォルトでここまで改善できるが素晴らしいです。 例えば、ある画像だけ品質を下げてもいいなというときには、qualityに数値を渡してあげるだけで調整ができます。

<Image
  src="/sample.jpg"
  alt="sample picture"
  width={500}
  height={300}
  quality={50} // ここで調整する(デフォルトは75)
/>

こうすることで、よりSizeを抑え込めます。 f:id:yun8boo:20201130170431p:plain

その他propsについてはnext/image#usageを御覧ください。

画像最適化の全体設定

画像最適化の全体での設定はnext.config.jsで行えます。

module.exports = {
  images: {
    // ここに記載
  },
}

こちらも詳細はimage-optimization#configurationを御覧ください

まとめ

Next.jsのImageコンポーネントを使うだけで画像を簡単に最適化することができます。 今回紹介しきれなかったんですが、初期表示で表示される画像が画面の外にある場合は、viewportを計算して遅延読み込みまでしてくれます。最近のNext.jsは成長がとてつもなく速く、質が高いので今後も楽しみです。

株式会社スタメンでは一緒に働くエンジニアを募集しています。ご興味のある方はぜひエンジニア採用サイトをご覧ください。