简体   繁体   English

workbox-webpack-plugin&Angular。 如何在Angular中收听broadcastUpdate事件

[英]workbox-webpack-plugin & Angular. How to listen to broadcastUpdate event in Angular

I'm trying to use service-worker with my Angular Application. 我正在尝试将服务工作者与我的Angular应用程序一起使用。 It is build using webpack. 它是使用webpack构建的。

I use workbox-webpack-plugin. 我使用workbox-webpack-plugin。 I want to serve my GET API calls form cache and in the background update the data. 我想提供我的GET API调用表单缓存并在后台更新数据。

FOr this, I use the option runtimeCaching with the handler staleWhileRevalidate ( more details on GenerateSW plugin here ) 对此,我使用runtimeCaching选项和处理程序staleWhileRevalidate有关GenerateSW插件的更多详细信息

This is the config I have in webpack.config.js: 这是我在webpack.config.js中的配置:

  new GenerateSW({
    // importWorkboxFrom: 'local',
    clientsClaim: true,
    skipWaiting: true,
    navigateFallback: '/index.html',
    runtimeCaching: [
      {
        // Match any same-origin request that contains 'api'.
        urlPattern: /https:\/\/api.*/,
        handler: 'staleWhileRevalidate',
        options: {
          cacheName: 'api',
          broadcastUpdate: {
            channelName: 'api-updates',
          },
          // Add in any additional plugin logic you need.
          plugins: [],
        },
      }
    ]
  }),

According to this documentation , I should be able to receive an event when the cache is updated (I want to display something to the user so he can refresh the data). 根据此文档 ,我应该能够在更新缓存时收到一个事件(我想向用户显示一些内容,以便他可以刷新数据)。

The code to receive the data look like this: 接收数据的代码如下所示:

export class AppComponent implements OnInit {

  public ngOnInit() {
    console.log( 'AppComponent - ngOnInit' );

    const updatesChannel = new BroadcastChannel('api-updates');
    updatesChannel.addEventListener('message', async (event) => {
      console.log('Event received');
    });
  }
}

I put this code inside one of my Angular component, it never got called even if I'm sure that the cache was updated. 我将此代码放在我的一个Angular组件中,即使我确定缓存已更新,它也永远不会被调用。

I think it might have something to do with how change detection works in Angular ( like described in this question ) but I'm not sure how to fix it. 我认为它可能与Angular中的变化检测如何工作有关( 如本问题所述 ),但我不确定如何解决它。

Did anyone manage to successfully listen to broadcast event from Angular component ? 有没有人设法成功收听Angular组件的广播事件?

Had difficulties finding a solution with workbox documentation. 难以找到工作箱文档的解决方案。

On start of you app, you can register to workbox serviceworker and override onupdatefound update the UI when detecting a change and loading it: 在应用程序启动时,您可以注册到onupdatefound serviceworker并覆盖onupdatefound ,在检测到更改并加载时更新UI:

if (process.env.NODE_ENV != "development" && "serviceWorker" in navigator) {
  window.addEventListener("load", () => {
    navigator.serviceWorker
      .register("/service-worker.js")
      .then(registration => {
        registration.onupdatefound = event => {
          console.log("An update has been detected. Workbox will now download the newest version, then send a notification.");
        };
      })
      .catch(registrationError => {
        console.log("SW registration failed: ", registrationError);
      });
  });
}

This is triggered when workbox detect difference between current cached version and the one stored on server (stored as a hash in precache-manifest.d6104197c4431d9f111e4c4f0bdf858d.js ). 当工作箱检测当前缓存版本与存储在服务器上的版本之间的差异(在precache-manifest.d6104197c4431d9f111e4c4f0bdf858d.js存储为散列)时,会触发此操作。

To detect the actual update with files received and ready to load, I couldn't make the option broadcastUpdate as described in documentation so inspired by it I implemented a MessageChannel between webpack and my app. 为了检测接收到的文件并准备加载的实际更新,我无法按照文档中的描述制作选项broadcastUpdate ,因此我在webpack和我的应用程序之间实现了一个MessageChannel。

In webpack: 在webpack中:

new WorkboxPlugin.GenerateSW({
      // these options encourage the ServiceWorkers to get in there fast
      // and not allow any straggling 'old' SWs to hang around
      clientsClaim: true,
      skipWaiting: true,
      include: [
        /\.html$/,
        /\.js$/,
        /\.jpg$/,
        /\.svg$/,
        /\.png$/,
        /\.json$/,
        /\.xml$/
      ],
      runtimeCaching: [
        {
          urlPattern: /./,
          handler: "StaleWhileRevalidate",
          options: {
            // Add in any additional plugin logic you need.
            plugins: [
              {
                cacheDidUpdate: event => {
                  clients.matchAll().then(clients => {
                    clients.forEach(client => {
                      var msg_chan = new MessageChannel();
                      client.postMessage("APP_UPDATE", [msg_chan.port2]);
                    });
                  });
                }
              }
            ]
          }
        }
      ]
    })

This will send a message from I don't know where to a channel. 这将发送一条消息,我不知道通道在哪里。 We can then add a listenner on that channel in app to trigger ou UI. 然后,我们可以在应用中的该频道上添加一个监听器来触发您的UI。

In app : 在app中:

if ("serviceWorker" in navigator) {
  navigator.serviceWorker.addEventListener("message", event => {
    if (event.data == "APP_UPDATE") {
      dispatch(AppActions.cacheDidUpdate());
    }
  });
}

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM