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

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

我正尝试在我的 Angular 应用程序中使用 service-worker。它是使用 webpack 构建的。

我使用 workbox-webpack-plugin。我想提供我的 GET API 调用表单缓存并在后台更新数据。

为此,我将选项 runtimeCaching 与处理程序 staleWhileRevalidate (more details on GenerateSW plugin here)

一起使用

这是我在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: [],
        },
      }
    ]
  }),

根据this documentation,我应该能够在更新缓存时接收到一个事件(我想向用户显示一些东西以便他可以刷新数据)。

接收数据的代码如下所示:

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

我将此代码放入我的 Angular 组件之一,即使我确定缓存已更新,它也从未被调用。

我认为这可能与 Angular () 中更改检测的工作方式有关,但我不确定如何修复它。

有没有人设法成功收听来自 Angular 组件的广播事件?

很难找到工作箱文档的解决方案。

在您的应用程序启动时,您可以注册到 workbox 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);
      });
  });
}

当工作箱检测到当前缓存版本与存储在服务器上的版本(存储为 precache-manifest.d6104197c4431d9f111e4c4f0bdf858d.js 中的散列)之间存在差异时触发。

为了检测接收到并准备加载文件的实际更新,我无法按照文档中的描述选择 broadcastUpdate 选项,因此受到它的启发,我在 webpack 和我的应用程序之间实现了一个 MessageChannel。

在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]);
                    });
                  });
                }
              }
            ]
          }
        }
      ]
    })

这会将消息从我不知道的位置发送到频道。然后我们可以在应用程序的那个频道上添加一个监听器来触发ou UI.

在应用程序中:

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