Access service worker skipWaiting from within App build with Webpack+Workbox
我有一个使用Aurelia构建并通过Webpack进行编译的PWA,使用了生成
我已经在后台成功下载并安装了新版本,甚至检测到已准备好新版本。但是,当我尝试调用
主要问题可能是我无法编辑实际的sw.js,因为它是自动生成的。这些示例都建议使用
webpack.config.js
1 2 3 4 5 6 7 | new WorkboxPlugin({ globDirectory: './dist', globPatterns: ['**/*.{html,js,css,woff,woff2,ttf,svg,eot,jpg}'], swDest: './dist/sw.js', clientsClaim: true, skipWaiting: false, // because I want to notify the user and wait for response }), |
index.ejs
1 2 3 4 5 6 7 8 9 10 | if ('serviceWorker' in navigator) { navigator.serviceWorker.register('/sw.js') .then(reg => { // make the registration available globally, for access within app window.myServiceWorkerReg = reg; // Check for update on loading the app (is this necessary?) return reg.update(); }) .catch(console.error); } |
app.js
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 | activate() { // listener for service worker update this.swReg = window.myServiceWorkerReg; console.warn('[app.js] ACTIVATE.', this.swReg); this.swReg.addEventListener('updatefound', () => { // updated service worker found in reg.installing! console.warn('[app.js] UPDATE FOUND.', this.swReg); const newWorker = this.swReg.installing; newWorker.addEventListener('statechange', () => { // has the service worker state changed? console.warn('[app.js] STATE HAS CHANGED.', newWorker, newWorker.state); if (newWorker.state === 'installed') { // New service worker ready. // Notify user; callback for user request to load new app myUserMessage({ clickToActivate: () => { // reload fresh copy (do not cache) console.warn('[app.js] Post Action: skipWaiting.'); // this.swReg.postMessage({ action: 'skipWaiting' }); // THIS IS THE LINE THAT FAILS this.swReg.skipWaiting(); }}); } }); }); } |
除最后一行(
我终于知道了。一个问题是我使用的是旧版本的workbox-webpack-plugin。当前版本(4.2)在服务工作者中包含一个侦听器,当向该工作者发布消息时,该侦听器可以触发
1 | newWorker.postMessage({ type: 'SKIP_WAITING' }); |
但是您必须确保配置具有
这些说明非常好:
https://developers.google.com/web/tools/workbox/modules/workbox-webpack-plugin
https://developers.google.com/web/tools/workbox/guides/advanced-recipes#offer_a_page_reload_for_users
但是,我在index.ejs文件中调整了应用程序和服务工作者实例之间的正常工作。
webpack.config.js
1 2 3 4 5 6 | new GenerateSW({ globPatterns: ['dist/**/*.{html,js,css,woff,woff2,ttf,svg,eot,jpg}'], swDest: 'sw.js', clientsClaim: true, skipWaiting: false, })), |
index.ejs
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 | if ('serviceWorker' in navigator) { // register the service worker navigator.serviceWorker.register('/sw.js') .then(reg => { window.myWorkerReg = reg; // Check for update on loading the app (is this necessary?) return reg.update(); }) .catch(console.error); // The event listener that is fired when the service worker updates navigator.serviceWorker.addEventListener('controllerchange', function () { // when the service worker controller is changed, reload the page if (window.swRefreshing) return; window.location.reload(); window.swRefreshing = true; }); } |
app.js
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 | activate() { // listener for service worker update this.swReg = window.myWorkerReg; if (this.swReg) { // if there is already a new service worker ready to install, prompt user if (this.swReg.waiting) { this.promptUpdateServiceWorker(this.swReg.waiting); } // add listener to detect when a new service worker is downloaded this.swReg.addEventListener('updatefound', () => { // updated service worker is being installed const newWorker = this.swReg.installing; // add listener to detect when installation is finished newWorker.addEventListener('statechange', () => { if (newWorker.state === 'installed') { // New service worker ready to activate; prompt user this.promptUpdateServiceWorker(newWorker); } }); }); } } // listener for buildVersion buildVersionChanged(buildVersion) { // through proprietary code, we've detected a new version could be downloaded now window.myWorkerReg.update(); } // New service worker ready. Show the notification promptUpdateServiceWorker(newWorker) { // actual code for UI prompt will vary; this is pseudocode uiPrompt('New_version_ready').then((response) => { if (response.approved) { // reload fresh copy (do not cache) newWorker.postMessage({ type: 'SKIP_WAITING' }); } }); } |
您无法在页面(app.js)上调用它。您可以在Service Worker脚本(service-worker.js)上调用self.skipWaiting。
https://developer.mozilla.org/zh-CN/docs/Web/API/ServiceWorkerGlobalScope/skipWaiting