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);
+};