LEARNING OBJECTIVES ⌵
- Understand the Web Push Protocol and the Push API handshake.
- Generate VAPID public/private key pairs for secure push subscription authorization.
- Trigger background notifications from Service Worker
pushevent listeners. - Handle notification click navigation via
clients.openWindow()orclient.focus().
🎬 INTERACTIVE VISUAL PIPELINE
Core Architecture Simulation
1. Input
Directives & Tags
2. Parse
Tokenizer & AST
3. Layout
Box Model & Flow
4. Render
GPU Paint & Composite
PHASE 1: INPUT & DIRECTIVES
Browser receives declarative markup stream, parsing tag tokens and initializing component state.
📖 The Mental Model & Story
Standard notifications created via new Notification() only work while your tab is open in the foreground.
Push Notifications with Service Workers connect your user directly to the operating system's Push Service (Google FCM, Apple APNs, Mozilla autopush). Even when the browser is completely closed or the phone screen is off, the server sends a wake-up packet. The OS wakes your Service Worker in the background, which calls registration.showNotification().
[Your App Server] ===(VAPID Encrypted Push)===> [Browser Vendor Push Service]
|
v
[OS / Android / macOS / Windows]
|
v
[Background Service Worker]
|
v
[registration.showNotification()]
Technical Deep Dive & Specifications
// Inside Service Worker (sw.js)
self.addEventListener('push', (event) => {
const data = event.data ? event.data.json() : { title: 'New Alert', body: 'You have an update.' };
const options = {
body: data.body,
icon: '/images/icon-192.png',
badge: '/images/badge-72.png',
data: { url: data.url || '/' },
vibrate: [100, 50, 100],
actions: [
{ action: 'open', title: 'Open App' },
{ action: 'dismiss', title: 'Dismiss' }
]
};
event.waitUntil(
self.registration.showNotification(data.title, options)
);
});
self.addEventListener('notificationclick', (event) => {
event.notification.close();
if (event.action === 'dismiss') return;
event.waitUntil(
clients.matchAll({ type: 'window', includeUncontrolled: true }).then((clientList) => {
// Focus existing tab if open
for (const client of clientList) {
if (client.url === event.notification.data.url && 'focus' in client) {
return client.focus();
}
}
// Otherwise open new window
if (clients.openWindow) {
return clients.openWindow(event.notification.data.url);
}
})
);
});
📌 Key Takeaways
- Use
self.registration.showNotification()instead ofnew Notification()inside Service Workers. - Wrap notification creation inside
event.waitUntil()to prevent the browser from killing the background worker early. - Always close the notification on click using
event.notification.close(). - --
❓ Knowledge Check
1. Which of the following is correct?
2. Which of the following is correct?
🏋️ Study Exercise
Task: Review the javascript example above. Identify the key directives and their purpose, then try writing your own version from memory.
// Inside Service Worker (sw.js)
self.addEventListener('push', (event) => {
const data = event.data ? event.data.json() : { title: 'New Alert', body: 'You have an update.' };
const options = {
body: data.body,
icon: '/images/icon-192.png',
badge: '/images/badge-72.png',
data: { url: data.url || '/' },
vibrate: [100, 50, 100],
actions: [
{ action: 'open', title: 'Open App' },
{ action: 'dismiss', title: 'Dismiss' }
]
};
event.waitUntil(
self.registration.showNotification(data.title, options)
);
});
self.addEventListener('notificationclick', (event) => {
event.notification.close();
if (event.action === 'dismiss') return;
event.waitUntil(
clients.matchAll({ type: 'window', includeUncontrolled: true }).then((clientList) => {
// Focus existing tab if open
for (const client of clientList) {
if (client.url === event.notification.data.url && 'focus' in client) {
return client.focus();
}
}
// Otherwise open new window
if (clients.openWindow) {
return clients.openWindow(event.notification.data.url);
}
})
);
});