Yves Gurcan
Senior software engineer with a passion for developing bleeding edge web applications and event-driven architecture. More talks and resources at https://connect.yvesgurcan.com.
Pickle with 4 years of experience in condiments.
Work at Brinelify.
Expert in juice network solutions.
• Yes, at work.
• Yes, on a personal project.
• No, but I heard about them.
• No, and I don’t know what they are.
How many websites will stay reactive while users are disconnected?
State of JavaScript 2018: Which new browser APIs are gaining traction?
🔥🔥🔥 Hot stuff! 🔥🔥🔥
Can I Use: Service workers are supported by pretty much all browsers
1. App served over HTTPS (required for service workers anyway).
2. Responsive design.
3. Accessible offline.
4. App manifest.
5. Time to interactive <10 seconds on first visit in 3G.
6. Cross-browser compatibility.
7. Show something when clicking on a link (loading indicator or skeleton).
8. Unique URLs for each page.
• Offer an offline experience to your users.
• Increase performances by caching anything you want in the browser.
• Pay less by decreasing the load on your servers.
• ​Send notifications remotely to the browser.
// index.js
navigator.serviceWorker.register('serviceWorker.js')
.then(registration => console.log('Service worker registered.'))
.catch(error => console.error('Service worker could not register.'));
// serviceWorker.js
const addUrlsToCache = async (urls) => {
const cache = await caches.open('my-cache')
return await cache.addAll(urls);
}
const handleFetchRequest = async (event) => {
const result = await caches.match(event.request)
if (result) {
return result;
}
return fetch(event.request);
}
self.addEventListener('install', event => {
return event.waitUntil(addUrlsToCache(['/', '/style.css', '/index.js']))
});
self.addEventListener('fetch', event => {
event.respondWith(handleFetchRequest(event));
});
// webpack.config.js
const { GenerateSW } = require('workbox-webpack-plugin');
module.exports = () => ({
plugins: [
new GenerateSW({
swDest: 'workboxServiceWorker.js',
maximumFileSizeToCacheInBytes: 5 * 1024 * 1024,
clientsClaim: true,
})
]
});
• Simple configuration.
• Customizable.
• Generates a service worker at compilation.
• The notion of scope in service workers can be confusing.
• Since service workers live on the client, you're not fully in control when to update the script.
• The nature of the beast makes debugging more difficult.
However, from personal experience, you're better off with a single service worker in control of your whole app.
// index.js
navigator.serviceWorker.register('/assetsServiceWorker.js', { scope: '/assets' })
You can restrict which requests a service worker intercepts (such as requests under the /assets scope, for example).
Start: Â Â Â Â Â myServiceWorker.register()
Install: Â Â Â Service worker creates pre-cache.
Wait: Â Â Â Â Â Skipped if there is not an active service
          worker yet.
           Prepares to take over old service worker.
Activate: Â Serves cache or fetches data.
          Additionally, creates cache dynamically.
Stop: Â Â Â Â Â myServiceWorker.unregister()
Your service worker will update as expected if your app is not open on your user's browser.
Otherwise, your updated service worker will not activate. As a consequence, your users might get stuck with an old service worker forever!
You can circumvent this behavior by calling self.skipWaiting() in the worker script.
The brutal way: Desync app from service worker
If you call skipWaiting() without refreshing the app, it might try to access deleted cache and all hell might break loose.
The gentle way: A new beginning
Prompt user to reload the app after calling skipWaiting().
If they agree, it will let the new worker take over.
If they don't, the new worker will take control when they close the tab anyway.
// index.js
async updateServiceWorker(registration) {
// trigger update check manually
const updatedRegistration = await registration.update();
updatedRegistration.addEventListener('updatefound', () => {
// the state of the installing SW has changed
updatedRegistration.installing.addEventListener('statechange', (event) => {
// new SW is ready for activation
if (event.target.state === 'installed') {
promptUserToRefreshApp(updatedRegistration);
}
});
});
if (updatedRegistration.waiting) {
promptUserToRefreshApp(updatedRegistration);
}
}
promptUserToRefreshApp(registration) {
if (window.confirm('A new version of the app is available. Reload the app?')) {
activateUpdatedServiceWorker(registration);
window.location.reload()
}
}
activateUpdatedServiceWorker = (registration) => {
registration.waiting.postMessage({ type: 'SKIP_WAITING' });
}
• Keep control of your service workers while developing them.
• Familiarize yourself with the lifecycle of your service workers.
• See which version of a service worker is running.
• Test offline functionalities.
• Nuke a bad service worker.
ServiceWorker Cookbook: https://serviceworke.rs
Slides: github.com/eugenewebdevs/archive/tree/master/2019-06-27-Service-Workers
State of JavaScript 2018: 2018.stateofjs.com
Can I Use Service Workers: caniuse.com/#search=service%20workers
Is Service Worker Ready? jakearchibald.github.io/isserviceworkerready
The ServiceWorker is coming, look busy: youtube.com/watch?v=SmZ9XcTpMS4
ServiceWorkers Outbreak: youtube.com/watch?v=CPP9ew4Co0M
yvesgurcan
By Yves Gurcan
Link to the Meetup event: https://www.meetup.com/eugenewebdevs/events/261941044/. Yves explores what service workers are and how to implement them in your applications. The talk includes use cases, details on the benefits and caveats of using service workers, and info on Workbox (a Google library to facilitate the usage of workers). We also explore the Cache API and how you can create an experience close to (or even better than) native mobile apps with progressive web applications.
Senior software engineer with a passion for developing bleeding edge web applications and event-driven architecture. More talks and resources at https://connect.yvesgurcan.com.