5

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

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

为此,我将选项runtimeCaching与处理程序一起使用staleWhileRevalidate有关 GenerateSW 插件的更多详细信息,请点击此处

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

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

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

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 组件的广播事件?

4

1 回答 1

2

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

在您的应用程序启动时,您可以注册到 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());
    }
  });
}
于 2019-07-03T05:59:48.223 回答