RIT Tech Blog

株式会社RITのエンジニアが知見を共有する技術ブログです。

コーポレートサイトのNext.js 10対応ついでにパフォーマンス改善してみた

f:id:rit-inc:20201107133327p:plain

最近京都に引っ越した福田です。 全然更新できてないですがエンジニアも増えてきたので頻度上げたいとは思ってます。

Next.js 10リリースされましたね

next/imageが出てきたりhrefasが要らなくなったりi18n系の新機能だったり、すぐにでも使ってみたい機能が色々ありましたね。 RITのコーポレートサイトではNext.js使ってるんですが、特に画像の最適化をサボってたせいでLighthouseのスコアがよろしくなくて、丁度いい機会だったので主にnext/image使うためにバージョンアップしてみました。

変更点

インフラ構成の変更

旧構成

github actions + firebase
旧構成

図にするほどのものでもないですがGitHub Actionsでbuildとexportしたファイルをfirebase hostingにデプロイしてます。

新構成

github actions + firebase + cloud run
新構成

Cloud Runが追加されてますね。 これは微妙にハマったポイントでもあるんですが、現状next/imageSSR必須っぽいので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になってる
webp確認

ちゃんとwebpになってますね。

結果

(Next.js関係なくページ遷移時のアニメーション消したのも影響してますが許してください)

変更前

Performanceが低い
Lighthouse結果

よろしくない数字ですね。

変更後

Performanceが91に改善
Lighthouse結果

だいぶ改善しました。 画像の最適化という面倒な問題をnext/image使うだけでいい感じにやってくれるのは便利ですね。

さいごに

最初はnext/image使って高速化するだけのつもりだったんですが、Lighthouseちゃんと見てみたらNext関係ない部分で最適化できる箇所とかも割とあったので、適宜パフォーマンスチェックするのは大事ですね。

RITでは、新しい技術をキャッチアップしてユーザに最適なパフォーマンスで価値を提供できるエンジニアを募集しています!

herp.careers