Slide 1

Slide 1 text

Service Worker registration/lifecycle Frontend Meetup Tokyo vol.2 2016/5/18 Jxck

Slide 2

Slide 2 text

● id: Jxck ● github: Jxck ● twitter: @jxck_ ● blog: https://blog.jxck.io ● podcast: http://mozaic.fm ● Love: music Jack

Slide 3

Slide 3 text

mozaic.fm ep17 3 Service Worker w/ @kinu, @nhiroki_ http://mozaic.fm/post/117004083098/17-service-worker

Slide 4

Slide 4 text

中級者向け Service Worker Tutorial 4 https://blog.jxck.io/entries/2016-04-24/service-worker-tutorial.html

Slide 5

Slide 5 text

Todays Talk 5

Slide 6

Slide 6 text

Next Step of Introduction 6 ● Go Deeper / Understand Examples Well ● Good Introductions ○ https://serviceworke.rs/ ○ https://jakearchibald.com/2014/offline-cookbook/ ○ http://www.html5rocks.com/ja/tutorials/service- worker/introduction/ ○ More ● Focus on … ○ Registration ○ Update ○ Scope

Slide 7

Slide 7 text

Service Worker 7

Slide 8

Slide 8 text

Workers class Hero 8 ● Service Worker (got back together) ● Shared Worker ● Web Worker ● App Cache (broke up)

Slide 9

Slide 9 text

I'm free to be whatever I 何になるのも俺の自由だ Whatever I choose 何を選ぶのも俺の自由だ And I'll hook the request if I want その気になればリクエストだってフックしてやる 9 https://youtu.be/zUADzarhFyA

Slide 10

Slide 10 text

Architecture 10

Slide 11

Slide 11 text

11 Architecture

Slide 12

Slide 12 text

12 Controller/Client ● Controller controls Client ○ Client = Window ○ Controller = Service Worker

Slide 13

Slide 13 text

13 Event with Client ● Controller hooks HTTP request from Client ● Controller talks with Client via message

Slide 14

Slide 14 text

14 Event with Network ● Controller hooks push from network ● Controller hooks change from offline -> online

Slide 15

Slide 15 text

15 websocket ● Controller doesn’t hooks client WebSocket ● Controller also talks WebSocket

Slide 16

Slide 16 text

16 worker/db ● Controller also Use WebWorker / IndexedDB ● No LocalStorage because Sync I/O ● Separate Context between Client

Slide 17

Slide 17 text

17 cache ● Client/Controller has Cache API ● Before browser cache ● Means fetch from SW hits browser cache

Slide 18

Slide 18 text

18 Architecture

Slide 19

Slide 19 text

Lifecycle 19

Slide 20

Slide 20 text

Lifecycle 20

Slide 21

Slide 21 text

Install SW 21

Slide 22

Slide 22 text

register() navigator.serviceWorker.register('worker.js') .then((registration) => { return navigator.serviceWorker.ready; }); 22 self.addEventListener('install', (e) => { console.info('install', e); }); self.addEventListener('activate', (e) => { console.info('activate', e); }); master.js worker.js

Slide 23

Slide 23 text

register() -> oninstall 23 ● Browser fetches script ● Install it ● Fires oninstall ● Prepare cache or migrate schema Ver. 1

Slide 24

Slide 24 text

installed -> waiting 24 ● Installed script moves to waiting ● Waiting waits to be active ● If no active script available, through to active Ver. 1

Slide 25

Slide 25 text

waiting -> activate 25 ● waiting script moves to active ● Fires onactivate ● but Not Controller yet Ver. 1

Slide 26

Slide 26 text

Be a Controller 26 ● If there has a chance to be controller ● Script became controller ● Fires oncontrollerchange Ver. 1

Slide 27

Slide 27 text

Chance to be Controlle ? 27 ● Avoid state conflict between current controller and next controller ● Next page load ● call claim() Ver. 1

Slide 28

Slide 28 text

skipWaiting/claim self.addEventListener('activate', (e) => { console.info('activate', e); // make me controller immediately !! e.waitUntil(self.clients.claim()); }); 28 navigator.serviceWorker.register('worker.js') .then((registration) => { return navigator.serviceWorker.ready; }); master.js worker.js

Slide 29

Slide 29 text

Update SW 29

Slide 30

Slide 30 text

update() navigator.serviceWorker.register('v1.js') .then((reg) => { reg.addEventListener('updatefound', (e) => { console.info('update', e); // v2 found }); return navigator.serviceWorker.ready; }).then((registration) => { setInterval(() => { // update registration.update(); }, 1000); }); 30

Slide 31

Slide 31 text

update() or reload 31 ● reload / call update() fetches script again ● If script changed(v2), install again ● Fires onupdatefound Ver. 2

Slide 32

Slide 32 text

update() and browser cache 32 ● update() hits browser cache ● But bypass(max-age) it after 24h ● Security knowledge from App Cache Cached Ver. 1 Ver. 2

Slide 33

Slide 33 text

waiting 33 ● Installed v2 became waiting (v1) ● If activate v2 immediatly, call skipWaiting() Ver. 1 Ver. 2

Slide 34

Slide 34 text

oninstall/onactivate self.addEventListener('install', (e) => { console.info('install', e); // do some prepare not affect to v1 // like cache new resouce etc }); self.addEventListener('activate', (e) => { console.info('activate', e); // do some cleanup of v1 // like schema update etc }); 34

Slide 35

Slide 35 text

waiting 35 ● Redundant old controller & oncontrollerchange Ver. 1 Ver. 2

Slide 36

Slide 36 text

skipWaiting/claim self.addEventListener('install', (e) => { console.info('install', e); // make me active immediately !! e.waitUntil(skipWaiting()); }); self.addEventListener('activate', (e) => { console.info('activate', e); // make me controller immediately !! e.waitUntil(self.clients.claim()); }); 36

Slide 37

Slide 37 text

37 When worker works ? ● Works even if offline ● Works even if page not opened ● Works even if browser closed

Slide 38

Slide 38 text

38 When worker stops ? ● Active worker stops anytime while no event ● Restart when event fired ● Save Every Data into Storage (not on memory)

Slide 39

Slide 39 text

Scope 39

Slide 40

Slide 40 text

register() with scope navigator .serviceWorker .register('worker.js', { scope: '.' }) .then((registration) => { return navigator.serviceWorker.ready; }); 40 master.js ● Controller controls client in scope ● Could register multiple controller in different scope ● But only one Controller for Client always

Slide 41

Slide 41 text

Scope 41 ● Browser searches controller for client ● Wide scope affects deep path ● Deep match with path & scope

Slide 42

Slide 42 text

Scope 42 ● If you avoid sw in deep path ○ If-else in controller ○ Register emtpy SW cache.js cache-push.js empty.js

Slide 43

Slide 43 text

Service Worker Allowed 43 ● /js/worker.js can’t register /foo ○ Only /js/* are allowed ○ Add Service Worker Allowed: “/foo” as HTTP header

Slide 44

Slide 44 text

Tips 44

Slide 45

Slide 45 text

On insecure origin 45 $ google_chrome \ --user-data-dir=/path/to/js \ --unsafely-treat- insecure-origin-as-secure=http://insecure.example. com ● Register SW to insecure origin ● For Develop only ● But Let’s Encrypt it

Slide 46

Slide 46 text

tips 46 ● Be friend with Chrome Canaly Dev Tools ● Always Check registration & update ● Design Scope Carefully ● Maintain Cache Carefully ● Never forget save to DB while event lifetime ● Basiclly no code outside event handler ● Start with Implicit Proxy ○ Local Implicit proxy: works same w/o sw ○ Local Orgin Server: generate contents in sw ● Push is not only usecase for sw

Slide 47

Slide 47 text

Finished 47

Slide 48

Slide 48 text

Jack thanks