0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

next/imageの画像最適化を独自実装してみた

Posted at

next/imageとは?

reactのフレームワークであるNext.jsが標準で提供している画像用のコンポーネント。

画像のパフォーマスを上げる機能が色々と付いており、この中に画像最適化というものがある。

画像最適化とは?

色々ありますが、主に以下が自動で行われる。

  • ①webpへの変換
    • pngに比べてファイルサイズが半分になる
    • 見た目もほぼ変わらない
  • ②圧縮してファイルサイズの削減
  • ③指定された画像サイズ、またはレスポンシブの場合画面幅によって自動で表示する画像サイズを変更
    • 画面サイズが小さいスマホでは小さいサイズの画像、画面サイズが大きいPCでは大きいサイズの画像を表示してくれる。例えばスマホであまりに大きいサイズの画像を表示してしまうと不必要に表示まで時間がかかってしまうため

より詳細は以下記事参照

独自実装した理由

vercelの無料プランだと画像最適化が1000枚までの制限があったため。有料プランだと5,000枚になるが、上げるのは難しったので独自実装できないか?と試してみた。

CleanShot 2025-02-04 at 16.40.24@2x.png

ref:https://vercel.com/docs/pricing/image-optimization

独自実装した方法

①sharpパッケージで画像変換

画像のリサイズなど様々な処理をできるsharpパッケージを使用する。next/imageも内部的にはこのsharpパッケージを使用している。

今回はnext/imageで行われている以下の処理をする。

  • webpへの変換
  • qualityによる圧縮
  • 各サイズの画像を作成

以下コード例

import sharp from 'sharp'

const deviceSizes = [475, 640, 750, 828, 1080, 1200, 1920]
const imageUrl = 'https://placehold.jp/1920x1920.png'
const response = await axios({
    responseType: 'arraybuffer',
    url: imageUrl,
})

for (const size of deviceSizes) {
    const outputPath = `image-${size}.webp`

    const image = await sharp(Buffer.from(response.data))
      .resize(size, null, {
        fit: 'inside',
      })
      .webp({
        quality: 75,
      })
      .toFile(outputPath)
  }

サイズの配列でループ処理して、sharpのresize関数にサイズを指定して画像サイズを変更。
sharpのwebp関数でwebpに変換。
webp関数のオプションのqualityでnext/image同様に圧縮できる

自分の場合はsharpで変換した画像をaws s3に保存しておき、画像キャッシュもしたいのでcloudfrontを経由して画像を配信しています。

CleanShot 2025-02-24 at 15.32.45@2x.png

②imgタグのsrc、srcsetにsharpで変換した画像を指定する

画像URLは例です。

<img 
    src="https://placehold.jp/1920x1920-1920.webp" 
    srcset="
        https://placehold.jp/1920x1920-475.webp 475w, 
        https://placehold.jp/1920x1920-640.webp 640w, 
        https://placehold.jp/1920x1920-750.webp 750w, 
        https://placehold.jp/1920x1920-828.webp 828w, 
        https://placehold.jp/1920x1920-1080.webp 1080w, 
        https://placehold.jp/1920x1920-1200.webp 1200w, 
        https://placehold.jp/1920x1920-1920.webp 1920w
    " 
    sizes="(max-width: 768px) 100vw, 50vw"
    loading="lazy"
>

next/imageも内部的にはこのsrcsetが使用されている

レスポンシブ画像の場合はsizesの指定も重要になります。srcsetとsizesの書き方は以下記事を参考にしください

最後に

独自実装してみて、これらを全て自動で行ってくれるnext/imageが便利だなと改めて実感しました。Next.jsを使っておらずnext/imageが使えない場合や、自分と同じように無料プランの1,000枚を越えそうなときにぜひ独自実装をお試しください

0
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
0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?