Application CacheからService Workerへ最速移行する! [10分で移行できます]

2018年11月2日金曜日

ApplicationCache HTML5 移行

t f B! P L

Application CacheからService Workerへ最速移行する! [10分で移行できます]

enter image description here

廃止予定の、Application Cacheを、Service Worker最速移行させる方法です。

2016/10/28 に、HTML5.1が勧告され、正式にApplication Cacheが仕様から削除されました。

2018/10現在の状況は、非推奨として、まだ ほとんどのブラウザで使用可能な状態です。
しかし、将来的には廃止される事が決まって、いつ使えなくなってもおかしくない状態です。
今のうちに移行しましょう!!

Application Cacheの代わりとして、より高機能な Service Workerの使用が推奨されています。
今回は、Application Cacheで作ったマニュフェストファイルをそのまま使って、最速でService Workerに対応する方法について、紹介します。

マニュフェストファイルを動的に作る外部のプログラムを別で作っていた場合、この方法であれば、外部プログラムの修正が不要で、移行がスムーズに進むと思います。

オフライン対応のイメージ

Service Workerでのオフライン対応イメージです。

下のイメージ通り、オンライン時に、Service Workerが必要なリソースをダウンロードし、Cacheストレージに溜めておきます。

オンライン時

オフラインになった時は、Cacheストレージに溜めてあるリソースをレスポンスとして返します。
これにより、オフラインても動作出来るWebアプリになります。

オフライン時

Application Cache → Service Workerに移行

マニュフェスト(manifest)の準備

Application Cacheで作った、マニュフェストファイルを、そのまま使います。
以下のように、必要なリソースのURLを、CACHE:セクションに書いておきます。

[site.appcache]

CACHE MANIFEST

CACHE:
index.html
css/common.css
scripts/jquery-1.10.2.min.js
css/images/back.png

NETWORK:

Service Workerの作成

Application Cacheでは、マニュフェストさへ用意しておけば、勝手にリソースをキャッシュしてくれる仕様ですた。
Service Workerの場合は、JavaScriptでキャッシュする処理を自前で書く必要があります。

以下が、キャッシュをサンプルコードとなるので、コピペで使ってください。

[service-worker.js]

const STATIC_CACHE_KEY = 'cache-key';
const MANIFEST_URL = "site.appcache";

var ORIGIN = location.protocol + '//' + 
            location.hostname + 
            (location.port ? ':' + location.port : '');

/*************************************************************************
 * インストール時の処理
*************************************************************************/
self.addEventListener('install', event => {

  //ワーカーをアクティブ状態に切り替える
  event.waitUntil(self.skipWaiting());

  //キャッシュするリソースをダウンロードする
  event.waitUntil(
    //マニュフェストファイルから、キャッシュ対象のリソースURLを取得
    load_manifest()
      //キャッシュ対象のリソースをダウンロードし、キャッシュストレージに保存する
      .then((list) => download_files(list))
  );
});

/*************************************************************************
 * マニュフェストファイルの読み込み
 * @description マニュフェストの :CACHEセクションに書かれているリソースURLを抽出
*************************************************************************/
function load_manifest() {

  return fetch(ORIGIN + "/" + MANIFEST_URL)
  .then(response => response.text())
  //マニュフェストから、キャッシュするURLのリストを取得する
  .then(content => {

    //マニュフェストファイルの中身を解析して、
    //キャッシュセクションに書かれているファイルリストを取り出す
    content = content.replace(
      new RegExp(
        "(NETWORK|FALLBACK):" +
        "((?!(NETWORK|FALLBACK|CACHE):)[\\w\\W]*)",
        "gi"
        ),
        ""
    );
    content = content.replace(
      new RegExp( "#[^\\r\\n]*(\\r\\n?|\\n)", "g" ),
        ""
    );
    content = content.replace(
      new RegExp( "CACHE MANIFEST\\s*|\\s*$", "g" ),
        ""
    );
    content = content.replace(
      new RegExp( "[\\r\\n]+", "g" ),
        "#"
    );

    //キャッシュ対象のURLを、リストで返す
    var fileList = content.split("#");
    //マニュフェスト変更チェックの為に、マニュフェストファイルもキャッシュしておく
    fileList.push(MANIFEST_URL);
     
    return fileList.map(function(url) {
      return ORIGIN + "/" + (url == "/" ? "": url);
    }).slice(1, fileList.length);
  });
}

/*************************************************************************
 * キャッシュ対象のリソースをダウンロードして、キャッシュストレージに保存する
 * @param {Array} cache_urls キャッシュするリソースのURLリスト
*************************************************************************/
function download_files(cache_urls) {

  return caches.open(STATIC_CACHE_KEY).then((cache) => {
    return Promise.all(
      cache_urls.map(url => {
        return fetch(new Request(url, { cache: 'no-cache', mode: 'no-cors' }))
         .then((response) => {
           return cache.put(url, response);
         });
      })
    );
  });
}

/*************************************************************************
 * fetchイベント発生時の処理 
 * @description ブラウザからのリクエストが、キャッシュ済みのリソースであれば、
 *              キャッシュストレージの内容でレスポンスを返します。
*************************************************************************/
self.addEventListener('fetch', function(event) {

  //マニュフェストファイルに対するリクエストの場合、変更チェックを行い、
  //マニュフェストに変更がある場合、リソースの再キャッシュを行う
  if (event.request.url == ORIGIN + "/" + MANIFEST_URL) {
    check_manifest();
  }
  
  //キャッシュ済みのリソースであれば、キャッシュストレージの内容でレスポンスを返します。
  event.respondWith(
    caches.match(event.request).then(response => {
      return response || fetch(event.request);
    })
  );
});

/*************************************************************************
 * マニュフェストファイルの変更チェック
 * @description マニュフェストファイルに差異があれば、リソースを再ダウンロード&再キャッシュする
*************************************************************************/
function check_manifest() {

  //キャッシュされているマニュフェストを格納する変数
  var cacheManifest = "";

  //キャッシュからマニュフェストファイルを取得する
  caches.match(new Request(ORIGIN + "/" + MANIFEST_URL))
    .then((response) => {
      if (response == null || typeof response === "undefined") {
        return "";
      }
      return response.text();
    })
    //最新版のマニュフェストファイルを Webサーバから取得する
    .then(content => {
      cacheManifest = content;
      return fetch(ORIGIN + "/" + MANIFEST_URL);
    })
    .then(response => response.text())
    //マニュフェストファイルに差異があれば、リソースを再キャッシュ
    .then(content => {
      if (content != cacheManifest) {
        console.log("マニュフェストファイルに変更があった為、リソースを再キャッシュします");
        //現在のキャッシュをクリア
        return caches.delete(STATIC_CACHE_KEY);
      } else {
        //変更がない場合h、処理を中断する為に、例外をスローする
        throw "NoChanged";
      }
    })
    .then(() => {
      return load_manifest()
        .then((list) => download_files(list));
    }).catch(err => {
      if (err === "NoChanged") return;
      throw err;
    });
}

HTMLファイルの修正

メインとなる HTMLファイルを修正していきます。

  • manifest 属性の削除

<html>タグの manifest属性は不要になるので、消します。

<html lang="ja" manifest="site.appcache">

↓↓↓↓↓↓

<html lang="ja">
  • Service Workerのインストール処理を追加

以下のJavascriptを、画面Load時に走るように追加します。

if (navigator.serviceWorker) {

  //(1)Service Workerのインストール
  navigator.serviceWorker.register('./service-worker.js', { scope: '.' });

  //(2)マニュフェストに変更があれば、Service Worker側でリソースの再キャッシュを行う
  if (navigator.onLine) {
    fetch("/site.appcache");
  }
}

動作確認

ちゃんとキャッシュされているか確認する

  1. 完成したWebページを立ち上げて、Chromeの開発者ツールを起動します。
  2. Cache -> Cache Storage -> cache-key を選択します。
  3. 右側の一覧に、マニュフェストファイルで書いたリソースがあれば、キャッシュ成功です。

キャッシュされている様子

オフラインでも動作するか確認する

次に、オフラインでも動作するか確認しましょう。
Chromeの開発者ツールで Offlineにチェックすれば、簡単にオフライン状態にする事ができます。

Chromeの開発者ツールで  Offlineにチェック

これで問題なく表示されれば、移行成功です。

最後に

いかがですか?
今回の方法であれば、すぐに移行が出来たと思います。
問題等あれば、極力直したいと思いますので、ご連絡をお願いします。

もうこれ以上、キャッシュAPIの仕様が変わらない事を祈って、まとめとさせてもらいます。

スポンサーリンク

QooQ