使用Webpack + Workbox从App内部访问服务工作者skipWaiing [英] Access service worker skipWaiting from within App build with Webpack+Workbox

查看:72
本文介绍了使用Webpack + Workbox从App内部访问服务工作者skipWaiing的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我有一个使用Aurelia构建并通过Webpack进行编译的PWA,使用了生成 sw.js 服务工作程序文件的Workbox插件.我正在尝试使新版本可用"用户通知,以便用户在单击应用程序内的链接时可以激活新版本.

I have a PWA built with Aurelia and compiled with Webpack, using the Workbox Plugin that generates the sw.js service worker file. I'm trying to make the "New version available" user notification so that the user can activate the new version when clicking on a link within the app.

我已经在后台成功下载并安装了新版本,甚至检测到已准备好新版本.但是,当我尝试调用 skipWaiting()方法以使用新版本强制刷新页面时,它失败了,因为显然我没有正确的范围或对象.

I am successfully downloading and installing the new version in the background, and even detecting that a new version is ready. However, when I try to call the skipWaiting() method to force refresh of the page with the new version, it fails, because apparently I don't have the right scope or object.

主要问题可能是我无法编辑实际的sw.js,因为它是自动生成的.这些示例都建议使用 self.skipWaiting(); ,但是我不知道如何访问该对象.

The main problem is probably that I can't edit the actual sw.js because it is automatically generated. The examples all suggest the use of self.skipWaiting();, but I don't know how to access that object.

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吗?

Everything works fine except the last line (this.swReg.skipWaiting();). Has anyone else used webpack+workbox plugin and gotten the skipWaiting to happen as a result of user interaction?

推荐答案

我终于使它起作用了.一个问题是我使用的是旧版本的workbox-webpack-plugin.当前版本(4.2)在服务工作者中包含一个侦听器,当向该工作者发布消息时,该侦听器可以触发 self.skipWaiting():

I finally got it to work. One problem was that I was using an older version of workbox-webpack-plugin. The current version (4.2) includes a listener in the service worker that can trigger self.skipWaiting() when a message is posted to the worker like this:

newWorker.postMessage({ type: 'SKIP_WAITING' });

但是您必须确保配置具有 skipWaiting:false; ,并且您使用的是最新版本.

But you have to ensure that the config has skipWaiting: false; and that you are using the latest version.

这些说明非常好:

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文件中的服务工作者实例之间的工作.

However, I tweaked things to work well between my App and the service worker instantiation in the index.ejs file.

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

这篇关于使用Webpack + Workbox从App内部访问服务工作者skipWaiing的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆