GatsbyJS公式推奨のキャッシュ設定を理解する
VercelでGatsbyJS用のキャッシュの設定をする
**GatsbyJSとは、React.js製の静的サイトジェネレータです。SSRをすることでビルド時に最適化された静的ファイルを生成するため、サイトの表示速度が爆速になります。**ブログで使われているケースが多いです。
GatsbyJSについては「GatsbyJSで実現する、高速&実用的なサイト構築」という本が詳しいです。GatsbyJSの構成やブログの作り方などが解説されています。
**この記事ではGatsbyJSで作成したのサイトに適切なキャッシュの設定方法を紹介します。**まずGatsbyJSで推奨されているキャッシュの種類は2種類あることを紹介し、コンテンツごとに最適なキャッシュ方法を紹介します。
関連記事
GatsbyJS公式が推奨するキャッシュの設定を読む
GatsbyJS公式サイトはキャッシュの推奨設定を公開しています。これを読むとGatsbyJSにおけるキャッシュの設定はファイルに応じて2種類あることがわかります。
1. cache-control: public, max-age=0, must-revalidate;
2. cache-control: public, max-age=31536000, immutable;
1のキャッシュヘッダーは、頻繁に更新があるコンテンツに対して付与します。max-age=0
なのでキャッシュはせず、さらにmust-revalidate
で必ずサーバー側でキャッシュの検証をします。なお、max-age=0, must-revalidate
はno-cache
と書き換えることもできます。
2は、max-age=31536000
とあるので、下記の計算式から1年間キャッシュを保存することがわかります。
GatsbyJSはビルド時にjsやCSSのファイル名にhashを付与するので、ビルドごとに一意なファイルを生成します。
例えばapp.js
というファイルはapp-[content-hash].js
というファイル名に変換されます。このため、以前ビルドしたコンテンツをブラウザが誤って読み込むことはなく、キャッシュを破棄させるキャッシュバスティングせずともコンテンツを常に最新に保てます。
以下ではなぜそのキャッシュを適用するのか、GatsbyJSで生成したコンテンツの内容を読みながらキャッシュの種類ごとに詳しく見ていきます。
「cache-control: public, max-age=0, must-revalidate」を適用するファイル一覧
キャッシュヘッダーにcache-control: public, max-age=0, must-revalidate;
を適用するものは、HTML、app-data.json、/page-data/配下のJSONです。
実際にファイルの中身を見れば、なぜキャッシュしないことが推奨されているか理解ができます。まず、HTMLは頻繁に更新されるので、最新版が必要であることは理解できると思います。
/page-data/のpage-data.jsonを読む
トップページで使うJSONファイル、page-data.json
を見てみましょう。
{
"componentChunkName": "component---src-templates-index-template-js",
"path": "/",
"result": {
"data": {
"allMarkdownRemark": {
"edges": [
{
"node": {
"fields": {
"slug": "/posts/gatsbyjs-cache",
"categorySlug": "/category/gatsbyjs/"
},
"frontmatter": {
"title": "GatsbyJS公式推奨のキャッシュ設定を理解する",
"date": "2020/07/05",
"category": "Vercel",
"description": "GatsbyJSとは、React.js製の静的サイトジェネレータです..."
}
}
},
{
"node": {
"fields": {
"slug": "/posts/nextjs-slack",
"categorySlug": "/category/next-js/"
},
"frontmatter": {
"title": "Next.jsからSlackに通知を送る",
"date": "2020/07/04",
"category": "Next.js",
"description": "この記事ではNext.jsからSlackに通知を送る方法を紹介します..."
}
}
}
// ...
]
}
}
}
}
ハイライトを当てている箇所は、本記事の情報です。
**/page-data/index/page-data.json
はトップページで表示している記事の一覧です。**確かにこのファイルをキャッシュしてしまうと、新規記事を追加しても以前サイトにアクセスした人は最新記事へのリンクが表示されなくなってしまいますね。
posts
やpages
といった個別の記事についても上記と同様にmarkdownRemark
(本文情報)とfrontmatter
(メタ情報)がJSONに格納されています。このため、常に最新の記事を配信するためにはpage-data.json
をキャッシュしてはいけないのです。
/page-data/のapp-data.jsonを読む
次にapp-data.json
を見てみましょう。
{"webpackCompilationHash":"ef93e02a0d2ee7cef376"}
webpackCompilationHash
は、ブラウザが読み込んでいるサイトのバージョンと実際にデプロイされた最新のバージョンが一致していることを確認するために使われます。
ユーザーが表示するサイトを常に最新に保つためには、これもキャッシュしてはいけない内容ですね。
「cache-control: public, max-age=31536000, immutable」を適用するファイルタイプ一覧
キャッシュヘッダーにcache-control: public, max-age=31536000, immutable;
を適用するものは、JavaScript、CSS、/static/
配下の静的ファイルです。
webpack.stats.jsonを読んでJS、CSSのファイル名を確認する
JavaScriptとCSSは、ビルドのたびに一意のハッシュが付与されると先ほど書きました。webpack.stats.json
を読むとビルドされたJS、CSSのファイル名を確認できます。
{
"namedChunkGroups": {
"app": {
"assets": [
"webpack-runtime-43c21f6c6453f3e9506e.js",
"webpack-runtime-43c21f6c6453f3e9506e.js.map",
"styles.595bac0ca0e2ea7b429b.css",
"styles-0dd9b16d06f2e4f550cc.js",
"styles-0dd9b16d06f2e4f550cc.js.map",
"framework-84c9287a5714d2d8ce36.js",
"framework-84c9287a5714d2d8ce36.js.map",
"532a2f07-f5ad30ee5092265c5f96.js",
"532a2f07-f5ad30ee5092265c5f96.js.map",
"app-c2875e4f24d448537cff.js",
"app-c2875e4f24d448537cff.js.map"
],
},
// ...
}
}
filename-[content-hash].js
の形式になっていますね。ファイル内容に変更がある場合にのみ新規のハッシュが付与されます。その場合、コンテンツはサーバーから読み込まれます。
**反対に、ファイルに変更がない場合はハッシュは変更されません。この時、ブラウザはキャッシュからコンテンツをロードします。**これは画像(png, jpg, webp)やフォント(woff、ttf)などの静的ファイルも同じです。
このため、JS、CSS、静的ファイルのキャッシュ期間は1年間が最適なのです。
/sw.jsのサービスワーカーだけはJSの例外
JavaScriptの中でもサービスワーカー/sw.js
だけはcache-control: public, max-age=0, must-revalidate
を設定します。これは新しいバージョンのサイトが利用可能かどうかをリクエストのたびに確認するためです。
/sw.js
はgatsby-plugin-offline
というプラグインを利用している場合にのみ生成されます。
まとめ
GatsbyJS公式が推奨しているキャッシュは、ざっくりいうと「キャッシュする」「キャッシュしない」の二択ですね。
また、キャッシュはLighthouseやCore Web Vitalsのスコアを上げるために有効です。つまりSEO対策にもなるんです。
最適なキャッシュを設定して、GatsbyJS製のサイトの表示速度をさらに爆速にしましょう。
Happy Coding 🎉