경우에 따라 서비스 워커가 제어하는 활성 탭과 사전에 통신하여 특정 이벤트를 알릴 수 있습니다. 예를 들면 다음과 같습니다.
- 서비스 워커의 새 버전이 설치되면 페이지에 알립니다. 그러면 페이지 에서 사용자에게 "새로고침하여 업데이트" 버튼을 표시하여 새 기능에 즉시 액세스할 수 있습니다 .
- **'이제 앱을 오프라인으로 사용할 수 있습니다'** 또는 **'새 버전의 콘텐츠를 사용할 수 있습니다'** 와 같은 표시를 보여주어 서비스 워커 측에서 발생한 캐시된 데이터의 변경사항을 사용자에게 알립니다.
서비스 워커가 통신을 시작하기 위해 페이지에서 메시지를 수신할 필요가 없는 이러한 유형의 사용 사례를 "업데이트 브로드캐스트"라고 합니다. 이 가이드에서는 표준 브라우저 API와 Workbox 라이브러리를 사용하여 페이지와 서비스 워커 간의 이러한 유형의 통신을 구현하는 다양한 방법을 검토합니다.
프로덕션 사례
Tinder
Tinder PWA는 workbox-window를 사용하여 페이지에서 중요한 서비스 워커 수명 주기 순간 ("설치됨", "제어됨" 및
"활성화됨")을 수신 대기합니다. 이렇게 하면 새 서비스 워커가 작동할 때 "업데이트 사용 가능"
배너가 표시되므로 PWA를 새로고침하고 최신 기능에 액세스할 수 있습니다.
Squoosh
Squoosh PWA에서 서비스 워커가 오프라인으로 작동하는 데 필요한 모든 애셋을 캐시하면 페이지에 메시지를 보내 '오프라인으로 작업할 준비가 됨' 토스트 메시지를 표시하여 사용자에게 기능을 알립니다.
Workbox 사용
서비스 워커 수명 주기 이벤트 수신 대기
workbox-window는 중요한 서비스 워커 수명 주기
이벤트를 수신 대기하는 간단한 인터페이스를 제공합니다.
내부적으로 라이브러리는
updatefound
및 statechange
와 같은 클라이언트 측 API를 사용하고 workbox-window 객체에서 상위 수준 이벤트 리스너를 제공하므로
사용자가 이러한 이벤트를 더 쉽게 사용할 수 있습니다.
다음 페이지 코드를 사용하면 서비스 워커의 새 버전이 설치될 때마다 감지하여 사용자에게 전달할 수 있습니다.
const wb = new Workbox('/sw.js');
wb.addEventListener('installed', (event) => {
if (event.isUpdate) {
// Show "Update App" banner
}
});
wb.register();
캐시 데이터의 변경사항을 페이지에 알림
Workbox 패키지
workbox-broadcast-update
는 캐시된 응답이 업데이트되었음을 창 클라이언트에 알리는 표준 방법을 제공합니다. 이는
StaleWhileRevalidate
전략과 함께 가장 흔히 사용됩니다.
업데이트를 브로드캐스트하려면 서비스 워커 측의 전략 옵션에 broadcastUpdate.BroadcastUpdatePlugin을 추가하세요.
import {registerRoute} from 'workbox-routing';
import {StaleWhileRevalidate} from 'workbox-strategies';
import {BroadcastUpdatePlugin} from 'workbox-broadcast-update';
registerRoute(
({url}) => url.pathname.startsWith('/api/'),
new StaleWhileRevalidate({
plugins: [
new BroadcastUpdatePlugin(),
],
})
);
웹 앱에서 다음과 같이 이러한 이벤트를 수신 대기할 수 있습니다.
navigator.serviceWorker.addEventListener('message', async (event) => {
// Optional: ensure the message came from workbox-broadcast-update
if (event.data.meta === 'workbox-broadcast-update') {
const {cacheName, updatedUrl} = event.data.payload;
// Do something with cacheName and updatedUrl.
// For example, get the cached content and update
// the content on the page.
const cache = await caches.open(cacheName);
const updatedResponse = await cache.match(updatedUrl);
const updatedText = await updatedResponse.text();
}
});
브라우저 API 사용
Workbox에서 제공하는 기능이 요구사항을 충족하지 않는 경우 다음 브라우저 API를 사용하여 "업데이트 브로드캐스트"를 구현하세요.
브로드캐스트 채널 API
서비스 워커는 BroadcastChannel
객체를 만들고 메시지 전송을 시작합니다. 이러한 메시지를 수신하는 데 관심이 있는 모든 컨텍스트 (예: 페이지)는 BroadcastChannel 객체를 인스턴스화하고 메시지 핸들러를 구현하여 메시지를 수신할 수 있습니다.
새 서비스 워커가 설치될 때 페이지에 알리려면 다음 코드를 사용하세요.
// Create Broadcast Channel to send messages to the page
const broadcast = new BroadcastChannel('sw-update-channel');
self.addEventListener('install', function (event) {
// Inform the page every time a new service worker is installed
broadcast.postMessage({type: 'CRITICAL_SW_UPDATE'});
});
페이지는 sw-update-channel을 구독하여 이러한 이벤트를 수신 대기합니다.
// Create Broadcast Channel and listen to messages sent to it
const broadcast = new BroadcastChannel('sw-update-channel');
broadcast.onmessage = (event) => {
if (event.data && event.data.type === 'CRITICAL_SW_UPDATE') {
// Show "update to refresh" banner to the user.
}
};
이는 간단한 기법이지만 제한사항은 브라우저 지원입니다. 이 문서를 작성하는 시점에 Safari는 이 API를 지원하지 않습니다.
클라이언트 API
클라이언트 API는 Client 객체 배열을 반복하여 서비스 워커에서 여러 클라이언트와 통신하는 간단한
방법을 제공합니다.
다음 서비스 워커 코드를 사용하여 마지막으로 포커스가 맞춰진 탭에 메시지를 보냅니다.
// Obtain an array of Window client objects
self.clients.matchAll(options).then(function (clients) {
if (clients && clients.length) {
// Respond to last focused tab
clients[0].postMessage({type: 'MSG_ID'});
}
});
페이지는 메시지 핸들러를 구현하여 이러한 메시지를 가로챕니다.
// Listen to messages
navigator.serviceWorker.onmessage = (event) => {
if (event.data && event.data.type === 'MSG_ID') {
// Process response
}
};
클라이언트 API는 여러 활성 탭에 정보를 브로드캐스트하는 경우와 같은 경우에 적합한 옵션입니다. API는 모든 주요 브라우저에서 지원되지만 모든 메서드가 지원되는 것은 아닙니다. 사용하기 전에 브라우저 지원을 확인하세요.
메시지 채널
메시지 채널에는 페이지에서 서비스 워커로 포트를 전달하여 둘 간의 통신 채널을 설정하는 초기 구성 단계가 필요합니다. 페이지는 MessageChannel 객체를 인스턴스화하고 postMessage() 인터페이스를 통해 서비스 워커에 포트를 전달합니다.
const messageChannel = new MessageChannel();
// Init port
navigator.serviceWorker.controller.postMessage({type: 'PORT_INITIALIZATION'}, [
messageChannel.port2,
]);
페이지는 해당 포트에서 'onmessage' 핸들러를 구현하여 메시지를 수신 대기합니다.
// Listen to messages
messageChannel.port1.onmessage = (event) => {
// Process message
};
서비스 워커는 포트를 수신하고 포트에 대한 참조를 저장합니다.
// Initialize
let communicationPort;
self.addEventListener('message', (event) => {
if (event.data && event.data.type === 'PORT_INITIALIZATION') {
communicationPort = event.ports[0];
}
});
이 시점부터 포트에 대한 참조에서 postMessage()를 호출하여 페이지에 메시지를 보낼 수 있습니다.
// Communicate
communicationPort.postMessage({type: 'MSG_ID' });
MessageChannel은 포트를 초기화해야 하므로 구현이 더 복잡할 수 있지만 모든 주요 브라우저에서
지원됩니다.
다음 단계
이 가이드에서는 창에서 서비스 워커로의 통신 중 한 가지 특정 사례인 "업데이트 브로드캐스트"를 살펴보았습니다. 살펴본 예에는 중요한 서비스 워커 수명 주기 이벤트 수신 대기, 콘텐츠 또는 캐시된 데이터의 변경사항에 관해 페이지와 통신이 포함됩니다. 서비스 워커가 이전에 메시지를 수신하지 않고 페이지와 사전에 통신하는 더 흥미로운 사용 사례를 생각해 볼 수 있습니다.
창과 서비스 워커 통신의 더 많은 패턴은 다음을 확인하세요.
- 명령형 캐싱 가이드: 페이지에서 서비스 워커를 호출하여 리소스를 미리 캐시합니다 (예: 프리페치 시나리오).
- 양방향 통신: 서비스 워커에 작업 위임 (예: 대용량 다운로드) 및 페이지에 진행 상황 알림