Slide 1

Slide 1 text

Service WorkerのCacheで ⾊々と問題が起きた話 Akihiro Tanaka(@biga816)

Slide 2

Slide 2 text

とりあえずService Workerで キャッシュしまくってみた

Slide 3

Slide 3 text

前提 ɾ地下アイドル向けのDAppsをPWAしてみたときの話。 ɾionic3を利⽤。 ɾSW-Toolboxを利⽤(今はDeprecatedとなっている)。

Slide 4

Slide 4 text

問題1 キャッシュの上限に到達!

Slide 5

Slide 5 text

問題1 〜キャッシュの上限に到達〜 ɾ画像をキャッシュするようにしたら下記エラーが発⽣。 ɾファイルをキャッシュしすぎたためキャッシュ可能容量の上限 に達していた。 self.toolbox.router.get(/<ファイルサーバーのURL>/, (request) => { return new Promise((resolve, reject) => { caches.match(request).then((response) => { if (response) { // from cache resolve(response); } // from network return fetch(request) .then((response) => resolve(response)) .catch((error) => reject(error)); }); }); });

Slide 6

Slide 6 text

解決策 ɾキャッシュ数の上限と期限を設定した。 self.toolbox.options.cache = { name: 'ionic-cache', maxAgeSeconds: 60 * 60 * 24, maxEntries: 50 };

Slide 7

Slide 7 text

問題2 開発環境でのみキャッシュの上限に到達!

Slide 8

Slide 8 text

問題2 〜開発環境でのみキャッシュの上限に到達〜 ɾ下記のエラーが気がついたらまた発⽣するようになった。 ɾ開発環境ではAoTコンパイルが実⾏されていないため、キャッ シュ対象となっていたアプリ⾃体のjsがキャッシュ容量を圧迫 していた。 self.toolbox.precache( [ './build/main.js', './build/vendor.js', './build/main.css', './build/polyfills.js', 'index.html', 'manifest.json' ] ); AoTコンパイル なしだとデカい

Slide 9

Slide 9 text

問題2 〜開発環境でのみキャッシュの上限に到達〜 ɾキャシュの上限はブラウザによって異なる。 <参考> https://developers.google.com/web/fundamentals/instant-and-offline/web-storage/offline-for-pwa

Slide 10

Slide 10 text

解決策 ɾ定期的にキャッシュを削除した。 ɾローカルで開発する際にはServiceWorkerをオフにしても良 かったかも。

Slide 11

Slide 11 text

問題3 キャッシュから動画が再⽣されない!

Slide 12

Slide 12 text

問題3 〜キャッシュから動画が再⽣されない〜 ɾSafariでのみ問題が発⽣。 ɾサーバーからデータを取得する初回は動画が再⽣されるが、2 回⽬以降キャッシュから取得する際には動画が再⽣されない。 Client App Cache Server

Slide 13

Slide 13 text

問題3 〜キャッシュから動画が再⽣されない〜 サーバーからの場合のHTTPヘッダ キャッシュの場合のHTTPヘッダ ɾHTTP Rangeリクエストに対し、Safariではレスポンスコード 200を受け取るとそれ以降そのファイルを読み込まない仕様に なっていた

Slide 14

Slide 14 text

解決策 ɾRangeリクエストが来た際にステータスコード206で返却する ようにService Workerでレスポンスを上書きする。

Slide 15

Slide 15 text

self.toolbox.router.get(/<ファイルサーバーのURL>/, (request) => { return new Promise((resolve, reject) => { if (request.headers.get('range')) { // Range request let rangeHeader = request.headers.get('range'); let rangeMatch = rangeHeader.match(/^bytes¥=(¥d+)¥-(¥d+)?/) let pos = Number(rangeMatch[1]); let pos2 = rangeMatch[2]; if (pos2) { pos2 = Number(pos2); } caches.open('ionic-cache') .then((cache) => { return cache.match(request.url); }).then((res) => { if (!res) { return fetch(request.url).then(res => res.arrayBuffer()); } else { return res.arrayBuffer(); } }).then((ab) => { let responseHeaders = { status: 206, statusText: 'Partial Content', headers: [ ['Content-Type', 'video/mp4'], ['Content-Range', 'bytes ' + pos + '-' + (pos2 || (ab.byteLength - 1)) + '/' + ab.byteLength]] }; : Qiita: Service Worker(PWA)でRangeリクエストに対応する https://qiita.com/biga816/items/dcc69a265235f1c3f7e0 抜粋

Slide 16

Slide 16 text

まとめ ɾService Workerのキャッシュは便利だけど上限を意識する必要 がある。 ɾ無限に増えるコンテンツはCDNでキャッシュした⽅が良い。 ɾキャシュ対象はオフラインで最低限参照できると嬉しいファイ ルに絞るのが良い。

Slide 17

Slide 17 text

Thank you Twitter: @biga816 Qiita: biga816