pwaUpdate()
: Mise à jour de l'applicationUn des avantages des PWA sur les applications natives est sans aucun doute la mise à jour de l'application.
Sur les applications natives, sur Android par exemple, il faut aller dans Google Play Store, aller sur l'icône du profil, aller sur "Gérer les applications de l'appareil" puis enfin appuyer sur "Mettre à jour".
Ce processus n'est pas idéal en terme d'expérience utilisateur et on retarde souvent cette action.
Avec les PWA, même si ça n'est pas forcément une bonne idée, on peut mettre à jour l'application de manière transparente et asynchrone.
Le problème des mises à jour des PWA
Le serviceworker est un fichier javascript qui va servir de proxy unique pour toutes les instances de l'application. Si un onglet reste ouvert, la mise à jour ne se fera pas, même si le navigateur a détecté l'a détecté.
De plus, rafraichir l'onglet de l'application ne suffira pas à enclencher la mise à jour. Pendant un certain temps, la nouvelle instance de l'application existe simultanément dans la mémoire à coté du précédent.
On peut forcer la mise à jour coté serviceworker, mais cela peut générer des soucis d'expérience utilisateur, comme dans le cas où la mise à jour s'effectuerait pendant que l'utilisateur saisi sa carte bancaire dans le tunnel de conversion de l'application.
Solution proposée par PWA Bunga!
Afin de pallier ces problèmes, la fonction pwaUpdate
va permettre :
Afin que la fonction soit fonctionnelle, il faut ajouter ces éléments au DOM :
pwa-update
: contenant de l'encart d'information de la disponibilité d'une mise à jourpwa-update-btn
: bouton de mise à jourpwa-update-close
: bouton de fermeture de l'encartpwa-loader
: le loader
<div class="pwa-update">
<button class="pwa-update-close">Close</button>
{{ content }}
<button class="pwa-update-btn">Install</button>
</div>
<div class="pwa-loader">
{{ loader }}
</div>
On cache les éléments utiles à la fonction
.pwa-update,
.pwa-loader {
display: none;
}
Si l'élément a la classe is-visible
, on l'affiche
.pwa-update.is-visible,
.pwa-loader.is-visible {
display: block;
}
const pwaUpdate = async () => {
...
}
On met en variable les éléments du DOM à manipuler
const pwaUpdateBar = document.querySelector('.pwa-update')
const pwaUpdateBtn = document.querySelector('.pwa-update-btn')
const pwaUpdateClose = document.querySelector('.pwa-update-close')
const pwaUpdateLoader = document.querySelector('.pwa-loader')
On met en variable l'instance du serviceworker de l'application, qui va nous servir à détecter une mise à jour et un changement de statut
const registration = await navigator.serviceWorker.getRegistration()
On détecte si un nouveau serviceworker est disponible
registration.addEventListener("updatefound", async () => {
if (registration.installing) {
On détecte s'il est prêt à prendre le relais
registration.installing.addEventListener('statechange', async () => {
if (registration.waiting) {
S'il existe déjà un serviceworker (sinon il s'agit de la première installation de l'application), on affiche l'encart de mise à jour
if (navigator.serviceWorker.controller) {
pwaUpdateBar.classList.add('is-visible')
}
Au clic sur le bouton de mise à jour
pwaUpdateBtn.addEventListener('click', async () => {
On cache l'encart de mise à jour
pwaUpdateBar.classList.remove('is-visible')
On affiche le loader qui va permettre de combler le laps de temps entre le moment où on envoi au serviceworker l'indication de se mettre à jour et le moment où il est mis à jour.
pwaUpdateLoader.classList.add('is-visible')
On indique au serviceworker que l'utilisateur a demandé la mise à jour en envoyant un message avec l'API postMessage
registration.waiting.postMessage('SKIP_WAITING')
Quand le serviceworker à reçu le message précèdent, il se met à jour (voir la partie PWA Bunga! PWA service worker pour plus de détails sur ce traitement).
On intercepte ce moment avec l'événement controllerchange
et nous rafraichissons toutes les instances de l'application ouvertes
navigator.serviceWorker.addEventListener('controllerchange', () => {
window.location.reload()
})
Dans le cas où pour une raison diverse, l'utilisateur ne fait pas la mise à jour, que la mise à jour ne se fait pas car d'autres instances de l'application sont ouvertes, on affiche l'encart de mise à jour.
if (registration.waiting) {
pwaUpdateBar.classList.add('is-visible')
}
On cache l'encart de mise à jour au click du bouton pwaUpdateClose
pwaUpdateClose.addEventListener('click', () => {
pwaUpdateBar.classList.remove('is-visible')
})
Voici l'appel de la fonction utilisé sur pwabunga.js
pwaUpdate()
pwaUpdate
const pwaUpdate = async () => {
const pwaUpdateBar = document.querySelector('.pwa-update')
const pwaUpdateBtn = document.querySelector('.pwa-update-btn')
const pwaUpdateClose = document.querySelector('.pwa-update-close')
const pwaUpdateLoader = document.querySelector('.pwa-loader')
const registration = await navigator.serviceWorker.getRegistration()
registration.addEventListener("updatefound", async () => {
if (registration.installing) {
registration.installing.addEventListener('statechange', async () => {
if (registration.waiting) {
if (navigator.serviceWorker.controller) {
pwaUpdateBar.classList.add('is-visible')
}
}
})
}
})
pwaUpdateBtn.addEventListener('click', async () => {
pwaUpdateBar.classList.remove('is-visible')
pwaUpdateLoader.classList.add('is-visible')t
registration.waiting.postMessage('SKIP_WAITING')
})
navigator.serviceWorker.addEventListener('controllerchange', () => {
window.location.reload()
})
if (registration.waiting) {
pwaUpdateBar.classList.add('is-visible')
}
pwaUpdateClose.addEventListener('click', () => {
pwaUpdateBar.classList.remove('is-visible')
})
}
pwaInstall()
: Promotion et bouton d'installation de la PWApwaUpdate()
: Mise à jour de l'applicationpwaShare()
: Utilisation du partage natif de l'appareilpwaParams()
: Encart des paramètres de la PWA