静的サイトで JS/CSS のキャッシュを防ぎつつレポジトリをキレイに保つ
「ABOUT」のページをリニューアルしました。
1つ前のデザインのままだったものを、現在のデザインに沿って作りなおして、ついでに文章やレイアウトなども整えました。
公開したものの問題発生
意気揚々と公開してみたのですが、1つ問題が見つかりました。
ページを公開したあと、本番環境を表示するとデザインが崩れていました。そのあと、ページをリロードすると期待通りの結果になりました。
原因は CSS がキャッシュされていた ことでした。
たとえページが更新されていたとしても、JavaScript や CSS は古いキャッシュを使い続けてしまうことがあります。
で、この問題に対処しようとしたのですが、「静的生成」「生成結果を GitHub で管理」「キャッシュ問題への対策」の 3 つのいいとこ取りをしようとすると、意外に複雑でした。
その話をいまからします。
キャッシュ問題の一般的な解決策
よく見る解決索は、JS や CSS の URL の最後に、URL パラメーターとしてタイムスタンプを入れておく方法です。
このようにすると、次のような効果が期待できます。
- JavaScript や CSS が更新されたとき:
- タイムスタンプが変更されていれば、必ずサーバーに取りに行く。
- JavaScript や CSS が更新されないとき:
- タイムスタンプが同じなので、キャッシュを使い続ける。
このサイトでも、同じ方法を使うことにしました。ただ、Jekyll で静的にサイト生成しているので、サーバー側で動的にタイムスタンプを埋め込むことはできません。
となれば、タイムスタンプを埋め込んだ状態で Jekyll で HTML を生成すれば万事解決しそうです。
しかし、もう一点、悩みどころがあります。
GitHub 上に生成結果の HTML をコミットしている
俺の最強ブログ システムが火を噴くぜ でも書きましたが、このサイトでは Jekyll でビルドした生成結果を GitHub 上に html ブランチとしてコミットしています。
その理由は次の通りです。
- 生成結果の HTML についても差分を管理したい。
- 何か修正をしたときに変な差分が発生していないかを
git diff
で確認できる。 - 任意の時点のサイトの生成結果を (再ビルドを行うことなく) 知ることができる。
- 何か修正をしたときに変な差分が発生していないかを
- サーバー側では html ブランチに追従するだけでデプロイが完了する。
- サーバー側にビルド環境を整えなくてよい。
- 生成処理はけっこう重いので、(格安レンタルサーバーでは) 時間がかかるプロセスが殺される可能性がある。
さて、前述の方法で「キャッシュ問題」に対処するには、JavaScript や CSS を更新するたびに、HTML を書き換えることになります。
たとえば、「JavaScript の更新」をしたとすると、そのスクリプトを利用する「すべての HTML を更新」することになります。このサイトに限っていえば、数百ある過去記事のすべての HTML が一緒に更新されます。
論理的には「JavaScript を 1 回書き換えた」だけなのに、レポジトリ上で数百の HTML ファイルが一緒にコミットされます。HTML の更新履歴に「JavaScript を更新」といった記述が並ぶことになります。
これは美しくありません。
そこでアクロバティックに解決
最初は SSI を使おうかとも思ったのですが、「Jekyll の開発サーバー上での表示が困難」「静的生成という大原則が崩れる」ことを理由にパスしました。
いろいろ悩んだ結果、デプロイ時の処理を次のように変更することを思いつきました。
- html ブランチを
git pull
する (※いままではこの処理のみだった)。 - 全部の HTML について、JavaScript・CSS の URL に URL パラメータを付与する。
この付与処理を実現するのが、次のスクリプトです。
だいぶアクロバティックですが、静的生成の大原則を守りつつ、生成結果のレポジトリ上の diff が大きくなりすぎないように工夫してみました。
しばらくはこれでやってみようと思います。