问题
I'm trying to use service-worker with my Angular Application. It is build using webpack.
I use workbox-webpack-plugin. I want to serve my GET API calls form cache and in the background update the data.
FOr this, I use the option runtimeCaching
with the handler staleWhileRevalidate
(more details on GenerateSW plugin here)
This is the config I have in 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.
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.
Did anyone manage to successfully listen to broadcast event from Angular component ?
回答1:
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:
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
).
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.
In 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.
In app :
if ("serviceWorker" in navigator) {
navigator.serviceWorker.addEventListener("message", event => {
if (event.data == "APP_UPDATE") {
dispatch(AppActions.cacheDidUpdate());
}
});
}
来源:https://stackoverflow.com/questions/51657007/workbox-webpack-plugin-angular-how-to-listen-to-broadcastupdate-event-in-angu