Upgrade to Pro
— share decks privately, control downloads, hide ads and more …
Speaker Deck
Sign up for free
Menu
Search
Features
All features
Private URLs
Password Protection
Custom URLS
Scheduled publishing
Remove Branding
Restrict embedding
Deck Collections
Notes
Features
All features
Private URLs
Password Protection
Custom URLS
Scheduled publishing
Remove Branding
Restrict embedding
Deck Collections
Notes
Explore
Featured decks
Featured speakers
Programming
Technology
Storyboards
Explore
Featured decks
Featured speakers
Programming
Technology
Storyboards
Pricing
Search
Sign in
Sign up for free
Offline Web Apps (Service Workers)
Search
Sponsored
·
Ship Features Fearlessly
Turn features on and off without deploys. Used by thousands of Ruby developers.
→
Erik Hellman
August 03, 2017
Programming
190
3
Share
Embed
Copy iframe code
Copy JS code
Copy link
Start on current slide
Offline Web Apps (Service Workers)
Erik Hellman
August 03, 2017
More Decks by Erik Hellman
See All by Erik Hellman
Wireless protocols for the next generation IoT devices
erikhellman
2
170
Working with Custom Android Devices and AOSP build system
erikhellman
2
720
Working with custom Android devices
erikhellman
2
540
Developing system apps without AOSP
erikhellman
2
850
State of BLE on Android in 2023
erikhellman
3
1.1k
State of BLE on Android in 2022
erikhellman
1
1.4k
The technical solutions behind Öppna Skolplattformen
erikhellman
0
300
Bluetooth Low Energy for Modern Android Development
erikhellman
1
1.1k
Introduction to Flutter
erikhellman
0
300
Other Decks in Programming
See All in Programming
Domain-Driven Transformation
hschwentner
2
2.3k
ChromeでローカルLLM
ryu1013
0
110
phperだってパンチカードでコーディングしたい
o0h
PRO
0
280
[2026-09-26]空論ジェネリックプロセス~テスト資産とAIで紡ぐ、再現可能なパフォーマンスチューニングの話~
tosite
0
270
パスワード再設定メールのURLについて知っておこう
uyuki234
0
140
C#の現在地 進化の歴史と、AI時代の.NET Everywhere
neuecc
5
5.1k
パーソナライズPodcastを作った話
repunit11
0
130
iOS 27でニュースアプリはどう変わる!? 〜日経電子版の新機能対応と、開発事例から〜
lynnswap
7
13k
Kubernetes祭り #2 OP/ED
bells17
0
110
更なる可用性を求めて、5年間運用したKotlinのアプリケーションをGoでリプレイスする話
ken_tunc
0
580
Ghostty + Neovimで作る 透明でカッコ良い開発環境
j341nono
0
170
APNsからLive Activityを開始する話
yumnumm
0
160
Featured
See All Featured
Taking LLMs out of the black box: A practical guide to human-in-the-loop distillation
inesmontani
PRO
3
2.4k
Mind Mapping
helmedeiros
1
400
The Organizational Zoo: Understanding Human Behavior Agility Through Metaphoric Constructive Conversations (based on the works of Arthur Shelley, Ph.D)
kimpetersen
PRO
0
490
Visualizing Your Data: Incorporating Mongo into Loggly Infrastructure
mongodb
50
10k
Evolution of real-time – Irina Nazarova, EuRuKo, 2024
irinanazarova
9
1.6k
Money Talks: Using Revenue to Get Sh*t Done
nikkihalliwell
0
520
[Rails World 2026] Durable orchestration on Rails: from continuation to workflow
palkan
1
730
How to Talk to Developers About Accessibility
jct
2
570
The Illustrated Children's Guide to Kubernetes
chrisshort
51
53k
Into the Great Unknown - MozCon
thekraken
41
2.8k
The Cult of Friendly URLs
andyhume
79
7k
CoffeeScript is Beautiful & I Never Want to Write Plain JavaScript Again
sstephenson
162
16k
Transcript
Offline Web Apps
None
None
Lie-fi
of users abandon sites that take longer than 3 seconds
to load 53%
60% of world-wide mobile connections are 2G
Service Workers
Service Workers are a client-side proxy Service worker (written in
Javascript) Cache Web server
Service Worker Lifecycle • Adds app-like lifecycle to a page
• Wakes up only when the OS says • Only responds to system events Activated Error Idle Active Terminated Install Register
• Adds app-like lifecycle to a page • Wakes up
only when the OS says • Only responds to system events Activated Error Idle Active Terminated Install Register Service Worker Lifecycle
Service Worker Lifecycle • Adds app-like lifecycle to a page
• Wakes up only when the OS says • Only responds to system events Activated Error Idle Active Terminated Install Register
Service Worker is for the SECOND load.
Implementing a Simple Service Worker
Register the Service Worker Activated Error Idle Active Terminated Install
Register
Register the Service Worker if ('serviceWorker' in navigator) { navigator.serviceWorker.register('/service-worker.js')
.then(function(reg) { console.log('Service Worker Registered', reg); }) .catch(function(err) { console.log('Error registering Service Worker', err); }); }
Register the Service Worker if ('serviceWorker' in navigator) { navigator.serviceWorker.register('/service-worker.js')
.then(function(reg) { console.log('Service Worker Registered', reg); }) .catch(function(err) { console.log('Error registering Service Worker', err); }); }
Add an install Event Handler Activated Error Idle Active Terminated
Install Register
Add an install Event Handler self.addEventListener('install', function(event) { return self.skipWaiting();
});
Pre-fetch the App Resources Activated Error Idle Active Terminated Install
Register
Pre-fetch the App Resources var cacheName = 'app-shell-cache-v1'; var filesToCache
= ['/', '/index.html', ...]; self.addEventListener('install', function(event) { event.waitUntil( caches.open(cacheName).then(function(cache) { return cache.addAll(filesToCache); }).then(function() { return self.skipWaiting(); }) ); });
Pre-fetch the App Resources var cacheName = 'app-shell-cache-v1'; var filesToCache
= ['/', '/index.html', ...]; self.addEventListener('install', function(event) { event.waitUntil( caches.open(cacheName).then(function(cache) { return cache.addAll(filesToCache); }).then(function() { return self.skipWaiting(); }) ); });
Pre-fetch the App Resources var cacheName = 'app-shell-cache-v1'; var filesToCache
= ['/', '/index.html', ...]; self.addEventListener('install', function(event) { event.waitUntil( caches.open(cacheName).then(function(cache) { return cache.addAll(filesToCache); }).then(function() { return self.skipWaiting(); }) ); });
Pre-fetch the App Resources var cacheName = 'app-shell-cache-v1'; var filesToCache
= ['/', '/index.html', ...]; self.addEventListener('install', function(event) { event.waitUntil( caches.open(cacheName).then(function(cache) { return cache.addAll(filesToCache); }).then(function() { return self.skipWaiting(); }) ); });
Add an activate Event Handler Activated Error Idle Active Terminated
Install Register
Add an activate Event Handler self.addEventListener('activate', function(e) { e.waitUntil( caches.keys().then(function(keyList)
{ return Promise.all(keyList.map(function(key) { if (key !== cacheName) { return caches.delete(key); } })); }) ); return self.clients.claim(); });
Add an activate Event Handler self.addEventListener('activate', function(e) { e.waitUntil( caches.keys().then(function(keyList)
{ return Promise.all(keyList.map(function(key) { if (key !== cacheName) { return caches.delete(key); } })); }) ); return self.clients.claim(); });
Not Done Yet… Activated Error Idle Active Terminated Install Register
None
Add a fetch Event Handler self.addEventListener('fetch', function(e) { e.respondWith( caches.match(e.request).then(function(response)
{ return response || fetch(e.request); }) ); });
Add a fetch Event Handler self.addEventListener('fetch', function(e) { e.respondWith( caches.match(e.request).then(function(response)
{ return response || fetch(e.request); }) ); });
Add a fetch Event Handler self.addEventListener('fetch', function(e) { e.respondWith( caches.match(e.request).then(function(response)
{ return response || fetch(e.request); }) ); });
Add a fetch Event Handler self.addEventListener('fetch', function(e) { e.respondWith( caches.match(e.request).then(function(response)
{ return response || fetch(e.request); }) ); });
Ready to Go! Activated Error Idle Active Terminated Install Register
Scope if ('serviceWorker' in navigator) { navigator.serviceWorker.register('/service-worker.js') .then(function(reg) { console.log('Service
Worker Registered', reg); }) .catch(function(err) { console.log('Error registering Service Worker', err); }); }
Scope if ('serviceWorker' in navigator) { navigator.serviceWorker.register('/service-worker.js') .then(function(reg) { console.log('Service
Worker Registered', reg); }) .catch(function(err) { console.log('Error registering Service Worker', err); }); }
Scope if ('serviceWorker' in navigator) { navigator.serviceWorker.register('/scripts/s-worker.js') .then(function(reg) { console.log('Service
Worker Registered', reg); }) .catch(function(err) { console.log('Error registering Service Worker', err); }); }
Scope if ('serviceWorker' in navigator) { navigator.serviceWorker.register('/service-worker.js') .then(function(reg) { console.log('Service
Worker Registered', reg); }) .catch(function(err) { console.log('Error registering Service Worker', err); }); }
Caching Strategies YOU are in control of the network
Cache, Falling Back to Network Page Service Worker Network Cache
X
Network, Falling Back to Cache Page Service Worker Network Cache
X
Cache, then Network Page Service Worker Network Cache
Generic Fallback Page Service Worker Network Cache X X
control You are in
Tools
Chrome Dev Tools
Chrome Dev Tools: the cache
Chrome Dev Tools: the cache
sw-toolbox
Cache first in sw-toolbox importScripts('/sw-toolbox.js'); toolbox.router.get('/(.*)', toolbox.cacheFirst, { origin: /\.googleapis\.com$/
});
sw-precache Node module
sw-precache precache.write('service-worker.js', { staticFileGlobs: ['**/*.{html,css}'], runtimeCaching: [ {urlPattern: '/', handler:
'fastest'}, {urlPattern: '/api/.*', handler: 'networkFirst', options: {networkTimeoutSeconds: 5} }, {urlPattern: '/posts/.*', handler: 'cacheFirst'}, {urlPattern: '/styles/.*', handler: 'cacheOnly'}, {urlPattern: '/inbox.json', handler: 'networkOnly'} ] });
PWA Codelab https://codelabs.developers.google.com/codelabs/your-first-pwapp
Service Workers the core underpinning Progressive Web Apps
Service Workers Web Apps will need to worry about lifecycle...
Thank You!