シンクロ・フードでフロントエンドの開発を担当している四之宮です。
今回は、「cssとjavascriptのキャッシュクリアの自動化に対応していないフレームワークでのキャッシュクリア自動化」についてについてお話したいと思います。
ここでいうキャッシュクリアとは、ハッシュ値をファイルに付与することで、強制的にブラウザキャッシュを無効化するキャッシュクリアのことです。
お話する前に、なぜこのような記事を書こうと思ったのかを弊社のシステム構成を交え、ご説明したいと思います。
システム構成
弊社のシステム構成に関しては以前にご紹介した通り、新サービスの開発ではRuby on Rails、既存サービスの開発はSeasar2となっています。
もちろん既存サービスに関しても、少しずつRuby on Railsへの載せ替えを行っていますが、まだSeasar2で開発しているサービスも多々ある状態です。
キャッシュクリアの対応について
Ruby on Railsで開発していればcssとjavascriptのキャッシュクリアは自動で行ってくれます。しかし、Seasar2で開発したものに関しては、キャッシュクリアを自動では行ってくれません。 そのため、Seasar2で開発しているサービスに関しては、以前までは手動で対応していました。よくあるファイル名の後ろにキャッシュクリア用のパラメータを付与するという手法です。
しかし、この対応を忘れ、キャッシュが効いてしまい変更後のcssが反映されないことがありました。
このように、「本当は新しいフレームワークに載せ替えたいけどできていない。そのため手動でキャッシュクリアの対応をしている。」という方もまだいるのではないでしょうか?
本記事はそんな方向けの内容となっています。
キャッシュクリア自動化の方法
弊社ではgulpによるscssのコンパイルを行っているため、gulp-cachebustというnpmを使用しました。
下記コマンドでインストールを行います。
npm install --save-dev gulp-cachebust
そして、テスト~本番用のTaskにgulp-cachebustを組み込む形となります。
開発用に組み込まなかったのは、ファイル数が多くなってくると時間がかかるためです。
gulp-cachebustについて
gulp-cachebustには大きく分けてresourcesとreferencesという2つのメソッドがあります。
resourcesは、対象ファイルにハッシュ値を付与する処理を、referencesは対象ファイルを参照しているファイル(cssやjsを読み込んでいるhtmlが記述されたファイル)の中身を変える処理を行います。
この2つのメソッドを使用することで、簡単にキャッシュクリアをしてくれます。
使用例
実際のコードを元に説明したいと思います。
var CacheBuster = require('gulp-cachebust'); var cachebust = new CacheBuster(); gulp.task('cachebustResources-css', ['事前Taskがあれば指定(scssのコンパイルTaskなど)'], function () { return gulp.src('src/main/webapp/**/*.css') .pipe(cachebust.resources()) .pipe(gulp.dest('src/main/webapp/')); }); gulp.task('cachebustReferences-jsp', ['cachebustResources-css'], function () { return gulp.src('src/main/webapp/WEB-INF/view/**/*.jsp') .pipe(cachebust.references()) .pipe(gulp.dest('src/main/webapp/WEB-INF/view/')); });
cachebustResources-css Task
まず、srcにcssが格納されたディレクトリをします。
そこにpipeでつなげてcachebust.references()します。
これだけでファイルの中身から作成された文字列が付与されたファイルが生成されます。
test.cssとtest.de4e3ce6.cssのような状態です。
このファイルの中身は全く同じ内容ですので、二重に出来上がってしまいます。
これが嫌な場合は、destで指定するディレクトリを別にするなどして元ファイルを削除する必要があります。
cachebustReferences-jsp Task
cachebust.resources()の後で実行する必要があります。
上記の例では、cssに対するresources実行後に指定しています。
こちらでは、cssを読み込んでいるファイルをsrcに指定し、pipeでつなげてcachebust.references()します。
これで、例えばtest.cssを読み込んでいる箇所が、test.de4e3ce6.cssと書き換わった状態になります。
使用例ではcssのみですが、JavaScriptファイルについても同様の処理を行うことでキャッシュクリアできます。
注意点
srcに指定したディレクトリ直下(上記の場合src/main/webapp/)に.cssファイルがないようにする必要があります。
これは、直下に存在するcssファイルの名前と同名のcssファイルが別ディレクトリにあると問題が発生するためです。
具体的には、jsp内のcss読み込みの書き換えの際に追加されるハッシュ値が、指定したディレクトリ直下にあるものになってしまうというものです。
その結果、存在しないcssの読み込みをすることになり、cssが効かない状態になってしまいます。
例えば、以下のような状態の場合にこの問題が発生します。
ディレクトリ構成
webapp/ ├ stylesheet/ │ └ test.css └ test.css
キャッシュクリア前
- html1
<link href="/test.css" rel="stylesheet" type="text/css">
- html2
<link href="/stylesheet/test.css" rel="stylesheet" type="text/css">
キャッシュクリア後
- html1
<link href="/test.de4e3ce6.css" rel="stylesheet" type="text/css">
- html2
<!-- 本当ならこちらになって欲しい --> <link href="/stylesheet/test.se5teg42.css" rel="stylesheet" type="text/css"> <!-- でもこちらになってしまう。html1で読み込んでいるtest.cssのハッシュ値が付与。 --> <link href="/stylesheet/test.de4e3ce6.css" rel="stylesheet" type="text/css">
最後に
以上が、cssとjavascriptのキャッシュクリアの自動化に対応していないフレームワークでのキャッシュクリア自動化になります。
これだけの実装で、cssとjsのキャッシュクリア漏れによるバグがなくなったので、とてもよかったと思います。
この記事によって、キャッシュクリア機能がないフレームワークを使用していて同じ悩みを持っていた方のお役に立てればと思います。
尚、シンクロ・フードではエンジニアを大募集しています!
最近では、下記の記事ようにフロントエンド側にも力を入れており、ReactやAngular2によるサービス開発もスタートしています。
IonicとAngularJSを使ってSPAでサービスを作った話
少しでもご興味があれば、気軽にお話しする場を設けますので、以下よりご連絡ください!