Flask+Service Worker on Heroku で PWA チュートリアル

Flask+Service Worker on Heroku で PWA チュートリアル

概要

自分にとっては dev.to でバズった Service Worker。
その概要と機能性をなぞってみようとチュートリアル的に学んだ内容をまとめました。

掲題の通り、Flask + Service Worker を Heroku で動作させ、PWA(Progressive Web Apps) してみました。

さらなる sleep 対策として
Service Worker があればオフラインでもサービス動作させられるし、sleep し続けてもいいのでは?と思い、導入してみました。

Flask に Service Worker 導入

ソースは git にあります。

簡単に導入時のポイント

  • app.py というメインスクリプトに /sw.js へのアクセスできるようにします。
1
2
3
@app.route('/sw.js', methods=['GET'])
def sw():
return app.send_static_file('sw.js')
  • static ディレクトリ内に空の sw.js を配置

基本、上記 2 step をしてから Service Worker の各処理を実装していきます。

Install

以下の install イベントでは、指定したキャッシュさせたいファイルパスを全てキャッシュさせています。
挙動のイメージとしては、トップページにアクセスした際に Service Worker がブラウザに導入(install)されるイベントの発生時にキャッシュを生成しています。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
var urlsToCache = [
'/',
'/static/img/favicon.ico',
'/static/img/logo.png',
'/static/css/bootstrap.min.css',
'/static/css/flickity.org.css',
'/static/js/async_set_circuit.js',
'/static/js/bootstrap.min.js',
'/static/js/flickity.pkgd.min.js',
'/static/js/jquery-3.1.0.min.js',
'/static/js/jquery.countdown.min.js',
'/static/js/superagent.js',
'/static/js/tether.min.js',
];

self.addEventListener('install', (event) => {
console.log('install');
event.waitUntil(
caches.open(cacheName).then(function (cache) {
console.log('Opened cache');
return cache.addAll(urlsToCache);
})
);
});

Chrome > Developer Tool > Application > Cache Storage を見るとキャッシュされているのがわかります。

fetch

以下処理は、fetch イベントでブラウザでキャッシュしたファイルを呼び出しています。

1
2
3
4
5
6
7
8
9
10
11
self.addEventListener('fetch', function (event) {
console.log('fetch');
event.respondWith(
caches.match(event.request).then(function (response) {
if (response) {
return response;
}
return fetch(event.request);
})
);
});

activate

Service Worker は active 状態になってもすぐにブラウザ上のリソースを操作できず、
もう一度ページにアクセスした際にできるようになっています。

その為、一度しかアクセスしないユーザにとっては Service Worker によるパフォーマンスの向上を体験できないことになります。

その為、 以下 activate イベントによって直ちに操作できるようにします。

1
2
3
4
self.addEventListener('activate', (event) => {
console.log('activate');
event.waitUntil(self.clients.claim());
});

基本、以上の設定で Service Worker 導入完了でした。

前後を比較すると Waterfall で見る、リソースのロードタイムがキュッと縮んでいるのがわかります。

Before
f:id:kenzo0107:20180814124810p:plain

After
f:id:kenzo0107:20180814124826p:plain

まとめ

Service Worker で一度キャッシュさせた後はオフラインでも動作するような仕組みが作れました。
オフラインでも動作する、というのは魅力的 ♪

ただし、クエリパラメータのパターンの多い URL がある場合などは
キャッシュされにくく、この場合のキャッシュ戦略としては、ひとまず静的ファイルのみキャッシュするなどで対応するのが良いのか、
等考えさせられるところがありました。

例)

1
2
3
/ts?circuit_id=1&station_id=1 はアクセスしたけど
/ts?circuit_id=1&station_id=2 はアクセスしてない
という場合はオフラインにしたら /ts?circuit_id=1&station_id=2 は閲覧できなくなる

また、POST method は Service Worker は未対応で issue が上がっているようです。
Workaround として以下提案がされているブログがありましたが、実装が複雑で、まだこの辺りは開発の余地がある印象です。

以下 Service Worker 導入時の苦労した点があり、涙無くして見られない内容でした。
日経電子版 サイト高速化と PWA 対応

他趣味アプリで Workbox を利用していますが、
こちらも書いていきたいと思います。

参考

Flask+Service Worker on Heroku で PWA チュートリアル

https://kenzo0107.github.io/2018/08/13/2018-08-14-flask-service-worker-on-heroku-pwa/

Author

Kenzo Tanaka

Posted on

2018-08-14

Licensed under

コメント