One off the most prometting technology that show up these last year are Progressive Web Apps(PWA). No more pain for building an app per mobile store, each with their constraint and specificity (store rules, language, platform limitation, ect), your website IS your application, and it work (at this time) in a lots of Androids and latest iOs (https://caniuse.com/#feat=serviceworkers)
But even is this tech is awesome, it is easy to get lost when you want to build your own PWA, due to his youth, there are not so much tuturials or even solutions on stackOverflow.
What will you learn
- Build a PWA
- Use ServiceWorker
- Use Offline fonctionality
What you will not learn
- Use of framework like Workbox.js
- Ultimate answer of life, universe and everything else (sorry !)
Let's start
Requirements
To make a mobile client install a pwa, (with a native popup on android for exemple), you neede to achieve some requierements :
- Your site must be on HTTPS
- Have a valid webmanifest
- Register a service worker
HTTPS
I'm not going to explain how to set your site on https, sevrals tuto already exist on this subject, but if your goal is just to discover and test PWA, this part is not required is you local server use http://localhost/
on chrome as multiple security check are turn off on this url like https requirement for service worker !
Webmanifest
One easy thing to do, is to implement a correct webmanifest to tell navigator you have an PWA ! so let's do it
<!-- in your html head -->
<link rel="manifest" href="/manifest.json">
// in /manifest.json
{
"short_name": "PWA",
"name": "My first PWA",
"icons": [
{
"src": "/images/icons-192.png",
"type": "image/png",
"sizes": "192x192"
},
{
"src": "/images/icons-512.png",
"type": "image/png",
"sizes": "512x512"
}
],
"start_url": "/?source=pwa",
"background_color": "#000000",
"display": "standalone",
"scope": "/",
"theme_color": "#FFFFFF"
}
There aren't so mch things to say here, except that name
(or short_name
), icons
, start_url
and display
are required.
You can find more information on webmanifest for PWA here : https://developers.google.com/web/fundamentals/web-app-manifest/
Service Worker
This is it, heart of any PWA, a Service Worker(SW) but you can be wondering what is it and what it do ?
- It's a Javascript worker so it can receive instruction, even when your PWA or navigator is closed.
- Act as a fully configurable network proxy, to handle offline case.
One thing to know about SW is it's heavily rely on promise
, so if you don't understand it, I advise you to learn a little about it !
Register a SW
<script type="text/javascript">
if ('serviceWorker' in navigator) {
navigator.serviceWorker.register('/sw.js', {'scope': '/').then(function(registration) {
// Registration was successful
console.log('ServiceWorker registration successful with scope: ', registration.scope);
}, function(err) {
// registration failed :(
console.log('ServiceWorker registration failed: ', err);
});
}
</script>
Just put it a before </body>
for exemple
This is a basic SW registration, we test if navigator support fonctionnality then we just add it to client. Pretty simple no ?
Scope of service worker is important ! If it's at site root, it can listen to any request from anyhere in your site, but if it's in /assets/
it will only listen to request comming from /assets/*
pages.
Lifecycle
SW have an "Apps" like life cycle, let's see it.
One off most important thing to reminder is that Service Worker is active beyond your website tabs, it's directly executed in browser so it's still alive and ready when an user close your site, permitting him to received push notification or content sync at anytime !
Let's begin
Now that everything is ready, let's code your first service worker with basic installation
//sw.js
const cacheName = 'my-cache';
const filesList = [
'/assets/style.css',
'/assets/main.js'
];
self.addEventListener('install', (event) => {
event.waitUntil(
caches.open(cacheName)
// Add your file to cache
.then( (cache) => {
return cache.addAll(filesList);
})
// Tell SW to end 'waiting' state
.then(() => self.skipWaiting())
);
})
self.addEventListener('activate', (event) => {
event.waitUntil(
// tell browser to use this service worker and not outdated one
self.clients.claim()
);
})
To see if your SW have corectly installed, on chrome for exemple, open DevTools and go in Application tab, you should see something like this :
PWA
Now that your first SW is ready, let's upgrade it to a pwa, and to achieve this goal, we only need to make your Service Worker respond with something, like a generic offline page, when we aren't online.
const cacheName = 'my-cache';
const offlinePage = '/offline.html';
const filesList = [
'/assets/style.css',
'/assets/main.js',
offlinePage
];
self.addEventListener('install', (event) => {
event.waitUntil(
caches.open(cacheName)
// Add your file to cache
.then( (cache) => {
return cache.addAll(filesList);
})
// Tell SW to end 'waiting' state
.then(() => self.skipWaiting())
);
})
self.addEventListener('activate', (event) => {
event.waitUntil(
// Tell browser to use this service worker and not outdated one
self.clients.claim()
);
})
self.addEventListener('fetch', (event) => {
// If we don't have internet connection and it's a navigation request
if (!navigator.onLine && event.request.mode === 'navigate') {
event.respondWith( caches.open(cacheName)
.then( (cache) => {
// If we find our offline page in cache, respond with it
return cache.match(offlinePage)
.then( (response) => response);
})
);
} else {
// Return null let browser do his normal behavior
return;
}
So we just add on more file to get cached at beginning and a fetch
listener. For those who wonder, this transform your SW into a local proxy, so every request comming from your website will be catch by your Service Worker and processed before doing anything (like let request pass or directly respond with a cached file).
Enjoy
Your first PWA is now ready to use ! for those who just want a fast try, I make a fully fonctionnal github.
PWA tutorial
Here you can easily test PWA basic,
install
Get repo in local and go on index.html. wait for service worker to install then cut your internet connection and try to reload page
PS: don't forgetted to be on https or on http://localhost on chrome
Top comments (0)