Staff Developer Advocate at
Patricio Vargas (Pato)
@devpato
@devpato
@devpato
A Service worker is a proxy script between your web app and the outside. Service Workers execute separately from the main browser thread.
Web App
Service Worker
Cache
Network
@devpato
@devpato
@devpato
@devpato
@devpato
Student | Grade | Action |
---|---|---|
Pato | A | 💾 ❌ ✏️ |
Chris D | F | 💾 ❌ ✏️ |
Service Worker & Background Sync API
Offline Cache
Backend
@devpato
@devpato
@devpato
@devpato
index.js
sw.js
@devpato
if ("serviceWorker" in navigator) {
window.addEventListener("load", ()=>{
navigator.serviceWorker.register("sw.js").then(swRegistered => {
console.log("[ServiceWorker**] - Registered");
});
});
}
index.js
@devpato
const cacheName = "my-pwa-shell-v1.0";
const filesToCache = [
"index.html",
"./js/index.js",
"./styles/styles.css",
"manifest.json",
"./assets/icons/icon.png",
"./assets/nike1.jpeg",
];
self.addEventListener("install", e => {
console.log("[ServiceWorker] - Install");
e.waitUntil((async () => {
const cache = await caches.open(cacheName);
console.log("[ServiceWorker] - Caching app shell");
await cache.addAll(filesToCache);
})());
});
sw.js
@devpato
self.addEventListener("activate", e => {
e.waitUntil((async () => {
const cacheList = await caches.keys();
await Promise.all(
cacheList.map(currentCache => {
// currentCache = "cacheVersion-1.0" , newCache = "cacheVersion-2.0"
if (currentCache !== newCache) {
return caches.delete(currentCache);
}
})
);
})());
});
sw.js
@devpato
@devpato
“Workbox is a library that incorporates a set of best practices and eliminates the boilerplate that every developer writes when working with service workers.” - Google Devs.
@devpato
@devpato
Your resources are put in the cache before they are requested. This is an extreme approach.
E.g Your web app start url, offline fallback, and, key js and files
Pre-caching happens at the service worker install event at the cache first strategy
@devpato
Runtime cache adds resources to the cache when they are requested. Runtime caching works with different caching strategies and the resources are cached independently.
E.g a new cache named "images".
@devpato
self.addEventListener('fetch', e => {
e.respondWith((async () => {
const resource = await caches.match(e.request);
return resource || fetch(e.request);
})());
});
sw.js
@devpato
2
fallback
Web App
Network
Service Worker
1
The Asset
3
self.addEventListener('fetch', function (event) {
event.respondWith(
caches.match(event.request).then(function (response) {
return response || fetch(event.request);
}),
);
});
import {registerRoute} from 'workbox-routing';
import {CacheFirst} from 'workbox-strategies';
registerRoute(({request}) => request.destination === 'style', new CacheFirst());
With Workbox.js
Without Workbox.js
@devpato
3
fallback
2
Web App
Cache
Network
Service Worker
1
The Asset
self.addEventListener('fetch', function (event) {
event.respondWith(
fetch(event.request).catch(function () {
return caches.match(event.request);
}),
);
});
import {registerRoute} from 'workbox-routing';
import {NetworkFirst} from 'workbox-strategies';
registerRoute(
({url}) => url.pathname.startsWith('/social-timeline/'),
new NetworkFirst()
);
With Workbox.js
Without Workbox.js
@devpato
2
Web App
Network
Service Worker
1
The Asset
self.addEventListener('fetch', function (event) {
event.respondWith(fetch(event.request));
// or simply don't call event.respondWith, which
// will result in default browser behavior
});
import {registerRoute} from 'workbox-routing';
import {NetworkOnly} from 'workbox-strategies';
registerRoute(({url}) => url.pathname.startsWith('/admin/'), new NetworkOnly());
With Workbox.js
Without Workbox.js
@devpato
2
Web App
Cache
Service Worker
1
The Asset
self.addEventListener('fetch', function (event) {
// If a match isn't found in the cache, the response
// will look like a connection error
event.respondWith(caches.match(event.request));
});
import {registerRoute} from 'workbox-routing';
import {CacheOnly} from 'workbox-strategies';
registerRoute(({url}) => url.pathname.startsWith('/app/v2/'), new CacheOnly());
With Workbox.js
Without Workbox.js
@devpato
@devpato
@devpato
Make sure to set the right scope for your service worker
Delay registering a service worker until after a web app's load event fire
Don't worry about a service worker caching itself
Avoid caching bad responses by properly handling them in fetch
Evaluate caching strategy examples and never copy-paste them directly
You might not need to build a service worker from scratch
@devpato
Don't Try to Recreate All Your Business Logic in the Service Worker
Always Define an offline response
Be careful when using hot-reload
@devpato
@devpato
@devpato