Vercel + GatsbyJSの最適なキャッシュ設定を紹介します

更新日: 2020/07/07

@Panda_Program

Vercel + GatsbyJSのキャッシュの設定

**VercelとはVercel社(旧ZEIT)が開発しているサーバレスなホスティングサービスです。**VercelはCDNであるためJAMStackなアプリケーションをデプロイするために最適で、Vue、Nuxt.js、React、Next.js、GatsbyJSなどフロントエンドのアプリケーションのデプロイ先として相性がとても良いです。

GatsbyJSとは、React.js製の静的サイトジェネレータです。SSRをすることでビルド時に最適化された静的ファイルを生成するため、サイトの表示速度が爆速になります。

GatsbyJSについては「GatsbyJSで実現する、高速&実用的なサイト構築」という本が詳しいです。GatsbyJSの構成やブログの作り方などが解説されています。

この記事では、VercelにGatsbyJSをデプロイする時のオススメのキャッシュの設定方法をご紹介します。

関連記事: NetlifyでGatsbyJSのキャッシュを設定してレスポンス速度を爆速にしよう

GatsbyJSのキャッシュ戦略はファイル名の変更の有無で決める

GatsbyJSのキャッシュ戦略は、ざっくり分けるとファイル名が変わらないものはキャッシュせず、ビルドのたびにファイル名が変わるものはキャッシュするというものです。

ビルドごとに名前が変わるファイルは、cache-controlヘッダーにmax-age=31536000を付与して1年間キャッシュします。これはビルドのたびにファイル名に一意なハッシュが与えられ、サイトにアクセスするたびに読み込むファイルが変わるため、ブラウザは古いファイルを読み込むことがないからです。

反対にpage-data.jsonなどはビルドするとファイルの内容が変わるものの、ファイル名は変わらないため、キャッシュしないのがGatsbyJS公式の推奨設定です。

Vercelの設定ファイルvercel.jsonにキャッシュの設定を書く

**Vercelの設定は、vercel.jsonに書き込みます。**vercel.jsonはルートディレクトリに作成しましょう。

Vercelでレスポンスに含めるHTTPヘッダーを設定するときは、以下のようにheadersの項目に記述します。

vercel.json
{
  "headers": [
    {
      "source": "(.*).html",
      "headers":[
        // ...
      ]
    }
  ]
}

sourceは該当するファイル名を指定します。Vercelはパスの取得に正規表現を使っていません。このため*.htmlという正規表現のシンタックスを書くことはできません。

Vercelはpath-to-regexpを利用しているので、全てのHTMLを指定する場合は(.*).htmlとsourceに記述します。

次に、HTTPヘッダーはheadersのkeyとvalueに記述します。

vercel.json
{
  "headers": [
    {
      "source": "(.*).html",
      "headers":[
        {
          "key" : "Cache-Control",
          "value" : "public, max-age=0, must-revalidate"
        }
      ]
    }
  ]
}

これで「HTMLファイルはキャッシュせず、必ずサーバーに問い合わせる」という設定が書けました。同様に、JSやCSS、sw.jsや画像ファイルにもキャッシュヘッダーを付与しましょう。

この記事の最後に、GatsbyJSが生成する全てのコンテンツに対してGatsbyJSが推奨するキャッシュヘッダーを付与する設定を書いたvercel.jsonを掲載しています(vercel.jsonの全文)。

なお、どのコンテンツにどんなヘッダーを付与するかは「GatsbyJS公式推奨のキャッシュ設定を理解する」という記事で解説しています。

Vercelはcache-controlにstale-while-revalidateを設定できる

Vercelはcache-controlのstale-while-revalidateをサポートしています。

stale-while-revalidateとは、「コンテンツをキャッシュしているならキャッシュからロードする。一方、サーバーにもリクエストを送り、キャッシュした内容と相違があるなら、サーバーからのレスポンスを表示する」という仕組みです。

stale-while-revalidateの特徴は、最初にキャッシュからコンテンツをロードするためコンテンツを表示するためにサーバーからレスポンスを待つ必要がなくなる一方、キャッシュしたコンテンツが古くなっていてもサーバーに問い合わせをしているので、後から最新のコンテンツが表示されるというものです。

キャッシュヘッダーにstale-while-revalidateの設定を書くだけでこの便利な仕組みを使えます(Vercel公式ドキュメント)。

Cache-Control: s-maxage=1, stale-while-revalidate

なお、ReactのAPIからデータを取得するためのHooks、useSWRも、stale-while-revalidateからインスピレーションを受けたものです(useSWRについては最近紹介・解説記事書いています)。

まとめ

Vercelはだんだん日本で知られ始めてきたものの、日本語の情報はまだ少ないです。

しかし海外では着実にVercel社の注目度は上がっています。その証拠に、最近$21M、つまり2,100万ドル(約22億円)を調達し、投資家から「将来のフロントエンドエンジニアのAWSになる」と言われるなどにわかに注目を集めています。

個人開発をする人にとって、サーバーサイドの言語ならHeroku、フロントエンドならVercelにデプロイするのが最近の流れですね。

将来Vercelがフロントエンド界隈を席巻することは想像に難くないですね。

最後に、Vercel社CEOであるGuillermo Rauch氏がVercelを簡潔に紹介したTweetを掲載して筆を置くことにします。

vercel.jsonの全文

GatsbyJSが公式で推奨している設定をVercelで適用するためのvercel.jsonは以下の通りです。

Vercelがサポートしているstale-while-revalidateを利用して、さらにコンテンツの表示速度を早めるようにしています。

vercel.json
{
  "headers": [
    {
      "source": "(.*).html",
      "headers":[
        {
          "key" : "Cache-Control",
          "value" : "s-maxage=1, stale-while-revalidate"
        }
      ]
    },
    {
      "source": "/page-data/app-data.json",
      "headers":[
        {
          "key" : "Cache-Control",
          "value" : "s-maxage=1, stale-while-revalidate"
        }
      ]
    },
    {
      "source": "/page-data/(.*)",
      "headers":[
        {
          "key" : "Cache-Control",
          "value" : "s-maxage=1, stale-while-revalidate"
        }
      ]
    },
    {
      "source": "/static/(.*)",
      "headers":[
        {
          "key" : "Cache-Control",
          "value" : "public, max-age=31536000, immutable"
        }
      ]
    },
    {
      "source": "/sw.js",
      "headers" : [
        {
          "key" : "Cache-Control",
          "value" : "public, max-age=0, must-revalidate"
        }
      ]
    },
    {
      "source": "(.*).js",
      "headers":[
        {
          "key" : "Cache-Control",
          "value" : "public, max-age=31536000, immutable"
        }
      ]
    },
    {
      "source": "(.*).css",
      "headers":[
        {
          "key" : "Cache-Control",
          "value" : "public, max-age=31536000, immutable"
        }
      ]
    },
    {
      "source": "/icons/(.*)",
      "headers":[
        {
          "key" : "Cache-Control",
          "value" : "public, max-age=31536000, immutable"
        }
      ]
    },
    {
      "source": "/media/(.*)",
      "headers":[
        {
          "key" : "Cache-Control",
          "value" : "public, max-age=31536000, immutable"
        }
      ]
    }
  ]
}

Happy Coding 🎉

この記事が「役に立つ」「面白い」と思ったら、下記のボタンから Twitter でのシェアやはてなブックマークをお願いします!

  • Share on Hatena
  • Share on Twitter
  • Share on Line
  • Copy to clipboard