A service worker helper library that uses the Broadcast Channel API to announce when a cached response has updated
npx @tessl/cli install tessl/npm-workbox-broadcast-update@7.3.0A service worker helper library that uses the Broadcast Channel API to announce when a cached response has been updated. This library enables applications to automatically notify users when cached content is refreshed, providing real-time feedback about content freshness in cache-first strategies.
npm install workbox-broadcast-updateimport {
BroadcastCacheUpdate,
BroadcastCacheUpdateOptions,
BroadcastUpdatePlugin,
responsesAreSame
} from "workbox-broadcast-update";For CommonJS:
const {
BroadcastCacheUpdate,
BroadcastUpdatePlugin,
responsesAreSame
} = require("workbox-broadcast-update");import { BroadcastUpdatePlugin } from "workbox-broadcast-update";
import { StaleWhileRevalidate } from "workbox-strategies";
// Use as a plugin with Workbox strategies
const strategy = new StaleWhileRevalidate({
cacheName: "api-cache",
plugins: [
new BroadcastUpdatePlugin({
headersToCheck: ["etag", "last-modified"],
}),
],
});
// Direct usage for manual cache updates
import { BroadcastCacheUpdate } from "workbox-broadcast-update";
const broadcastUpdate = new BroadcastCacheUpdate({
headersToCheck: ["content-length", "etag"],
notifyAllClients: true,
});
await broadcastUpdate.notifyIfUpdated({
cacheName: "my-cache",
oldResponse,
newResponse,
request,
event,
});Workbox Broadcast Update is built around several key components:
The library uses header comparison rather than full response body comparison for efficiency, making it suitable for high-traffic applications.
Core functionality for detecting and broadcasting cache updates using the Broadcast Channel API.
class BroadcastCacheUpdate {
/**
* Creates a new BroadcastCacheUpdate instance
* @param options - Configuration options for the broadcast update behavior
*/
constructor(options?: BroadcastCacheUpdateOptions);
/**
* Compares two responses and broadcasts an update message if they differ
* @param options - Parameters containing old/new responses and cache metadata
* @returns Promise that resolves when broadcast is complete
*/
notifyIfUpdated(options: CacheDidUpdateCallbackParam): Promise<void>;
}
interface BroadcastCacheUpdateOptions {
/** Headers to check for differences (default: ['content-length', 'etag', 'last-modified']) */
headersToCheck?: string[];
/** Custom function to generate message payload */
generatePayload?: (options: CacheDidUpdateCallbackParam) => Record<string, any>;
/** Whether to notify all clients or just the requesting client (default: true) */
notifyAllClients?: boolean;
}
interface CacheDidUpdateCallbackParam {
/** Name of the cache being updated */
cacheName: string;
/** The previous cached response */
oldResponse?: Response;
/** The new response being cached */
newResponse: Response;
/** The request that triggered the update */
request: Request;
/** The event that triggered the update */
event?: ExtendableEvent;
}Plugin that automatically broadcasts cache updates when integrated with Workbox caching strategies.
class BroadcastUpdatePlugin implements WorkboxPlugin {
/**
* Creates a new BroadcastUpdatePlugin instance
* @param options - Configuration options passed to internal BroadcastCacheUpdate
*/
constructor(options?: BroadcastCacheUpdateOptions);
/**
* Workbox plugin lifecycle method triggered when cache entries are updated
* @param options - Cache update parameters from Workbox
*/
cacheDidUpdate: WorkboxPlugin['cacheDidUpdate'];
}
interface WorkboxPlugin {
cacheDidUpdate?: (param: CacheDidUpdateCallbackParam) => Promise<void> | void;
}Utility function for comparing Response objects based on specific headers.
/**
* Compares two Response objects by checking specified headers
* @param firstResponse - First response to compare
* @param secondResponse - Second response to compare
* @param headersToCheck - Array of header names to check for differences
* @returns True if responses are considered the same, false otherwise
*/
function responsesAreSame(
firstResponse: Response,
secondResponse: Response,
headersToCheck: string[]
): boolean;Configuration interface for BroadcastCacheUpdate behavior.
interface BroadcastCacheUpdateOptions {
/** Headers to check for differences (default: ['content-length', 'etag', 'last-modified']) */
headersToCheck?: string[];
/** Custom function to generate message payload */
generatePayload?: (options: CacheDidUpdateCallbackParam) => Record<string, any>;
/** Whether to notify all clients or just the requesting client (default: true) */
notifyAllClients?: boolean;
}When a cache update is detected, the library broadcasts a message with the following structure:
interface BroadcastMessage {
/** Always 'CACHE_UPDATED' */
type: "CACHE_UPDATED";
/** Always 'workbox-broadcast-update' */
meta: "workbox-broadcast-update";
/** Update details - customizable via generatePayload option */
payload: {
/** Name of the updated cache */
cacheName: string;
/** URL of the updated resource */
updatedURL: string;
/** Additional custom fields from generatePayload function */
[key: string]: any;
};
}The library includes built-in error handling for common scenarios:
WorkboxError for non-Response objects in developmentcacheName, newResponse, and request parameterstrue (no update) when none of the specified headers are presentimport { BroadcastUpdatePlugin } from "workbox-broadcast-update";
import { registerRoute } from "workbox-routing";
import { StaleWhileRevalidate } from "workbox-strategies";
// Register a route with automatic broadcast updates
registerRoute(
({ request }) => request.destination === "document",
new StaleWhileRevalidate({
cacheName: "pages-cache",
plugins: [
new BroadcastUpdatePlugin({
headersToCheck: ["etag", "last-modified"],
}),
],
})
);import { BroadcastCacheUpdate } from "workbox-broadcast-update";
const broadcastUpdate = new BroadcastCacheUpdate({
generatePayload: ({ cacheName, request, newResponse }) => ({
cacheName,
updatedURL: request.url,
timestamp: Date.now(),
responseSize: newResponse.headers.get("content-length"),
contentType: newResponse.headers.get("content-type"),
}),
});import { BroadcastUpdatePlugin } from "workbox-broadcast-update";
// Only notify the client that made the original request
const plugin = new BroadcastUpdatePlugin({
notifyAllClients: false,
});import { responsesAreSame } from "workbox-broadcast-update";
const hasChanged = !responsesAreSame(
oldResponse,
newResponse,
["etag", "content-length", "last-modified"]
);
if (hasChanged) {
console.log("Content has been updated!");
}// In your main thread (window) code
navigator.serviceWorker.addEventListener("message", (event) => {
if (
event.data.type === "CACHE_UPDATED" &&
event.data.meta === "workbox-broadcast-update"
) {
const { cacheName, updatedURL } = event.data.payload;
// Show notification to user
showUpdateNotification(`New content available for ${updatedURL}`);
// Optionally reload the page
if (confirm("New content is available. Reload now?")) {
window.location.reload();
}
}
});