diff --git a/gulp/tasks/gen-index-html.js b/gulp/tasks/gen-index-html.js index 5525c5fd36..a8a1d4951d 100644 --- a/gulp/tasks/gen-index-html.js +++ b/gulp/tasks/gen-index-html.js @@ -23,10 +23,6 @@ function generateIndex(es6) { ]; if (!es6) { - toReplace.push([ - '/service_worker.js', '/service_worker_es5.js' - ]); - const compatibilityPath = `/frontend_es5/compatibility-${md5(path.resolve(config.output_es5, 'compatibility.js'))}.js`; const es5Extra = ` diff --git a/index.html b/index.html index 6de893b334..dfad638741 100644 --- a/index.html +++ b/index.html @@ -90,11 +90,6 @@ document.write(e.outerHTML); }()); } - if ('serviceWorker' in navigator) { - window.addEventListener('load', function () { - navigator.serviceWorker.register('/service_worker.js'); - }); - } diff --git a/src/entrypoints/app.js b/src/entrypoints/app.js index 2134b65ade..f76027bc6d 100644 --- a/src/entrypoints/app.js +++ b/src/entrypoints/app.js @@ -8,6 +8,7 @@ import '@polymer/paper-styles/typography.js'; import { html } from '@polymer/polymer/lib/utils/html-tag.js'; import { setPassiveTouchGestures } from '@polymer/polymer/lib/utils/settings.js'; import { PolymerElement } from '@polymer/polymer/polymer-element.js'; +import { afterNextRender } from '@polymer/polymer/lib/utils/render-status.js'; import LocalizeMixin from '../mixins/localize-mixin.js'; @@ -26,6 +27,7 @@ import '../util/legacy-support'; import '../util/roboto.js'; import hassCallApi from '../util/hass-call-api.js'; import makeDialogManager from '../dialogs/dialog-manager.js'; +import registerServiceWorker from '../util/register-service-worker.js'; import computeStateName from '../common/entity/compute_state_name.js'; import applyThemesOnElement from '../common/dom/apply_themes_on_element.js'; @@ -107,6 +109,7 @@ class HomeAssistant extends LocalizeMixin(PolymerElement) { this.addEventListener('settheme', e => this.setTheme(e)); this.addEventListener('hass-language-select', e => this.selectLanguage(e)); this.loadResources(); + afterNextRender(null, registerServiceWorker); } computeShowMain(hass) { diff --git a/src/entrypoints/service-worker-hass.js b/src/entrypoints/service-worker-hass.js index f8edefa27c..b20ac7a2a0 100644 --- a/src/entrypoints/service-worker-hass.js +++ b/src/entrypoints/service-worker-hass.js @@ -111,11 +111,16 @@ function initPushNotifications() { }); } +self.addEventListener('message', (message) => { + if (message.data.type === 'skipWaiting') { + self.skipWaiting(); + clients.claim(); + } +}); + workbox.setConfig({ debug: __DEV__ }); -workbox.skipWaiting(); -workbox.clientsClaim(); if (!__DEV__) { initRouting(); diff --git a/src/util/register-service-worker.js b/src/util/register-service-worker.js new file mode 100644 index 0000000000..1e241736be --- /dev/null +++ b/src/util/register-service-worker.js @@ -0,0 +1,25 @@ +const serviceWorkerUrl = __BUILD__ === 'latest' ? + '/service_worker.js' : '/service_worker_es5.js'; + +export default () => { + if (!('serviceWorker' in navigator)) return; + + navigator.serviceWorker.register(serviceWorkerUrl).then((reg) => { + reg.addEventListener('updatefound', () => { + const installingWorker = reg.installing; + installingWorker.addEventListener('statechange', () => { + if (installingWorker.state === 'installed' && + navigator.serviceWorker.controller && + !__DEV__) { + // Notify users here of a new frontend being available. + import('./show-new-frontend-toast.js').then(mod => mod.default(installingWorker)); + } + }); + }); + }); + + // If the active service worker changes, refresh the page because the cache has changed + navigator.serviceWorker.addEventListener('controllerchange', () => { + location.reload(); + }); +}; diff --git a/src/util/show-new-frontend-toast.js b/src/util/show-new-frontend-toast.js new file mode 100644 index 0000000000..cdaf4d193b --- /dev/null +++ b/src/util/show-new-frontend-toast.js @@ -0,0 +1,19 @@ +import '@polymer/paper-toast/paper-toast.js'; +import '@polymer/paper-button/paper-button.js'; + +export default (installingWorker) => { + const toast = document.createElement('paper-toast'); + toast.opened = true; + toast.text = 'A new version of the frontend is available.'; + toast.duration = 0; + + const button = document.createElement('paper-button'); + button.addEventListener('click', () => + installingWorker.postMessage({ type: 'skipWaiting' })); + button.style.color = 'var(--primary-color)'; + button.style.fontWeight = 'bold'; + button.innerHTML = 'reload'; + toast.appendChild(button); + + document.body.appendChild(toast); +};