ServiceWorker: 수명 주기, 업데이트 및 알림
If you have tried CRA (create react app), have you ever wonder what does this file - `/src/serviceWorker.js` do? In this article, I will demonstrate what we can do by implementing the service worker into our application.
시작하기 전에 서비스 작업자가 제대로 처리하지 않으면 버그가 있을 수 있으므로 이 기사를 확인하여 몇 가지 중요한 지식을 미리 확인하는 것이 좋습니다. - Offline-First Considerations
의제
서비스 워커 등록
At first, we need to register service worker.
navigator.serviceWorker
.register("/sw.js")
.then((reg) => {
// no controller exist, page wasn't loaded via a service worker
if (!navigator.serviceWorker.controller) {
return;
}
if (reg.waiting) {
// If we have a new version of the service worker is waiting,
// we can display the message to the user and allow them
// to trigger updates manually.
// Otherwise, the browser will replace the service worker
// when the user closes or navigate away from all tabs using
// the current service worker.
return;
}
if (reg.installing) {
// If we have a new service worker is installing, we can
// tracking the status and display the message once the
// installation is finished.
return;
}
});
이벤트: 설치
The install
event is the first event a service worker gets, and it only happens once.
We can cache the pages here.
const urlsToCache = ["/faq", "/contact"];
self.addEventListener("install", (event) => {
event.waitUntil(
caches.open(CACHE_NAME).then((cache) => {
return cache.addAll(urlsToCache);
})
);
});
이벤트: 활성화
Once your service worker is ready to control clients, we'll get an activate
event.
It's common to delete the old caches here.
self.addEventListener("activate", (event) => {
event.waitUntil(
caches.keys().then((cacheNames) => {
const promiseArr = cacheNames.map((item) => {
if (item !== CACHE_NAME) {
return caches.delete(item);
}
});
return Promise.all(promiseArr);
})
);
});
이벤트: 가져오기
We can intercept the request and custom the response in the fetch
event.
self.addEventListener("fetch", (event) => {
// hijacking path and return a mock HTML content
if (event.request.url.includes("/faq")) {
event.respondWith(
new Response("<div>Mock FAQ Page</div>", {
headers: { "Content-Type": "text/html" },
})
);
}
// hijacking API request and return mock response in JSON format
if (event.request.url.includes("/api/users")) {
const data = [
{
id: "0001",
name: "andrew",
},
];
const blob = new Blob(
[JSON.stringify(data, null, 2)],
{ type: "application/json" }
);
const init = { status: 200, statusText: "default mock response" };
const defaultResponse = new Response(blob, init);
event.respondWith(defaultResponse);
}
// Stale-while-revalidate:
// return the cached version if it exists. At the same time,
// send a request to get the latest version and update the cache
const requestUrl = new URL(event.request.url);
if (requestUrl.pathname.startsWith("/avatars/")) {
const response = caches.open(CACHE_NAME).then((cache) => {
return cache.match(event.request).then((response) => {
const networkFetch = fetch(event.request)
.then((networkResponse) => {
cache.put(event.request, networkResponse.clone());
return networkResponse;
});
return response || networkFetch;
});
});
event.respondWith(response);
return;
}
});
이벤트: 메시지
We can use postMessage to communicate with the service worker.
Here, we bind a click event to send a postMessage to the service worker.
In the service worker, we can listen to the message
event to received the postMessage.
- send message to service worker
function handleClickEven() {
worker.postMessage({ action: "skipWaiting" });
}
- receive message
self.addEventListener("message", (event) => {
if (event.data.action === "skipWaiting") {
// skip waiting to apply the new version of service worker
self.skipWaiting();
}
});
이벤트: updatefound & statechange
We can listen to the updatefound
event to see if we have a new service worker.
If there is a service worker is installing, we listen to the statechange
event,
once the install is finished, we can display a message to notify our users.
self.addEventListener("updatefound", () => {
if (reg.installing) {
reg.installing.addEventListener("statechange", () => {
if (worker.state == "installed") {
// display a message to tell our users that
// there's a new service worker is installed
}
});
}
});
웹 푸시 알림
We can use a service worker to handle the notification.
Here, we ask permission to display the notification, if the user agrees,
then we can get the subscription information.
- Get permission & subscription
if (Notification && Notification.permission === "default") {
Notification.requestPermission().then((result) => {
if (result === "denied") {
return;
}
if (result === "granted") {
if (navigator && navigator.serviceWorker) {
navigator.serviceWorker.ready.then((reg) => {
reg.pushManager
.getSubscription()
.then((subscription: any) => {
if (!subscription) {
// we need to encrypt the data for web push notification,
// I use web-push to generate the public and private key.
// You can check their documentation for more detail.
// https://github.com/web-push-libs/web-push
const vapidPublicKey = "xxxxx";
const applicationServerKey =
urlBase64ToUint8Array(vapidPublicKey);
return reg.pushManager.subscribe({
userVisibleOnly: true,
applicationServerKey,
});
}
return subscription;
})
.then((sub) => {
// Get the subscription information here, we need to
// create an API and save them into our database
/*
{
endpoint:
"https://fcm.googleapis.com/fcm/send/xxx",
keys: {
auth: "xxx",
p256dh: "xxx",
},
};
*/
});
});
}
}
});
}
- send notification
const webpush = require('web-push');
webpush.setVapidDetails("mailto:[email protected]", "my_private_key");
const pushConfig = {
endpoint: sub.endpoint,
keys: {
auth: sub.keys.auth,
p256dh: sub.keys.p256dh,
},
};
webpush
.sendNotification(
pushConfig,
JSON.stringify({ title: "Test Title", content: "Test Content" })
)
.catch((err) => {
console.log(err);
});
이벤트: 푸시
We can receive the web push message by listening to the push
event.
self.addEventListener("push", (event) => {
if (event.data) {
try {
data = JSON.parse(event.data.text());
event.waitUntil(
self.registration.showNotification(data.title, {
body: data.content,
icon: "/icon-192.png",
badge: "/badge-192.png",
})
);
} catch (e) {
console.error('push event data parse fail');
}
}
});
결론
이상입니다. 이 기사가 서비스 워커에 익숙해지는 데 도움이 되었으면 합니다.
참조
Reference
이 문제에 관하여(ServiceWorker: 수명 주기, 업데이트 및 알림), 우리는 이곳에서 더 많은 자료를 발견하고 링크를 클릭하여 보았다 https://dev.to/oahehc/serviceworker-lifecycle-update-and-notification-1n68텍스트를 자유롭게 공유하거나 복사할 수 있습니다.하지만 이 문서의 URL은 참조 URL로 남겨 두십시오.
우수한 개발자 콘텐츠 발견에 전념 (Collection and Share based on the CC Protocol.)