Simplifies communications with Workbox packages running in the service worker
npx @tessl/cli install tessl/npm-workbox-window@7.3.0Workbox Window is a TypeScript library that simplifies communication between web applications and Workbox service workers. It provides a comprehensive API for service worker registration, lifecycle management, and bidirectional messaging with full type safety and event-driven architecture.
npm install workbox-windowimport { Workbox, messageSW } from "workbox-window";For CommonJS:
const { Workbox, messageSW } = require("workbox-window");All event types and utilities:
import {
Workbox,
messageSW,
WorkboxEvent,
WorkboxMessageEvent,
WorkboxLifecycleEvent,
WorkboxLifecycleWaitingEvent,
WorkboxLifecycleEventMap,
WorkboxEventMap
} from "workbox-window";import { Workbox } from "workbox-window";
// Create and register service worker
const wb = new Workbox("/sw.js");
// Listen for lifecycle events
wb.addEventListener("waiting", (event) => {
console.log("Service worker is waiting");
// Optionally skip waiting
wb.messageSkipWaiting();
});
wb.addEventListener("controlling", (event) => {
console.log("Service worker is now controlling the page");
window.location.reload();
});
// Register the service worker
await wb.register();
// Send messages to service worker
const response = await wb.messageSW({ type: "CACHE_URLS", payload: urls });Workbox Window is built around several key components:
The core Workbox class provides comprehensive service worker registration and lifecycle management.
/**
* Main class for service worker registration, updates, and lifecycle management
*/
class Workbox {
/**
* Creates a new Workbox instance with a script URL and service worker options
* @param scriptURL - The service worker script URL (supports TrustedScriptURL)
* @param registerOptions - Service worker registration options
*/
constructor(scriptURL: string | TrustedScriptURL, registerOptions?: RegistrationOptions);
/**
* Registers the service worker, delaying until window load by default
* @param options - Registration options
* @param options.immediate - If true, register immediately without waiting for load
* @returns Promise resolving to ServiceWorkerRegistration or undefined
*/
register(options?: { immediate?: boolean }): Promise<ServiceWorkerRegistration | undefined>;
/**
* Checks for updates of the registered service worker
* @returns Promise resolving when update check completes
*/
update(): Promise<void>;
/**
* Returns promise resolving to the service worker instance
* @returns Promise resolving to ServiceWorker
*/
getSW(): Promise<ServiceWorker>;
/**
* Sends data to the service worker and resolves with response
* @param data - Object to send to service worker
* @returns Promise resolving to response from service worker
*/
messageSW(data: object): Promise<any>;
/**
* Sends SKIP_WAITING message to waiting service worker
*/
messageSkipWaiting(): void;
/**
* Promise resolving when service worker becomes active
*/
readonly active: Promise<ServiceWorker>;
/**
* Promise resolving when service worker starts controlling the page
*/
readonly controlling: Promise<ServiceWorker>;
/**
* Add event listener for service worker lifecycle and message events
* @param type - Event type to listen for
* @param listener - Event handler function
*/
addEventListener<K extends keyof WorkboxEventMap>(
type: K,
listener: (event: WorkboxEventMap[K]) => any
): void;
/**
* Remove event listener for specific event type
* @param type - Event type to remove listener from
* @param listener - Event handler function to remove
*/
removeEventListener<K extends keyof WorkboxEventMap>(
type: K,
listener: (event: WorkboxEventMap[K]) => any
): void;
}Standalone utility for sending messages to service workers with promise-based responses.
/**
* Sends data to a service worker via postMessage and resolves with response
* @param sw - The service worker to send the message to
* @param data - Object to send to the service worker
* @returns Promise resolving to response from service worker
*/
function messageSW(sw: ServiceWorker, data: object): Promise<any>;Type-safe event system for handling service worker lifecycle and messages.
/**
* Minimal Event subclass for Workbox events
*/
class WorkboxEvent<K extends keyof WorkboxEventMap> {
constructor(type: K, props: Omit<WorkboxEventMap[K], 'target' | 'type'>);
type: K;
target?: Workbox;
sw?: ServiceWorker;
originalEvent?: Event;
isExternal?: boolean;
}/**
* Event dispatched when receiving postMessage from service worker
*/
interface WorkboxMessageEvent extends WorkboxEvent<'message'> {
data: any;
originalEvent: Event;
ports: readonly MessagePort[];
}
/**
* Base interface for service worker lifecycle events
*/
interface WorkboxLifecycleEvent extends WorkboxEvent<keyof WorkboxLifecycleEventMap> {
isUpdate?: boolean;
}
/**
* Lifecycle event for waiting state with additional context
*/
interface WorkboxLifecycleWaitingEvent extends WorkboxLifecycleEvent {
wasWaitingBeforeRegister?: boolean;
}
/**
* Map of lifecycle event types to their event objects
*/
interface WorkboxLifecycleEventMap {
installing: WorkboxLifecycleEvent;
installed: WorkboxLifecycleEvent;
waiting: WorkboxLifecycleWaitingEvent;
activating: WorkboxLifecycleEvent;
activated: WorkboxLifecycleEvent;
controlling: WorkboxLifecycleEvent;
redundant: WorkboxLifecycleEvent;
}
/**
* Complete map of all Workbox event types
*/
interface WorkboxEventMap extends WorkboxLifecycleEventMap {
message: WorkboxMessageEvent;
}
/**
* Type for event listener callback functions
*/
type ListenerCallback = (event: WorkboxEvent<any>) => any;import { Workbox } from "workbox-window";
const wb = new Workbox("/sw.js", {
scope: "/app/",
type: "module"
});
// Register immediately without waiting for load
await wb.register({ immediate: true });import { Workbox } from "workbox-window";
const wb = new Workbox("/sw.js");
wb.addEventListener("installed", (event) => {
if (event.isUpdate) {
console.log("Service worker updated");
} else {
console.log("Service worker installed for first time");
}
});
wb.addEventListener("waiting", (event) => {
if (event.wasWaitingBeforeRegister) {
console.log("Service worker was already waiting");
}
// Show update available notification
if (confirm("New version available! Update now?")) {
wb.messageSkipWaiting();
}
});
wb.addEventListener("message", (event) => {
console.log("Message from SW:", event.data);
});
await wb.register();import { Workbox, messageSW } from "workbox-window";
const wb = new Workbox("/sw.js");
await wb.register();
// Get service worker reference
const sw = await wb.getSW();
// Send message using utility function
const response = await messageSW(sw, {
type: "GET_CACHE_STATS"
});
// Or send via Workbox instance
const response2 = await wb.messageSW({
type: "CLEAR_CACHE",
cacheName: "images"
});import { Workbox } from "workbox-window";
const wb = new Workbox("/sw.js");
await wb.register();
// Check for updates periodically
setInterval(async () => {
await wb.update();
}, 60000); // Check every minuteimport { Workbox } from "workbox-window";
// Using TrustedScriptURL for enhanced security
const trustedURL = trustedTypes
.createPolicy("workbox", {
createScriptURL: (url) => url
})
.createScriptURL("/sw.js");
const wb = new Workbox(trustedURL);
await wb.register();