en 2018
Vincent Ogloblinsky
Frontend software architect
Agenda
2.
Caractéristiques
3.
Outils
4.
Avantages / inconvénients
5.
Erreurs à éviter
1.
Contexte
Contexte
Caractéristiques
FIRE
Fast
Integrated
Reliable
Engaging
Fast
Integrated
Reliable
Engaging
Support OS
Support OS
Support OS
Support OS
Support OS
Les 3 caractéristiques techniques
App shell
Manifest
Service worker
App shell
Manifest
{
"name": "Funny App",
"short_name": "Funny App",
"lang": "fr-FR",
"start_url": "/",
"display": "fullscreen",
"theme_color": "#3c3c3c"
}
<link rel="manifest" href="manifest.json">
<meta name="mobile-web-app-capable" content="yes">
<meta name="apple-mobile-web-app-capable" content="yes">
<meta name="application-name" content="Funny App">
<meta name="apple-mobile-web-app-title" content="Funny App">
<meta name="theme-color" content="#3c3c3c">
<meta name="msapplication-navbutton-color" content="#3c3c3c">
<meta name="apple-mobile-web-app-status-bar-style" content="black-translucent">
<meta name="msapplication-starturl" content="/">
<meta name="viewport" content="width=device-width, initial-scale=1, shrink-to-fit=no">
Manifest
En développement pour Firefox et Safari
Service worker
Script exécuté en background
Offline
Notifications
Service worker
Service worker
Service worker
Service worker
Service worker
Parsed
/* In main.js */
if ('serviceWorker' in navigator) {
navigator.serviceWorker.register('./sw.js')
.then(function(registration) {
console.log("Service Worker Registered", registration);
})
.catch(function(err) {
console.log("Service Worker Failed to Register", err);
})
}
Service worker
Installing
/* In main.js */
navigator.serviceWorker.register('./sw.js').then(function(registration) {
if (registration.installing) {
// Service Worker is Installing
}
})
/* In sw.js */
self.addEventListener('install', function(event) {
event.waitUntil(
caches.open(currentCacheName).then(function(cache) {
return cache.addAll(arrayOfFilesToCache);
})
);
})
Service worker
Installed / waiting
/* In main.js */
navigator.serviceWorker.register('./sw.js').then(function(registration) {
if (registration.waiting) {
// Service Worker is Waiting
}
})
Service worker
Activating
/* In sw.js */
self.addEventListener('activate', function(event) {
event.waitUntil(
// Get all the cache names
caches.keys().then(function(cacheNames) {
return Promise.all(
// Get all the items that are stored under a different
// cache name than the current one
cacheNames.filter(function(cacheName) {
return cacheName != currentCacheName;
}).map(function(cacheName) {
// Delete the items
return caches.delete(cacheName);
})
); // end Promise.all()
}) // end caches.keys()
); // end event.waitUntil()
});
Service worker
Activated
/* In main.js */
navigator.serviceWorker.register('./sw.js').then(function(registration) {
if (registration.active) {
// Service Worker is Active
}
})
/* In sw.js */
self.addEventListener('fetch', function(event) {
// Do stuff with fetch events
});
self.addEventListener('message', function(event) {
// Do stuff with postMessages received from document
});
Service worker
Stratégies de cache : network only
Cas d'usage : ce qui ne peut être mis en cache
self.addEventListener('fetch', function(event) {
event.respondWith(fetch(event.request));
// or simply don't call event.respondWith, which
// will result in default browser behaviour
});
Stratégies de cache : cache only
Cas d'usage : ce qui ne change pas souvent
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));
});
Stratégies de cache : cache fallback to network
Cas d'usage : si la fraîcheur n'est pas primordiale
self.addEventListener('fetch', function(event) {
event.respondWith(
caches.match(event.request).then(function(response) {
return response || fetch(event.request);
})
);
});
Stratégies de cache : network fallback to cache
Cas d'usage : si la fraîcheur est primordiale
self.addEventListener('fetch', function(event) {
event.respondWith(
fetch(event.request).catch(function() {
return caches.match(event.request);
})
);
});
Stratégies de cache : cache then network
Cas d'usage : si la fraîcheur est primordiale
self.addEventListener('fetch', function(event) {
event.respondWith(
caches.open('mysite-dynamic').then(function(cache) {
return fetch(event.request).then(function(response) {
cache.put(event.request, response.clone());
return response;
});
})
);
});
Stratégies de cache : generic fallback
Cas d'usage : contenu secondaire
self.addEventListener('fetch', function(event) {
event.respondWith(
// Try the cache
caches.match(event.request).then(function(response) {
// Fall back to network
return response || fetch(event.request);
}).catch(function() {
// If both fail, show a generic fallback:
return caches.match('/offline.html');
// However, in reality you'd have many different
// fallbacks, depending on URL & headers.
// Eg, a fallback silhouette image for avatars.
})
);
});
Service worker
Outils
Audit : Lighthouse
Debug : Devtools
Manifest
PWA Feature detector
Setup : Workbox
- ensemble de librairies pour mettre en place l'offline
- configuration des stratégies de cache
Setup : framework module
@angular/service-worker
@vue/cli-plugin-pwa
...
Frameworks : HNPWA
Outil : GoodBarber
Avantages
Inconvénients
Avantages
Inconvénients
- coût
- technologies jeunes
- compatibilité (iOS / Android)
- limitations hardwares
- sécurité
- authentification partagée impossible
- légitimité utilisateurs
Erreurs à
éviter
Erreurs à éviter
- application lourde et lente
- UI lourde
- négliger les service workers
- ! au offline
News
Chrome 70 : Desktop PWAs on Windows, Linux et macOS avec Chrome 72 début 2019
Windows 10 supports for PWA in store
Merci
Des questions ?
Slides : bit.ly/pwa-in-2018
PWA in 2018
By Vincent Ogloblinsky
PWA in 2018
- 2,488