特に意味はないんだけど、Lighthouseのスコアが微妙に100点に届いていなかったので、前回の対応(Got 100 lighthouse score in all categories on mobile)に続いて、また100点を目指して修正してみました。
今回は「遅延読み込みが多すぎるとパフォーマンスに影響する」という項目にひっかかっていました。とりあえずなんでもloading="lazy"
を付けておけばいいと思っていたんですが、初期ビューポート内の画像まで lazy にしてしまうと、LCP(Largest Contentful Paint)の指標がむしろ悪化することがあるらしい。
あと「適切なサイズの画像」という項目にもひっかかっていた。ChatGPTで生成した1024×1024の正方形画像をFeatured Imageに使っていたのですが、横長で表示する場合には表示されない部分のピクセルが無駄になってるという、なんかそういうことらしい。
そこで、generate-responsive-images-serviceの中でsharpを使って画像リサイズする処理に、表示サイズに合わせて中央を切り取る処理を追加し、画像を再生成しました。コードはChatGPTが出してくれたものをほぼそのまま使ってる。
if (cropWidth || cropHeight) {
cropWidth = cropWidth || width;
cropHeight = cropHeight || height;
const left = Math.floor((width - cropWidth) / 2);
const top = Math.floor((height - cropHeight) / 2);
sharpObject = sharpObject.extract({
left,
top,
width: cropWidth,
height: cropHeight
});
}
また、Best Practice の「Avoids third-party cookies」で Google Analytics が引っかかっていたので、今回は単純にスクリプトごと削除しました(そもそも特に見ていなかったし)。真面目に対応しようとすると結構面倒くさそう。
Chrome is moving towards a new experience that allows users to choose to browse without third-party cookies. Learn more about third-party cookies.
まあとにかく、100点いったので記念のスクリーンショット。以前と同じく花火っぽいのが出てくる。

追記(2025/4/15)
上の extract
だと、たとえば画像の横幅が3000pxあったりすると、画像の真ん中を小さなエリアを切り取る感じになってしまうので、sharp.resizeでリサイズしつつ切り取る方が自分のやりたいケースとしては適切だった。
const sharpObject = sharp(buffer);
const { width, height } = await sharpObject.metadata();
if (cropWidth || cropHeight) {
cropWidth = (cropWidth || width) * scale;
cropHeight = (cropHeight || height) * scale;
sharpObject.resize(cropWidth, cropHeight, {
fit: "cover",
position: "centre"
});
}