使用 Webpack+Workbox 从 App 构建中访问 service worker skipWaiting
Access service worker skipWaiting from within App build with Webpack+Workbox
我有一个使用 Aurelia 构建并使用 Webpack 编译的 PWA,使用生成 sw.js
服务工作者文件的 Workbox 插件。我正在尝试发出 "New version available" 用户通知,以便用户在应用程序中单击 link 时可以激活新版本。
我正在后台成功下载和安装新版本,甚至检测到新版本已准备就绪。但是,当我尝试调用 skipWaiting()
方法以使用新版本强制刷新页面时,它失败了,因为显然我没有正确的范围或对象。
主要问题可能是我无法编辑实际的 sw.js,因为它是自动生成的。这些示例都建议使用 self.skipWaiting();
,但我不知道如何访问该对象。
webpack.config.js
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
<script>
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);
}
</script>
app.js
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();
}});
}
});
});
}
除最后一行 (this.swReg.skipWaiting();
) 外,一切正常。有没有其他人使用过 webpack+workbox 插件并让 skipWaiting 由于用户交互而发生?
您不能在页面上调用它(app.js)。您在 Service Worker 脚本 (service-worker.js) 上调用 self.skipWaiting。
https://developer.mozilla.org/en-US/docs/Web/API/ServiceWorkerGlobalScope/skipWaiting
我终于让它工作了。一个问题是我使用的是旧版本的 workbox-webpack-plugin。当前版本 (4.2) 在 service worker 中包含一个侦听器,可以在消息发布到 worker 时触发 self.skipWaiting()
,如下所示:
newWorker.postMessage({ type: 'SKIP_WAITING' });
但是你必须确保配置有 skipWaiting: false;
并且你使用的是最新版本。
这些说明很不错:
https://developers.google.com/web/tools/workbox/modules/workbox-webpack-plugin
但是,我对 index.ejs 文件中的应用程序和 service worker 实例化之间的内容进行了微调。
webpack.config.js
new GenerateSW({
globPatterns: ['dist/**/*.{html,js,css,woff,woff2,ttf,svg,eot,jpg}'],
swDest: 'sw.js',
clientsClaim: true,
skipWaiting: false,
})),
index.ejs
<script>
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;
});
}
</script>
app.js
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' });
}
});
}
我有一个使用 Aurelia 构建并使用 Webpack 编译的 PWA,使用生成 sw.js
服务工作者文件的 Workbox 插件。我正在尝试发出 "New version available" 用户通知,以便用户在应用程序中单击 link 时可以激活新版本。
我正在后台成功下载和安装新版本,甚至检测到新版本已准备就绪。但是,当我尝试调用 skipWaiting()
方法以使用新版本强制刷新页面时,它失败了,因为显然我没有正确的范围或对象。
主要问题可能是我无法编辑实际的 sw.js,因为它是自动生成的。这些示例都建议使用 self.skipWaiting();
,但我不知道如何访问该对象。
webpack.config.js
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
<script>
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);
}
</script>
app.js
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();
}});
}
});
});
}
除最后一行 (this.swReg.skipWaiting();
) 外,一切正常。有没有其他人使用过 webpack+workbox 插件并让 skipWaiting 由于用户交互而发生?
您不能在页面上调用它(app.js)。您在 Service Worker 脚本 (service-worker.js) 上调用 self.skipWaiting。
https://developer.mozilla.org/en-US/docs/Web/API/ServiceWorkerGlobalScope/skipWaiting
我终于让它工作了。一个问题是我使用的是旧版本的 workbox-webpack-plugin。当前版本 (4.2) 在 service worker 中包含一个侦听器,可以在消息发布到 worker 时触发 self.skipWaiting()
,如下所示:
newWorker.postMessage({ type: 'SKIP_WAITING' });
但是你必须确保配置有 skipWaiting: false;
并且你使用的是最新版本。
这些说明很不错:
https://developers.google.com/web/tools/workbox/modules/workbox-webpack-plugin
但是,我对 index.ejs 文件中的应用程序和 service worker 实例化之间的内容进行了微调。
webpack.config.js
new GenerateSW({
globPatterns: ['dist/**/*.{html,js,css,woff,woff2,ttf,svg,eot,jpg}'],
swDest: 'sw.js',
clientsClaim: true,
skipWaiting: false,
})),
index.ejs
<script>
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;
});
}
</script>
app.js
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' });
}
});
}