AngularJS で HTML5 の Cache manifest ファイルを利用して静的リソースを Application Cache にキャッシュする、というのを試してみたので、メモがてら手順をここに残します。
ちなみに Application Cache については、このサイトが分かりやすかったです。
⇒アプリケーション キャッシュを初めて使う
前提
- 開発環境 は Mac OS X (Mavericks)とします。
- Yeoman と Yeoman の generator-angular を使います。
-
もしまだ入ってなければ、次のようにセットアップしてください。
# npm install -g yo grunt-cli bower # npm install -g generator-angular
-
手順
① AngularJSのジェネレータを実行
-
コマンドラインにて、
$ yo anguler --minsafe
-
下記のように聞かれるのですが、何でもいいので適当に選択します。
-
雛型の生成が終わったら、とりあえず動作確認します。コマンドラインにて、
$ grunt serve
-
下記のように表示されたらOK。
② Application Cache の導入
-
index.html
と同じ階層に(どこでもいいのですが)、マニフェストファイルを新規に作成します。- 今回は、AngularJSの本体ファイルをキャッシュしてみます。
- 【注意】本番稼働時にはリリースビルド後のファイル名を記載してください。
sample.appcacheCACHE MANIFEST # TODO: ここにコメントやバージョン番号を書く CACHE: bower_components/angular/angular.js NETWORK: * FALLBACK:
※
CACHE:
エリアは正規表現を使えないので、対象ファイルを全て記載する必要があります。
※NETWORK:
エリアは逆にキャッシュしないファイルを指定します。全てのHTTPリクエストはCACHE
かNETWORK
に定義されている必要があるので、*
を指定しておくのがセオリーらしいです。 -
.htaccess
にて、マニフェストファイルのHTTPレスポンスにコンテンツタイプtext/cache-manifest
が設定されていることを確認します。.htaccess(念のため確認)AddType text/cache-manifest appcache manifest
-
index.html
のhtml
タグ部分で、先ほど作成したマニフェストファイルを指定します。index.html<!--[if gt IE 8]><!--> <html class="no-js" manifest="sample.appcache"> <!--<![endif]-->
※マニフェストファイルを指定したファイル(今回でいうとこの
index.html
)もキャッシュ対象になる、という仕様のようです。 -
iOS の Safari?では、ブラウザがマニフェストファイルの更新を検知しない仕様らしいので、
head
タグに次のように JavaScript を仕込んで更新を検知するようにします。- でないと、永遠に端末側のキャッシュが更新されないことになります。
- でも、私の端末(iOS 7.1.1)の Safari では、スクリプトを組まなくても、起動毎にマニフェストファイルの更新を確認してました。
index.html<script> window.addEventListener('load', function(e) { window.applicationCache.addEventListener('updateready', function(e) { if (window.applicationCache.status == window.applicationCache.UPDATEREADY) { window.applicationCache.swapCache(); window.location.reload(); } }, false); if (navigator.onLine) { window.applicationCache.update(); } window.addEventListener("online", function() { window.applicationCache.update(); }, false); }, false); </script>
-
必須ではないですが、Gruntのタスクも修正して、マニフェストファイルを修正したらブラウザをリロードするようにします。
Gruntfile.jsgrunt.initConfig({ 〜 watch: { js: { files: ['<%= yeoman.app %>/scripts/{,*/}*.js'], tasks: ['newer:jshint:all'], options: { livereload: true } }, jsTest: { files: ['test/spec/{,*/}*.js'], tasks: ['newer:jshint:test', 'karma'] }, styles: { files: ['<%= yeoman.app %>/styles/{,*/}*.css'], tasks: ['newer:copy:styles', 'autoprefixer'] }, gruntfile: { files: ['Gruntfile.js'] }, livereload: { options: { livereload: '<%= connect.options.livereload %>' }, files: [ '<%= yeoman.app %>/{,*/}*.html', '.tmp/styles/{,*/}*.css', '<%= yeoman.app %>/images/{,*/}*.{png,jpg,jpeg,gif,webp,svg}', + "<%= yeoman.app %>/sample.appcache" ] } },
-
また、リリース向けにビルドした際、マニフェストファイルもリリース用ディレクトリにコピーされるようにします。
Gruntfile.jsgrunt.initConfig({ 〜 copy: { dist: { files: [{ expand: true, dot: true, cwd: '<%= yeoman.app %>', dest: '<%= yeoman.dist %>', src: [ '*.{ico,png,txt}', '.htaccess', '*.html', 'views/{,*/}*.html', 'bower_components/**/*', 'images/{,*/}*.{webp}', 'fonts/*', + 'sample.appcache' ] }, { expand: true, cwd: '.tmp/images', dest: '<%= yeoman.dist %>/images', src: ['generated/*'] }] }, styles: { expand: true, cwd: '<%= yeoman.app %>/styles', dest: '.tmp/styles/', src: '{,*/}*.css' } },
③ 動作確認
-
$grunt serve
してローカルのWEBサーバを立ち上げ、Chrome の Developer Tools で各ファイルの HTTP リクエストの状態を確認します。参考までに、下記は Application Cache を導入する前の状態です。 -
下記は導入後です。マニフェストファイルで指定したファイルが、次のようにキャッシュから表示されていることが分かります。
-
また Chrome では、次のURLをブラウザに入力することで、Application Cache の内容を確認することが出来ます。
chrome://appcache-internals/
ほか
- 私のAndorid端末(GALAXY S II WiMAX:ISW11SC)の標準ブラウザ(Android 4.0.4)では、
window.applicationCache.
系やwindow.location.reload()
のスクリプトが動作しませんでした.. ブラウザ依存があるのかなあ。 - 今回のソースはGitHubに置いておきます。