ServiceWorkerをproductionで使ってる話
shokai.icon @shokai
右のメニューのStart presentationでスライドになります
画面遷移が速くなった
https://gyazo.com/86faa398b233f86be3ad4a15cd2e777e
ScrapboxはWiKiみたいなノートアプリです
https://gyazo.com/343caf0f14cc565ce656a43e9a02aad2https://gyazo.com/471d8cab15bf364febe29e6f2cafb5ad
今日の話
1. ServiceWorkerって何?
2. productionで使って得た知見
ServiceWorkerって何?
わかる人いますかshokai.icon
私もよくわかりませんが…
ググるとわかる
https://gyazo.com/e4d60843ceddd85aa65169e7027a6943
リッチなオフライン体験、定期的なバックグラウンド同期、プッシュ通知など、これまでネイティブアプリを必要としていた機能が Web にもやってきます。Service Worker はそれらの機能を提供する基盤技術です。
回線切ってググるとわかる
https://gyazo.com/438ef8eb64c22ae94b1885b1b9d8fafd
Chromeのホーム画面はServiceWorkerで実装されてるから、オフラインでも表示できる
workerのソースも見れるぞ
オフライン表示だけではない
webページからRequestが発行されて
ServiceWorkerを通って
サーバーに送信される
サーバーからResponseが返ってきて
ServiceWorkerを通って
webページにデータが戻る
ブラウザ内で動くプログラマブルなproxy、というイメージ
色々できる
RequestやResponseを途中で書き換えたり
勝手にRequestを発行してcacheを温めておいたり
プログラマブルなproxy
オフライン表示機能がServiceWorkerについてるわけではない
がんばって自分で実装する
fetch event
等を使う
オフライン表示の例
cache hitすれば、Requestをサーバーに送らずUIスレッドに返す
cache hitしなければ、サーバーからfetchして返す
code:sw.js
self.addEventListener('fetch', (event) => {
const {request} = event
if (request.method !== 'GET') return // GET以外をcacheするの怖い
event.respondWith((async () => {
// cacheがあれば返す
const cachedResponse = await self.caches.match(request)
if (cachedResponse) return cachedResponse
// cacheが無い場合
const response = await fetch(request)
const cache = await self.caches.open('foo') // 名前は何でも良し
cache.put(request, response)
return response
})())
})
self.とは
ServiceWorkerにおけるwindow.やglobal.のようなグローバルオブジェクト
CacheStorageとは
KVS
key: Request
value: Response
cache.match(request)で探せる
ServiceWorker内ではself.caches
window.cachesと共通
cache.addAll([...urls])で一気にfetchする事もできる
UIスレッド側でやる事
ServiceWorker自体のインストールだけやる
navigator.serviceWorker.register('./sw.js', {scope: '/'})
このRequestはServiceWorkerにハンドルしてもらって、こっちはしないで〜
とかはできない
全てのRequestがServiceWorkerを通ってしまう
webページ内に表示している別originへのリクエストも含む
Responseがどこから来た物なのか判別できない
cache storageから来たのか?
ServiceWorkerはちゃんと最新データをfetchしたのか?
ServiceWorkerがHTTP headerを追加する等、各自で工夫が必要
https://gyazo.com/86faa398b233f86be3ad4a15cd2e777e
光速を超えた
サーバーはアメリカにあるのに、clickした瞬間に画面が表示される
アドレスバーが書き換わった直後にUIスレッドはfetchしている
そこからパケットが太平洋を往復する間、待つ必要があった
click前にcacheを温めておいてもらうようにした
Random jumpも速い
ランダムにページを表示するボタン
https://gyazo.com/36012561fe418ce4150cd0f7c5cae5e3
インターンに来ているyutaro.iconが一瞬で作ってくれた
ランダムなのに速い
ランダム表示したら、次にランダム表示する予定のページをprefetchしている
対応ブラウザ
https://gyazo.com/1685be3b7bdadb0d94b7f16627f743e2
IE以外の最新版ならok
window閉じても生きてる
たぶんブラウザのプロセスが生きてる限り生きてるはず
setIntervalで定期的にcacheを更新なんて事も可能
でもたまに勝手に死んでる気がする
どうやって観測すればいいんだ?ぜんぜんわからない
ライフサイクル
ServiceWorkerが有効になるまで
1. Download
2. Install
3. Activate
ServiceWorkerのインストール自体を、UIスレッドのJavaScriptで行わなければならない
navigator.serviceWorker.register('./sw.js', {scope: '/'})
最初にアクセスしてactivateされるまでは、ServiceWorkerが存在しない
ダウンロード失敗してインストールできない事もある
ServiceWorkerとclient jsやサーバーAPIのバージョンがズレてるタイミングが必ず存在する
アクセス毎にregister再実行する事で更新する為
こわい
ServiceWorkerにstateを持たせたりすると絶対こわい
24時間毎に自動更新される
らしい
毎日開発してるので、自動更新を観測する暇がない…
ぜんぜんわからない
Request/Response以外にも
push通知
右上に出るやつ
オフラインの時に発行されたRequestをとっておいて、オンラインになったら一気に送信してくれる
らしい(まだ試したことない)
UIスレッドと通信
色々できてすごい!!
productionで使って得た知見
インストールするユーザーを絞った
まず最新のChromeを使っているログインユーザーだけ
理由
ServiceWorkerに不具合があった場合に、ServiceWorkerの更新ができなくなる場合がある
インストールはUIスレッドのJavaScriptから行うので
index.jsもServiceWorkerを通ってUIスレッドに配信される
24時間毎の自動更新もあるが、丸一日使えないと困る
ServiceWorker内のエラーを全部捕捉できる
2017年12月にSentryのclientライブラリがfetchに対応した
TypeErrorがいっぱいでる
fetch結果がstatus 200系以外だとでる
ユーザーが埋め込んだ画像とか
名前が変で混乱した
原因:try-catch忘れてた
PrefetchのせいでRequest増えた
https://gyazo.com/4d3bcd62fe59510a325f53fb62a6f19b
今の所は元気です
回線速度を計測できる
navigator.connection.rttでレイテンシを計測したかった
Chromeにしか実装されてない
fetchの前と後をServiceWorkerでフックして、時間をはかる
遅い回線ではprefetchをやめる等
SPAの初期表示に必要な部品だけcacheしてみた
HTML/JS/CSS/font/画像だけ
APIはcacheしない
サーバーに飛ぶRequest数が減る
304 not modifiedより速い
3G環境では初期ロードが1.5秒速くなった
レイテンシが小さい環境ではあまり変化なし
public WiFiのログイン画面がハンドルできない
https://gyazo.com/1322ba0413a43da8b4ce7c7205c73b61
自分がなぜサーバーに接続できないのか知る手段が無い
ぜんぜんわからない
スマホで出るやつをwebサイトでもやる方法を誰か教えてくれ
https://gyazo.com/4713046cfe5ee20c631538d16641e40e
private windowでもRequestがServiceWorker通ってる
Cache Storageは別になっているようだが
普通のwindowの方でインストールされたら、private windowでは既にインストールされた事になっているようだ
まとめ
ただのオフライン表示システムではない
プログラマブルなproxyです
下手すると24時間サービスが開けなくなる恐怖
わからない事だらけだ
怖いのでSentry入れよう