更新されたJS、CSS、画像のみブラウザキャッシュを破棄して読み込ませる

 WEBサービスの保守や開発をやっていると、JavaScriptやスタイルシート、画像などの静的リソースを更新した際、しばしば「確認したけど、更新されてないよ」とか云われて、「ブラウザのキャッシュを消してからもう一度見てみてください」みたいなやり取りが発生することがある。これが、サービス内部のメンバー間のやり取りであれば(非効率ではあるものの)まだ許せるが、サービスを提供している顧客側に更新内容が反映されない事態が発生してしまうと、それは障害と同義だ。

 そんなわけで、WEBページにおける静的リソースの読み込みには開発時に注意を払う必要がある。確実な対処方法としては、静的リソースの読み込み時にリソースパスに動的パラメータを付与して、ブラウザにキャッシュされないようにすることだ。
 下記のように、フロントエンドだけで対応することもできる。

 読み込む静的リソースのファイルパスの後にGETパラメータとして更新日時等を付けてやるだけだ。これで、それらの静的リソースはブラウザに新しいリソースとして認識され、それまでキャッシュされていたリソースは破棄される。
 だが、この方法だと、複数の画像を更新した際にHTML側で対応しなければならない箇所が多岐に渡ってしまうし、実際のページを見ながらスタイルシートを調整している時などはスタイルシートを更新する都度パラメータを変更しなければならず、作業効率が非常に悪くなる。
 そこで、リソースパスに対しては常に動的パラメータを付与するようにしてみる。

PHP向け:

Ruby向け:

 こんな感じに、PHPやRubyでページのテンプレートに元から動的パラメータを仕込んでしまえば良いのだ。

 しかし、これだと毎回ページを読み込んだ際に静的リソースの読み込みが発生してしまい、WEBサービスとしてのパフォーマンスが著しく悪くなってしまうという弊害がある。理想としては、更新が発生した静的リソースのみブラウザキャッシュを破棄して読み込ませ、更新されていないリソースファイルにはブラウザキャッシュを効かせたい。

 そういう時に使えるメソッドが、PHPやRubyなどには準備されている。

PHPなら filemtime() を使おう

 PHPの filemtime() は、指定されたファイルの更新時刻を取得する関数だ。これを使って静的リソースファイルのパスに動的パラメータを付与しておけば、リソースファイルが更新されない限り動的パラメータ部分が変わらないため、一度ブラウザにキャッシュされたリソースを有効に活用できる。
 実際には、PHPでレンダリングするテンプレート等で下記のようにコーディングしておけば良い。

 注意点としては、filemtime() に指定するリソースファイルのパスは、サーバ上でのパスになるということだ。しかし、上記のような記述をテンプレート上のすべての静的リソースに行うのはテンプレートの可読性が著しく下がるので、指定されたファイルパスに動的パラメータが付与されたURIを返すような関数を作った方が良いだろう。

独自関数化:

 上記の関数を使って静的リソースファイルを読み込むテンプレートの例は下記のようになる。

Rubyなら File.mtime() を使おう

 Rubyでは Fileオブジェクト の mtime() メソッドでファイルの更新日時を取得できる。これを使って静的リソースファイルのパスに動的パラメータを付与していけば、リソースファイルが更新されない限り動的パラメータ部分が変わらないため、一度ブラウザにキャッシュされたリソースを有効に活用できるようになる。

 注意点としては、File.mtime() に指定するリソースファイルのパスは、サーバ上でのパス(RailsであればRails上の公開ディレクトリ経由のパス)になるということだ。しかし、上記のような記述をテンプレート上のすべての静的リソースに行うのはテンプレートの可読性が著しく下がるので、指定されたファイルパスに動的パラメータが付与されたURIを返すような関数を作った方が良いだろう。 

独自関数化:

 Railsアプリなら、アプリケーション全体の共通処理用ヘルパーメソッド(app/helpers/application_helper.rb)に上記の関数を定義しておけば良い。そして、Viewのテンプレートではその関数にリソースパスを渡すようにする。

おまけ: WordPressでの静的リソースの読み込みを最適化する

 WordPressではテーマへの静的リソースの読み込みは、スタイルシートなら wp_enqueue_style() 関数、スクリプトなら wp_enqueue_script() 関数を使って wp_enqueue_scripts のアクションフックに読み込み処理を追加するのがセオリーである。
 wp_enqueue_style()wp_enqueue_script() の関数では、引数で読み込むリソースのバージョン番号などを指定することができるので、そこにキャッシングを抑止するための動的パラメータを渡してあげるのが良いだろう。もちろん、バージョン管理されている外部リソースであればバージョン番号をそのまま指定するべきだが、厳密なバージョン管理を行っていない自サイトのみで使っている静的リソースであれば動的パラメータを付与しておくと効果的にキャッシングされる。

テーマのfunctions.php等に:

 一方で、画像リソースについては、各WordPressサイトやテーマによって取り扱いが異なるので、キャッシングの最適化は個別対応となってしまう。もしWordPressにビルドインされているテンプレート関数を利用して出力を行っているのであれば、 アイキャッチ画像ならば post_thumbnail_html フィルター、本文内の埋め込み画像ならば the_content フィルター、管理画面からアップロードされたメディアならば get_attached_file フィルターなどを使って画像ファイルのパスを拾ってフィルタリングしてあげることになるかと。

これで「ブラウザのキャッシュを消してから見てみてください」とお願いする必要がなくなるのではないだろうか。

Leave a Reply

Your email address will not be published.