Angular service worker library for Progressive Web Apps with caching, push notifications, and update management
—
Pending
Does it follow best practices?
Impact
Pending
No eval scenarios have been run
Pending
The risk profile of this skill
Angular's service worker library provides comprehensive PWA support including caching strategies, push notifications, and app update management. It enables offline-first applications with automatic resource caching and background sync capabilities.
npm install @angular/service-workerimport { ServiceWorkerModule, SwPush, SwUpdate } from '@angular/service-worker';For standalone/functional approach:
import { provideServiceWorker } from '@angular/service-worker';For low-level communication:
import { NgswCommChannel } from '@angular/service-worker';For configuration and generation:
import { Config, AssetGroup, DataGroup, Generator } from '@angular/service-worker/config';For testing:
import {
MockServiceWorkerContainer,
MockServiceWorker,
patchDecodeBase64
} from '@angular/service-worker/testing';import { NgModule } from '@angular/core';
import { ServiceWorkerModule } from '@angular/service-worker';
@NgModule({
imports: [
ServiceWorkerModule.register('ngsw-worker.js', {
enabled: environment.production,
registrationStrategy: 'registerWhenStable:30000'
})
]
})
export class AppModule {}import { bootstrapApplication } from '@angular/platform-browser';
import { provideServiceWorker } from '@angular/service-worker';
bootstrapApplication(AppComponent, {
providers: [
provideServiceWorker('ngsw-worker.js', {
enabled: environment.production,
registrationStrategy: 'registerWhenStable:30000'
})
]
});import { SwPush } from '@angular/service-worker';
constructor(private swPush: SwPush) {}
subscribeToNotifications() {
if (this.swPush.isEnabled) {
this.swPush.requestSubscription({
serverPublicKey: 'YOUR_VAPID_PUBLIC_KEY'
})
.then(sub => console.log('Subscription object:', sub))
.catch(err => console.error('Could not subscribe', err));
}
}import { SwUpdate } from '@angular/service-worker';
constructor(private swUpdate: SwUpdate) {}
checkForUpdates() {
if (this.swUpdate.isEnabled) {
this.swUpdate.versionUpdates.subscribe(event => {
switch (event.type) {
case 'VERSION_READY':
if (confirm('New version available. Load now?')) {
document.location.reload();
}
break;
case 'VERSION_DETECTED':
console.log('Downloading new app version...');
break;
}
});
}
}Angular Service Worker is built around several key components:
Angular module and standalone provider setup for service worker integration with configurable registration strategies.
class ServiceWorkerModule {
static register(
script: string,
options?: SwRegistrationOptions
): ModuleWithProviders<ServiceWorkerModule>;
}
function provideServiceWorker(
script: string,
options?: SwRegistrationOptions
): EnvironmentProviders;
abstract class SwRegistrationOptions {
enabled?: boolean;
scope?: string;
registrationStrategy?: string | (() => Observable<unknown>);
}Complete push notification system with subscription management, message handling, and notification click events.
class SwPush {
readonly messages: Observable<object>;
readonly notificationClicks: Observable<{
action: string;
notification: NotificationOptions & { title: string };
}>;
readonly subscription: Observable<PushSubscription | null>;
get isEnabled(): boolean;
requestSubscription(options: {serverPublicKey: string}): Promise<PushSubscription>;
unsubscribe(): Promise<void>;
}Service for detecting, downloading, and activating app updates with comprehensive version event handling.
class SwUpdate {
readonly versionUpdates: Observable<VersionEvent>;
readonly unrecoverable: Observable<UnrecoverableStateEvent>;
get isEnabled(): boolean;
checkForUpdate(): Promise<boolean>;
activateUpdate(): Promise<boolean>;
}Direct service worker communication channel for advanced message passing and event handling.
class NgswCommChannel {
readonly worker: Observable<ServiceWorker>;
readonly registration: Observable<ServiceWorkerRegistration>;
readonly events: Observable<TypedEvent>;
get isEnabled(): boolean;
postMessage(action: string, payload: Object): Promise<void>;
postMessageWithOperation(type: string, payload: Object, operationNonce: number): Promise<boolean>;
generateNonce(): number;
eventsOfType<T extends TypedEvent>(type: T['type'] | T['type'][]): Observable<T>;
nextEventOfType<T extends TypedEvent>(type: T['type']): Observable<T>;
waitForOperationCompleted(nonce: number): Promise<boolean>;
}Configuration types and utilities for service worker behavior and caching strategies.
interface Config {
appData?: {};
index: string;
assetGroups?: AssetGroup[];
dataGroups?: DataGroup[];
navigationUrls?: string[];
navigationRequestStrategy?: 'freshness' | 'performance';
applicationMaxAge?: Duration;
}
interface AssetGroup {
name: string;
installMode?: 'prefetch' | 'lazy';
updateMode?: 'prefetch' | 'lazy';
resources: {files?: Glob[]; urls?: Glob[]};
cacheQueryOptions?: Pick<CacheQueryOptions, 'ignoreSearch'>;
}
interface DataGroup {
name: string;
urls: Glob[];
version?: number;
cacheConfig: {
maxSize: number;
maxAge: Duration;
timeout?: Duration;
refreshAhead?: Duration;
strategy?: 'freshness' | 'performance';
cacheOpaqueResponses?: boolean;
};
cacheQueryOptions?: Pick<CacheQueryOptions, 'ignoreSearch'>;
}Mock implementations for unit testing service worker functionality in Angular applications.
class MockServiceWorkerContainer {
controller: MockServiceWorker | null;
messages: Subject<any>;
notificationClicks: Subject<{}>;
addEventListener(event: 'controllerchange' | 'message', handler: Function): void;
removeEventListener(event: 'controllerchange', handler: Function): void;
register(url: string): Promise<void>;
getRegistration(): Promise<ServiceWorkerRegistration>;
setupSw(url?: string): void;
sendMessage(value: Object): void;
}Command-line tools and programmatic API for service worker configuration and manifest generation.
class Generator {
constructor(fs: Filesystem, baseHref: string);
process(config: Config): Promise<any>;
}
interface Filesystem {
list(dir: string, pattern: string): Promise<string[]>;
read(path: string): Promise<string>;
hash(path: string): Promise<string>;
write(path: string, contents: string): Promise<void>;
}interface VersionDetectedEvent {
type: 'VERSION_DETECTED';
version: {hash: string; appData?: object};
}
interface VersionReadyEvent {
type: 'VERSION_READY';
currentVersion: {hash: string; appData?: object};
latestVersion: {hash: string; appData?: object};
}
interface VersionInstallationFailedEvent {
type: 'VERSION_INSTALLATION_FAILED';
version: {hash: string; appData?: object};
error: string;
}
interface NoNewVersionDetectedEvent {
type: 'NO_NEW_VERSION_DETECTED';
version: {hash: string; appData?: Object};
}
type VersionEvent =
| VersionDetectedEvent
| VersionInstallationFailedEvent
| VersionReadyEvent
| NoNewVersionDetectedEvent;interface UnrecoverableStateEvent {
type: 'UNRECOVERABLE_STATE';
reason: string;
}interface TypedEvent {
type: string;
}
interface PushEvent {
type: 'PUSH';
data: any;
}
type IncomingEvent = UnrecoverableStateEvent | VersionEvent;type Glob = string;
type Duration = string;enum RuntimeErrorCode {
UNKNOWN_REGISTRATION_STRATEGY = 5600,
SERVICE_WORKER_DISABLED_OR_NOT_SUPPORTED_BY_THIS_BROWSER = 5601,
NOT_SUBSCRIBED_TO_PUSH_NOTIFICATIONS = 5602,
PUSH_SUBSCRIPTION_UNSUBSCRIBE_FAILED = 5603,
SERVICE_WORKER_REGISTRATION_FAILED = 5604
}