最近京都に引っ越した福田です。 全然更新できてないですがエンジニアも増えてきたので頻度上げたいとは思ってます。
Next.js 10リリースされましたね
next/image
が出てきたりhref
にas
が要らなくなったりi18n系の新機能だったり、すぐにでも使ってみたい機能が色々ありましたね。
RITのコーポレートサイトではNext.js使ってるんですが、特に画像の最適化をサボってたせいでLighthouseのスコアがよろしくなくて、丁度いい機会だったので主にnext/image
使うためにバージョンアップしてみました。
変更点
インフラ構成の変更
旧構成
図にするほどのものでもないですがGitHub Actionsでbuildとexportしたファイルをfirebase hostingにデプロイしてます。
新構成
Cloud Runが追加されてますね。
これは微妙にハマったポイントでもあるんですが、現状next/image
はSSR必須っぽいのでnextを動かすサーバが必要になります(違ったらごめんなさい)。
なので、firebaseでキャッシュされてるリソースはfirebaseから返しつつ、キャッシュされてないリソースは裏のCloud Runにリクエスト投げてビルドしてもらうような構成に変更しました。
実際のfirebase.jsonは↓みたいな感じ(rewritesのところがCloud Runにリクエスト投げる設定)。
{ "hosting": { "public": "public", "ignore": [ "firebase.json", "**/.*", "**/node_modules/**" ], "rewrites": [ { "source": "**", "run": { "serviceId": "<Cloud Runのサービス名>", "region": "asia-northeast1" } } ] } }
Cloud Runはリクエストがなければ0までスケールダウンしてくれるので、適切にキャッシュしておけばCloud Runの費用はほぼかからないはず。
この"適切にキャッシュ"というのが厄介なんですが、firebaseはCloud RunからのレスポンスのpublicなCache-Control
ヘッダを見てfirebaseへのキャッシュを行う(参考)ので、next.jsのレスポンスでCache-Control
ヘッダを返してやる必要があります。
特にキャッシュしちゃいけないリソースもないので、ここでは適当にすべてのパスへのリクエストで1日キャッシュするように設定しておきました。
nextのheader周りあんまりちゃんと理解してないのでもっといい設定方法があるかも。
module.exports = { async headers() { return [ { source: '/', headers: [ { key: 'Cache-Control', value: 'public, max-age=86400', }, ], }, { source: '/:path*', headers: [ { key: 'Cache-Control', value: 'public, max-age=86400', }, ], }, ]; }, };
next/imageの導入
一番面倒だったのはlayout指定しないと必須になるwidthとheightの指定です。 ただ、これはそもそもnext/image使わずただのimgタグだったとしてもUX的にちゃんとしといたほうがいいので頑張って指定しましょう。 他はimgタグと同じ感覚で大丈夫でした。
<Image src='/static/img/top/service.jpg' alt='service' width={612} height={510} />
ちゃんとwebpになってますね。
結果
(Next.js関係なくページ遷移時のアニメーション消したのも影響してますが許してください)
変更前
よろしくない数字ですね。
変更後
だいぶ改善しました。
画像の最適化という面倒な問題をnext/image
使うだけでいい感じにやってくれるのは便利ですね。
さいごに
最初はnext/image
使って高速化するだけのつもりだったんですが、Lighthouseちゃんと見てみたらNext関係ない部分で最適化できる箇所とかも割とあったので、適宜パフォーマンスチェックするのは大事ですね。
RITでは、新しい技術をキャッチアップしてユーザに最適なパフォーマンスで価値を提供できるエンジニアを募集しています!