CloudFront FunctionsでWordPressからWebP形式の画像を配信する
こんにちわ@・ェ・)めー。
ブログやWebサイトを高速化する方法として次世代フォーマットでの画像配信を行うというものがあります。
おなじみのJPEGやPNG形式の画像から、WebPという次世代の形式の画像にすることで同じ画質でも画像のサイズが小さくなり、より早く転送できるというわけです。このブログもPageSpeedInsightの指摘に出てきたのでCloudFront Functionsを使ってWordPressのWebP対応を行ってみようとおもいます。
CloudFrontを使っているWordPressでWebP対応をするには
CloudFrontを利用していない場合
まずはCloudFrontを利用していない構成を理解します。
CloudFrontを使っていないWordPressはEWWW Image Optimizerプラグインを使うと比較的簡単にWebP対応を行うことができます。このプラグインはApacheのmod_rewriteを使ってWebP対応を実現しています。これが何をやっているかと以下のようなフローになります。
画像(JPG・PNG・GIF)をリクエストするよ
ブラウザがWebPに対応していれば
WebP形式の画像がリクエストされたことにして
WebP形式の画像を返すよ
ここで重要なのはWordPressのサーバーは従来の画像のリクエストが来たら、WebP形式の画像がリクエストされたことにしてWebP形式の画像を返していることです。「されたことにして」というのがポイントです。.htaccessに追加したリライトルールによってリクエストされた画像のURLに変更を行っているんですね。
このフローはCloudFrontのようなCDNを使っている場合に状況が変わってきます。
CloudFrontを利用している場合
CloudFrontのようなCDNを利用している場合はどうなるかというと……
画像をリクエストするよ
画像のレスポンスを返すよ
リクエストまだかな
このようにブラウザからのリクエストをCloudFrontが受け付けてCloudFrontが画像のレスポンスを返すため、そもそもリクエストがWordPressに届きません。ApacheやWordPressの設定を変えてもリクエストが届かないので、WordPressからはどうすることもできないんですね。
CloudFrontはリクエストされた画像やCSSなど静的なコンテンツを高速に返すことに特化しているので今まではここに手を入れることができませんでした。
これを解決するアプローチは少なくとも2通り考えられます。「最初からクライアントがWebP形式の画像をリクエストする」か「CloudFrontがうまいことよろしくやる」です。今回は後者を採用することにしました。
CloudFront Functionsとは
2021年5月にリリースされたばかりの新しいAWSのサービス、CloudFront Functionsを使ってWebP対応を行うことにしました。
CloudFront Functionsが何なのかというとCloudFront上でJavaScriptのコードを実行できるサービスです。既存のサービスで似たようなものにLambda@Edgeというものがありますが、CloudFront FunctionsはLambda@Edgeよりも機能と制限が厳しい代わりに高速で料金も安いという特徴があります。特に実行時間の制限は厳しく、すべての処理を1msで終わらせる必要があります。
目的に対してちょうどいいサービスだし、まだ使っている人が少なくて面白そうだったのでお勉強も兼ねてやってみようかなといったところです。
両者の詳しい違いについてはDevelopersIOの記事が参考になりました。
WebP対応の手順
前提事項
アクセスしてくるブラウザは全てWebP形式の画像に対応しているものとします。IEや一部のブラウザはWebPに対応していませんが潔く切り捨てることにします。
主要なブラウザはWebPに対応しています。MacとiOSもしばらく前に対応されているのでWebP対応前提で構わないと思います。
ブラウザ | WebP対応状況 | 備考 |
---|---|---|
IE | × | 対応されることは無いでしょう |
Edge | ○ | |
Chrome | ○ | |
Firefox | ○ | |
Safari(Mac) | ○ | macOS 11 Big Surから対応 |
Safari(iOS) | ○ | iOS14から対応 |
Chrome(Android) | ○ |
ブラウザごとの詳細な対応状況は以下のページを参照してください。
事前準備:プラグインのインストール
まずはJPGやPNG画像をアップロードした際に自動的にWebP形式の画像を作成するようにします。これはEWWW Image Optimizerプラグインで実現します。プラグインをインストールして以下の設定にします。
タブ | 項目 | 値 |
---|---|---|
基本 | WebP変換 | ON |
JS WebPリライト | OFF | |
<picture> WebPリライト | OFF | |
高度な設定 | 定期的な最適化 | OFF |
EWWW Image OptimizerプラグインにはWebP対応の機能がありますが、説明したとおりCloudFrontがある場合は使うことができません。このプラグインはjpgやpng形式の画像から自動的にWebP形式の画像を作成することに使います。
事前準備:既存画像の一括最適化
多くの場合、WordPressは既に運用中でメディアライブラリに複数の画像がアップロード済みの状況かと思います。メディアの一括最適化から「最適化されていない画像をスキャンする」を選択して一括で既存画像のWebP版を作成しておきます。
CloudFront Functionsの登録
CloudFrontでWebP形式に対応する画像はメディアライブラリ内にある画像に限定してWordPress本体、テーマやプラグイン内蔵の画像は対象外にします。
私のブログの場合はメディアの設定で「アップロードしたファイルを年月ベースのフォルダーに整理」をONにしているので画像のURLはこんな感じ(/wp-content/uploads/2021/05/abc.jpg)になります。そのためuploads/数字4桁のURLでJPGもしくはPNGのときはWebP形式の画像がリクエストされたことにする、というコードにしています。
function handler(event) {
var request = event.request;
var uri = request.uri;
if (uri.match(/uploads\/\d{4}/) && (uri.endsWith('jpg') || uri.endsWith('png'))) {
console.log(uri);
request.uri += ".webp";
}
return request;
}
このコードをAWSのCloudFront Functionsに登録し、WordPressで使用しているディストリビューションのビヘイビア「wp-content/*」にビューワーリクエストとして紐付けます。
動作確認とテスト
テストその1:デベロッパーツールで確認する
ブラウザのデベロッパーツールを開き、ネットワークタブを選択します。ブログを再読込し、画像のリクエスト・レスポンスを確認します。
Request URLでJPGもしくはPNG形式の画像のとき、Response Headersのcontent-typeが「image/webp」になっていれば成功です。あわせてCloudWatchにCloudFront Functionsのログが出力されていることも確認します。
テストその2:コマンドで確認する
Macなどでcurlコマンドが使用できる場合はターミナルから下記の要領で確認することができます。
curl -i 'https://www.example.com/wp-content/uploads/xxxx/xx/xxx.jpg'
デベロッパーツールと確認する箇所は同じ。content-typeが「image/webp」になっていれば成功です。
PageSpeed Insights
PageSpeed Insightsでブログの再計測を行います。改善できる項目に「次世代フォーマットでの画像の配信」が出てこないか、メディアライブラリ内の画像の指摘がなければ成功です。
WebP生成前のCloudFrontのキャッシュに注意
画像をアップロードした際にEWWW Image OptimizerプラグインがバックグラウンドでWebP版の画像を生成します。この時、まだWebP版の画像が生成される前にブラウザから画像へのリクエストが送られるとCloudFrontが「画像が存在しないレスポンス」をキャッシュしてしまいます。そのためWebP版の画像が生成された後に画像にアクセスしようとしてもCloudFrontから返ってくるのは「画像が存在しないレスポンス」となってしまいます。
これを解決するにはキャッシュのTTLまで待つか、CloudFrontにInvalidationsのリクエストを投げてキャッシュを無効化すると改めてWebP版の画像にアクセスすることができます。メディアライブラリに画像をアップロードする場合はこの状態になりませんでしたが、記事の編集画面に直接画像をドロップすると発生しました。
また、今回紹介した方法では管理画面と公開用のドメインが同一である場合、管理画面の画像もCloudFront Functionsの処理対象となります。アップロードした画像が表示されない場合は各種AWSのログを参照することをおすすめします。