Did you know that you can navigate the posts by swiping left and right?
Foreword: Service workers in production require https, for good reason. You intercept network requests, and serve back what you want, so https is needed for security. You can get away with not having it on localhost.
The application (app) shell is the bare minimum needed to load your web application to a user. For my personal site that means the index page, js file and css file.
This application shell is cached by the service worker when it installs. This means that it can be loaded very quickly on subsequent requests, even with poor or no connection.
The actual content, within a proper web application will then be loaded asynchronously. This allows for a more native mobile application UX, as a native app will load instantly, with all the colours, branding etc, but will loaded the “content” when it’s ready.
source: https://codelabs.developers.google.com/codelabs/your-first-pwapp/
To achieve this we will need to write a small amount code.
2 files are needed. One to register a service worker and another to hold the service worker implementation.
/***** Service Worker Registration ****/
if ('serviceWorker' in navigator) { // Be "Progressive", check that the browser can use the sw.
navigator.serviceWorker.register('/sw.js', {
scope: '/'
}).then(function (registration) {
// Registration was successful :)
console.log('ServiceWorker registration successful with scope: ', registration.scope);
reg = registration;
}).catch(function (err) {
// registration failed :(
console.log('ServiceWorker registration failed: ', err);
});
}
Few things to clear up here.
Now let’s build the service worker itself:
var self = this,
version = 31;
//************ App Shell & Versioning ************/
// These cache names need incrementing on changes happening, make part of a build script.
var cacheName = 'danCodeMonkeyV' + version,
appShellFiles = [
"/",
"/assets/prod/all.min.js",
"/assets/prod/all.min.css"
];
self.addEventListener('install', function (e) {
console.log('Started', self);
function onInstall() {
return caches.open(cacheName)
.then(function (cache) {
cache.addAll(appShellFiles); // Atomic, one fails, it all fails
}).then(self.skipWaiting()); // Older service workers will cause this one to "wait". This skips the waiting stage.
}
e.waitUntil(onInstall(e));
});
//************ Destroy old caches ************/
self.addEventListener('activate', function (e) {
console.log('[ServiceWorker] Activate');
e.waitUntil(caches.keys().then(function (keyList) {
// Flushing the old cache here
// As it's a static site, a post is the only change, which also updates the index, therefore
// updating the cache name via versioning will remove the old cache and replace with the new.
return Promise.all(keyList.map(function (key) {
console.log('[ServiceWorker] Removing old cache', key);
if (key !== cacheName) {
return caches.delete(key);
}
}));
}));
});
There is a lot going on here. I could have broken it down into separate functions and wrote about each, but then I thought when I was learning this I wanted a complete working example so I could mess with it. Also I didn’t want to piss off the copy and paste warriors.
Now for the stuff you actually want to know, the gotchas!
If you’re doing the workshop the code here will help with completing 001_AppShell
Workshop code: https://github.com/DanTheNorthernCodeMonkey/ProgressiveWebAppsQuest