Lambda@Edge & Next.jsによるサイト画像最適化
はじめに
こんにちは
KINTO テクノロジーズでKINTO ONE(中古車)のフロントエンド開発を担当している中原です。
KINTO ONE(中古車) は KINTO ONE でのリースアップ車両を再度リース契約いただくための EC サイトとなっており、実際の在庫車両情報の確認や契約までの手続き、契約の管理などができるようになっています。
KINTO ONE(中古車)サイト
新車の納期が長期化して久しいですが、比較的短い納期で高品質な車両を利用できることや、中途解約時の解約金が 0 円と設定されている手軽さがおすすめのサービスとなっています。(2023 年 12 月現在、東京都・愛知県のみでのサービス展開となっています。)
車両画像の問題
新車と異なり中古車を扱うサイトにおいては、商品として個別の車両を扱うことになり、当然 EC サイトとしてはそれぞれの車両の画像を掲載することとなります。
KINTO ONE(中古車) では、リースアップ車を商品化するにあたり各車両の撮影を行い、その画像がバックエンドの車両管理サービスに格納されるようになっていました。
サイトの表示にあたっては、バックエンドから画像 URL を含む車両情報を取得しフロントエンドのサーバコンテナにてページとして構築し、車両画像に関してはクライアント側から車両管理サービスの画像配信パスから取得するようになっていました。
ここで、車両管理サービスが配信する車両の画像はワンサイズの JPG となっていたため以下のような問題がありました。
- 非効率な圧縮方式
- 表示サイズに関係ないサイズでの配信
実際のサイトでの表示サイズに関わらず、横 1000px 超の画像を配信していた
実際にサイト性能を測定するPageSpeed Insightsでも、車両画像に関する指摘が多く挙げられていました。
PageSpeed Insights の指摘
ありたい姿
まず挙げられるのは、PageSpeed Insights で指摘されたポイントの改善です。
- 効率的な圧縮方式で配信している
- 表示サイズに応じた画像サイズで配信している
これらにより、ページ表示のスピード改善・クライアントのネットワーク通信量の削減ができるだけでなく、サーバ側のコストも改善されます[1]。
また、開発・運用上の観点から次の点もありたい姿としてあげます。
- 追加リソース[2]は最小限に
- フロントエンド側から画像の変換設定の要求ができる
- 費用を抑えて、クイックに対応できる
リソースを追加すればそれに付随する管理工数も増えるため、できるだけ小さな構成でできることが望ましいです。
また変換設定については、デザインの変更や、新しいタイプ高解像度のデバイスの追加などにより表示する画像への要求が変わりうることを念頭に置いています。こういった時にフロントエンド側から容易に取得する画像の解像度や圧縮方式が変更できることが望ましいです。
画像変換手法の検討
-
車両管理サービス側で写真登録時に画像変換・配信
この方法は、事前に定めたものを作るだけならば要求を満たしていると言えますが、前節「追加リソースは最小限に」や、「フロントエンド側から画像の変換設定の要求ができる」の部分に合わないため選択しません。 -
外部サービスの利用
imgix をはじめ、さまざまな画像変換機能を持つ CDN がありますが、こちらも選択しませんでした。
サイトの利用状況から月額で言えば、200-300USD のプランがフィットしそうでした。また、作業として現状の画像を管理しているストレージに対する設定変更やそのための社内調整などで、そこそこの工数が発生しそうです。
外部サービス利用し監視等の工数がかからないことは良いですが、KINTO ONE(中古車) はまだまだ途上のサービスであり、導入効果の見積りも難しい中、金銭的・時間的コストを鑑みて選択しませんでした。 -
Next.js のリモート画像最適化
最も実装の工数がかからない方法としては Next.js の Image コンポーネントを用いて画像を最適化させる方法ですが、この方法も現在のサイト状況に見合わず取らないこととしました。
現状、Next.js をフレームワークとして利用し、サーバサイドレンダリングによるサイト配信を行っていますが、サーバとしては比較的小さなインスタンス構成で実行しています。しかし、1 ページあたりの画像の点数も多く、処理の負荷がピーキーになることから、最小負荷時におけるインスタンスサイズを大きくする必要がありそうでした。実際にサービス初期に同様の設定を行っていた際にサイトがダウンしてしまうこともありました。
画像変換のためだけにインスタンスサイズを大きくすることは避けたかったのでこの方法も選択しませんでした。 -
Lambda@Edge で自前で構築(★ 採用)
Cloudfront と組み合わせでエッジ側で画像変換を行う関数を実行し、変換後の画像を配信する方法です。サイト自体は Cloudfront 経由で配信していましたので、少し設定を追加するだけで素早く導入できそうでした。費用面も画像の枚数から変換処理に関してはほぼかからず、サイズを圧縮することから転送費用も圧縮できます。実装の手間は少々かかりますが以降はサーバレスで動作してくれるので、同時実行数にさえ気をつければそこまで管理の手間も掛からなそうでさそうでしたのでこの方法で行くことにしました。
Lambda@Edge での画像変換機能追加
以下のような構成へと変更します。
車両画像のパスへアクセスした際のビヘイビアを追加し、Lambda@Edge でリサイズ・WebP への変換を行なった結果を返却するようにしました。
Lambda@Edge での処理内容については、先例[3]や AWS 公式のガイド[4]など、情報が多くあるのであまり詳しくは記載しませんが、今回の実装におけるポイントに触れておきたいと思います。
-
クエリパラメータでの画像変換内容指定
画像の変換設定は以下のクエリパラメータで指定できるようにしておきます。query 説明 width リサイズ後の画像の横幅を指定 quality 画像変換時の画質を設定 これによりサイト側から表示したいサイズの画像を指定したサイズ・画質で取得できるようになります。
-
キャッシュ設定
上記のクエリパラメータをキャッシュキーとして設定するようにします。これを怠ると、先に生成されたサイズの画像がキャッシュされてしまい、大きなサイズの画像を要求したのに小さいサイズの画像が表示されてしまう、といったことが起きてしまいます。
next/image のカスタムローダー設定
Cloudfront 側で画像変換をできるようにしたら、ページ側でも対応する実装が必要になります。
本サービスは Next.js でサイト構築していますので、Image コンポーネントに対してカスタムローダーを設定することで細かな設定をすることなく表示されるサイズに対して最適な画像のサイズでリクエストすることができます。
なお、表示に対して最適なサイズを選択するためにはsizes
プロパティの設定が重要なので注意しましょう。
この値を設定することにより、Image コンポーネントのレンダリング時にsrcset
プロパティを実際の表示サイズに適した値で設定してくれます。
import Image, { ImageLoaderProps } from "next/image";
// 車両画像用コンポーネント
export function CarImage({ src, sizes, alt = "車両画像", className = "" }) {
// カスタムローダー
function optimizeLoader({ src, width, quality }: ImageLoaderProps) {
return `${src}?width=${width}&quality=${quality}`;
}
return (
<Image
className={className}
src={src}
alt={alt}
sizes={sizes}
quality={90}
loader={optimizeLoader}
loading="lazy"
/>
);
}
このようなコンポーネントを作成し利用することで、サイト上の表示サイズに応じた画像サイズのパラメータでリクエストされ、リサイズ・WebP 変換された画像を表示できるようになります。
結果
今回の手法で画像最適化を行うことで、PageSpeed Insights の画像に関する指摘が解消していることが確認できました。
PageSpeed Insights の画像に関する指摘が解消されました
最後に
今回はサイトパフォーマンス改善のうち、表示画像について最適化を試みました。ですがまだまだパフォーマンスの問題は多く山積しています。
引き続きサイトパフォーマンスの改善をし、ユーザにより快適な体験をしていただけるように取り組んでいきたいです。
KINTO テクノロジーズでは主に AWS 上にサービスを構築していますが、インターネットへのデータ送出もコストがかかるポイントです ↩︎
ここで言う「リソース」とは AWS のリソースだけでなく、画像変換の外部サービスなども含めた概念です。 ↩︎
https://techlife.cookpad.com/entry/2018-05-25-lambda-edge ↩︎
https://aws.amazon.com/jp/blogs/news/resizing-images-with-amazon-cloudfront-lambdaedge-aws-cdn-blog/ ↩︎
関連記事 | Related Posts
We are hiring!
【フロントエンドエンジニア(コンテンツ開発)】新車サブスク開発G/東京
新車サブスク開発グループについてTOYOTAのクルマのサブスクリプションサービスである『 KINTO ONE 』のWebサイトの開発、運用をしています。業務内容トヨタグループの金融、モビリティサービスの内製開発組織である同社にて、自社サービスである、クルマのサブスクリプションサービス『KINTO ONE』のWebサイトコンテンツの開発・運用業務を担っていただきます。
【フロントエンドエンジニア】新車サブスク開発G/東京
新車サブスク開発グループについてTOYOTAのクルマのサブスクリプションサービスである『 KINTO ONE 』のWebサイトの開発、運用をしています。業務内容トヨタグループの金融、モビリティサービスの内製開発組織である同社にて、自社サービスである、TOYOTAのクルマのサブスクリプションサービス『KINTO ONE』のWebサイトの開発、運用を行っていただきます。