Skip to content

oodrive/ServiceWorker.md

Β 
Β 

Folders and files

NameName
Last commit message
Last commit date

Latest commit

Β 

History

4 Commits
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 

Repository files navigation

title: Service Worker author: name: I'm Adrien, frontend developer url: https://oodrive.com email: a.gibrat@oodrive.com theme: ./theme controls: true output: index.html

--

Service Worker

A [gentle] introduction

--

What is a Worker?

--

Browsers used to run everything in one thread

sequenceDiagram
	participant B as πŸ—” Browser
	participant X
	B->X: HTTP requests, compute, DOM changes ...

πŸ‹ Intensive Javascript

<script> document.currentScript.parentNode.addEventListener('mermaid', event => event.target.querySelectorAll('g:nth-child(4), line').forEach(e => e.style = 'visibility: hidden!important')) // hide lines </script>

--

Workers runs Javascript in another thread

sequenceDiagram
	participant B as πŸ—” Browser
	participant W as πŸ“ƒ Worker
	B->>W: create

πŸ““ Worker API

--

Then uses events to communicate

sequenceDiagram
	participant B as πŸ—” Browser
	participant W as πŸ“ƒ Worker
	B->>W: create
	loop events
		W--xB: message
		B--xW: 
	end

πŸ“― postMessage

--

There are three kind of Workers

All run background scripts independently of any UI

  • Web Workers since 2010, perform heavy computation, ex: pdfjs
  • Shared Workers since 2010, shared across same origin webkit in 2015
  • Service Workers since 2014, control HTTP requests from same origin

πŸ‘· Workers

--

Let's talk about Service workers

--

Definition

A service worker acts as a proxy between the browser (your web application) and the network

Main usages

  • Offline access
graph LR
	B("πŸ—”") --> S("πŸ“ƒ")
    S -.- N("☁")
	style B fill:none,stroke:none
	style S fill:none,stroke:none
	style N fill:none,stroke:none
  • Push notifications
graph RL
	N("πŸ—¨") --> S("πŸ“ƒ")
	S -.- B("πŸ—”")
	style B fill:none,stroke:none
	style S fill:none,stroke:none
	style N fill:none,stroke:none
  • and more...
  • πŸ“– Service Worker API

    <script> document.currentScript.parentNode.addEventListener('mermaid', event => { event.target.classList.add('fragment', 'float-right') event.target.style.marginTop = '-5rem' event.target.style.maxWidth = '60%' if (event.target.matches('li:nth-of-type(2) svg')) event.target.style.marginTop = '-8rem' }) // graphs position </script>

    --

    It uses recent async APIs

    support: chrome, mozilla, android, opera, edge, safari

    • Promises construction to execute code after a task is fulfilled
    • postMessage method to communicate between contexts
    • fetch function to make simple HTTP requests, successor of XHR

    βœ“ Is Service Worker Ready

    --

    Runs under conditions

    support: chrome, mozilla, android, opera, edge (development), safari (development)

    • HTTPS only, same origin for security reason
    • No DOM access no document, nor window
    • Behind flag in Edge & Safari Technical Preview

    ❔ Can I Use Service Worker

    --

    How to use it?

    --

    Registration

    support: chrome, mozilla, android, opera, edge (development), safari (development)

    main.js

    if (navigator.serviceWorker)
    	navigator.serviceWorker
    		.register('/service-worker.js', { scope: '/' })
    		.then(registration => registration.state)

    Multiple Service Workers must register distinct scopes

    🍰 Getting Started

    --

    First install

    support: chrome, mozilla, android, opera, edge (development), safari (development)

    service-worker.js

    self.addEventListener('install', event => 
    	event.waitUntil(/* ready to activate */)
    )
    graph LR
    	P["πŸ—” page"] -. register .-> I("βš™ install")
        I --> A("βœ” activate")
        I --> E("⚠ error")
    	style P fill:white
    	style I fill:white,stroke:#41b6e8
    	style A fill:white,stroke:green
    	style E fill:white,stroke:red
    

    βš™ Service Worker Lifecycle

    --

    Next visit

    support: chrome, mozilla, android, opera, edge (development), safari (development)

    • Activates only inside scope
    • Skip the install event handler
    graph LR
    	P["πŸ—” page"] -. in scope .-> A("βœ” activate")
    	A -. control .-> P
    	click P callback "in the Service Worker Scope"
    	style P fill:white,stroke:lightgrey
    	style A fill:white,stroke:green
    

    πŸ‘ Service Worker: An Introduction

    --

    Upgrade process

    support: chrome, mozilla, android, opera, edge (development), safari (development)

    New Service Worker will wait deactivation of the old one before it activates

    graph LR
    	subgraph Old Service Worker
        	O("βœ” activate") --> D("☠ deactivate")
        end
    	subgraph New Service Worker
    		O("βœ” activate") -. updatefound .-> I("βš™ install")
    		I -. waiting .-> A("βœ” activate")
        end
    	style O fill:white,stroke:lightgrey
    	style D fill:white,stroke:red
    	style I fill:white,stroke:#41b6e8
    	style A fill:white,stroke:green
    
    <script> document.currentScript.parentNode.addEventListener('mermaid', event => event.target.style.maxWidth = '90%') </script>

    ✌ Service Worker Lifecycle

    --

    Emitted events

    Main functional events

    • fetch intercepted an HTTP request (made by main thread)
    • message received a message via postMessage
    • push received a push notification

    πŸ—± Service Worker events

    --

    States & events flow

    graph LR
    	A("βœ” Activated") --> D{"βŒ› Idle"}
    	D --> F("βš™ Handle event")
    	F --> D
        D --> T["☠ Terminated"]
    	T --> F
    	style A fill:white,stroke:green
    	style D fill:white
    	style F fill:white,stroke:#41b6e8
        style T fill:white,stroke:red
    
    <script> document.currentScript.parentNode.addEventListener('mermaid', event => event.target.style.maxWidth = '100%') </script>

    Service worker may terminate at any time!

    🌠 Using Service Workers

    --

    Avoid pitfalls

    --

    Persistence

    You cannot rely on global state within a service worker

    • No Local Storage
    • But IndexedDB (use a wrapper!)
    • Use the Cache interface

    πŸ–₯ Localforage

    --

    Tips

    • Beware of redirects, credentials, streams
    • Avoid puting version in script URL
    • Specific debug tools chrome://serviceworker-internals
    • By default first run does not control the main Thread

    ⚠ Service Workers gotchas

    --

    Let's go offline!

    --

    Offline basics

    support: chrome, mozilla, android, opera, edge (development), safari (development)

    service-worker.js

    const CACHE = 'my-awsome-pwa',
    const FILES = ['/', '/styles.css', '/script.js']
    self.addEventListener('install', event =>
    	event.waitUntil(
    		caches.open(CACHE)
    			.then(cache => cache.addAll(FILES))
    	)
    )

    πŸ“š Service Worker specification

    --

    Cache first, fallback to network

    support: chrome, mozilla, android, opera, edge (development), safari (development)

    service-worker.js

    self.addEventListener('fetch', event =>
    	event.respondWith(
    		caches.match(event.request)
    			.then(response => response || fetch(event.request))
    	)
    )

    πŸ“΄ Offline cookbook

    --

    Caching strategies

    • Cache only KISS Progressive Web Application
    • Cache first, falling back to network static assets
    • Network first, falling back to cache API resources
    • etc

    πŸ—ƒ Workboxjs

    --

    Receive notifications

    --

    Web push notification

    • Used to be complex vendor specific implementations
    • Fully standardized browser provides push server
    • Native notifications UI with user permission

    🚨 Push Notifications in Web App

    --

    Subscription

    support: chrome, mozilla, android, opera, edge (development), safari (development)

    main.js

    const registration = await navigator.serviceWorker.ready
    const push = await registration.pushManager.subscribe()
    sendToBackend(push.endpoint)

    manifest.json (chrome only)

    { ..., "gcm_sender_id": "<Your Sender ID Here>" }

    πŸ“² Web Push Notifications

    --

    And more!

    • Background sync wait for stable network connection (backoff)
    • Periodic background sync scheduled synch (in design)
    • Background fetch HTTP request outlives browser close

    🐢 Background-fetching proposal

    --

    Thanks!

    πŸ‘ Slides sources

    --

    feedback

    --

    Life cycle example

    sequenceDiagram
    	participant B as πŸ—” Browser
    	participant W as πŸ“ƒ Service Worker
    	participant S as ➑ Push Server
    	B->>W: register
    	activate B
    	activate W
    	W--xB: message
    	deactivate W
    	B--xW: fetch
    	activate W
    	deactivate W
    	deactivate B
    	S--xW: notification
    	activate W
    	W--xB: 
    	deactivate W
    
    <script> document.currentScript.previousElementSibling.style.maxWidth = '85%' // Fix arrow document.currentScript.parentNode.addEventListener('mermaid', event => { event.target.querySelectorAll('line[stroke-width][marker-end]').forEach((line, index) => index % 2 || (line.x2.baseVal.value -= 5)) }) </script>

    --

    partners

    Releases

    No releases published

    Packages

    No packages published

    Languages

    • HTML 87.3%
    • CSS 6.5%
    • JavaScript 6.2%