pwaUpdate()
: Application updateOne of the advantages of PWAs over native applications is undoubtedly the updating of the application.
On native applications, on Android for example, you have to go to Google Play Store, go to the profile icon, go to "Manage device applications" then finally press "Update".
This process is not ideal in terms of user experience and this action is often delayed.
With PWAs, even if it's not necessarily a good idea, you can update the application transparently and asynchronously.
The problem with PWA updates
The serviceworker is a javascript file that will serve as a single proxy for all instances of the application. If a tab remains open, the update will not occur, even if the browser has detected it.
In addition, refreshing the application tab will not be enough to trigger the update. For some time, the new instance of the application exists simultaneously in memory alongside the previous one.
You can force the update on the serviceworker side, but this can generate user experience issues, as in the case where the update would be carried out while the user enters his credit card in the conversion tunnel of the application.
Solution proposed by PWA Bunga!
In order to overcome these problems, the pwaUpdate
function will allow:
In order for the function to be functional, these elements must be added to the DOM:
pwa-update
: container of the information insert on the availability of an updatepwa-update-btn
: update buttonpwa-update-close
: inset close buttonpwa-loader
: the 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>
We hide the elements useful to the function
.pwa-update,
.pwa-loader {
display: none;
}
If the element has class is-visible
, we display it
.pwa-update.is-visible,
.pwa-loader.is-visible {
display: block;
}
const pwaUpdate = async () => {
...
}
We set the DOM elements to be manipulated as variables
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')
We set the instance of the serviceworker of the application as a variable, which will be used to detect an update and a change of status
const registration = await navigator.serviceWorker.getRegistration()
We detect if a new serviceworker is available
registration.addEventListener("updatefound", async () => {
if (registration.installing) {
We detect if he is ready to take over
registration.installing.addEventListener('statechange', async () => {
if (registration.waiting) {
If a serviceworker already exists (otherwise it is the first installation of the application), the update box is displayed
if (navigator.serviceWorker.controller) {
pwaUpdateBar.classList.add('is-visible')
}
On click on the update button
pwaUpdateBtn.addEventListener('click', async () => {
We hide the update insert
pwaUpdateBar.classList.remove('is-visible')
We display the loader which will make it possible to bridge the time between the moment when we send the serviceworker the indication to update and the moment when it is updated.
pwaUpdateLoader.classList.add('is-visible')
We indicate to the serviceworker that the user has requested the update by sending a message with the API postMessage
registration.waiting.postMessage('SKIP_WAITING')
When the serviceworker has received the above message, it updates itself (see the PWA Bunga! PWA service worker part for more details on this treatment).
We intercept this moment with the controllerchange
event
and we refresh all open instances of the application
navigator.serviceWorker.addEventListener('controllerchange', () => {
window.location.reload()
})
In the event that for some reason, the user does not update, the update does not take place because other instances of the application are open, the update insert is displayed.
if (registration.waiting) {
pwaUpdateBar.classList.add('is-visible')
}
We hide the update insert when the pwaUpdateClose
button is clicked
pwaUpdateClose.addEventListener('click', () => {
pwaUpdateBar.classList.remove('is-visible')
})
Here is the function call used on pwabunga.js
pwaUpdate()
pwaUpdate
function
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 and PWA install buttonpwaUpdate()
: Application updatepwaShare()
: Using device native sharingpwaParams()
: PWA parameters insert