서비스 워커를 사용하여 페이지에 업데이트 브로드캐스트

Andrew Guan
Andrew Guan
Demián Renzulli
Demián Renzulli

어떤 경우에는 서비스 워커가 활성 상태의 시스템 한 개와 특정 이벤트를 알립니다. 예를 들면 다음과 같습니다.

  • 서비스 워커의 새 버전이 설치되었을 때 페이지가 새 기능에 액세스할 수 있도록 사용자에게 '업데이트하여 새로고침' 버튼을 표시할 수 있음 즉시 삭제할 수 있습니다
  • 서비스 워커 측에서 발생한 캐시된 데이터의 변경에 대해 사용자에게 알리기 '이제 앱에서 오프라인으로 작업할 준비가 되었습니다.' 또는 '새 버전의 콘텐츠 사용 가능'을 참조하세요.
업데이트를 전송하기 위해 페이지와 통신하는 서비스 워커를 보여주는 다이어그램

서비스 워커가 메시지를 받을 필요가 없는 이러한 유형의 사용 사례를 페이지에서 '브로드캐스트 업데이트'로 커뮤니케이션을 시작합니다. 이 가이드에서는 표준 인터페이스를 사용하여 페이지와 서비스 워커 간에 이러한 유형의 통신을 구현하는 브라우저 API, Workbox 라이브러리를 모두 지원합니다.

프로덕션 사례

Tinder

Tinder PWA에서 workbox-window를 사용하여 서비스 워커의 중요한 서비스 워커 수명 주기 순간('설치', '제어' 및 "활성화됨") 이런 방식으로 새 서비스 워커가 실행되면 "Update Available" PWA를 새로고침하고 최신 기능에 액세스할 수 있습니다.

<ph type="x-smartling-placeholder">
</ph> Tinder 웹 앱 &#39;업데이트 가능&#39; 스크린샷 기능을 제공합니다
Tinder PWA에서 서비스 워커는 페이지에 새 버전이 준비되었음을 알리고 페이지에서 사용자에게 '업데이트 가능'을 표시합니다. 있습니다.

초오시

Squoosh PWA에서, 서비스 워커가 필요한 모든 애셋이 오프라인에서 작동하도록 하려면 페이지에 '오프라인으로 작업 준비 완료'라는 메시지가 전송됩니다. 토스트 메시지를 통해 사용자에게 기능에 관해 알립니다.

<ph type="x-smartling-placeholder">
</ph> Squoosh 웹 앱 &#39;오프라인으로 작업 가능&#39; 스크린샷 기능을 제공합니다
Squoosh PWA에서 서비스 워커는 캐시가 준비되면 페이지에 업데이트를 브로드캐스트하고 페이지에 'Ready to work offline'이라고 표시합니다. 토스트 메시지

Workbox 사용

서비스 워커 수명 주기 이벤트 수신 대기

workbox-window는 중요한 서비스 워커 수명 주기를 수신 대기할 수 있는 간단한 인터페이스를 제공합니다. 이벤트를 참조하세요. 이 라이브러리는 내부에서 다음과 같은 클라이언트 측 API를 사용합니다. updatefound 드림 및 statechange 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를 지원하지 않습니다.

Client API

Client 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
   }
};

Client API는 여러 활성 탭에 정보를 브로드캐스팅하는 등의 경우에 유용한 옵션입니다. 이 API는 모든 주요 브라우저에서 지원되지만 모든 메서드가 지원되는 것은 아닙니다. 사전에 브라우저 지원 확인 사용할 수 있습니다.

메시지 채널

메시지 채널 요구사항 포트 100%를 서비스 워커로 설정해서 통신할 수 있게 해줍니다 페이지는 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는 포트 초기화의 필요성 때문에 구현하기가 더 복잡할 수 있지만 모든 주요 브라우저에서 지원됩니다.

다음 단계

이 가이드에서는 Window to Service Worker 통신의 한 가지 사례를 살펴봤습니다. "방송 업데이트"로 이동합니다. 중요한 서비스 워커의 수신 대기를 예로 들 수 있습니다 콘텐츠 또는 캐시된 데이터의 변경사항에 관해 페이지에 전달해야 합니다. 서비스 워커가 페이지와 사전에 커뮤니케이션하는 더 흥미로운 사용 사례들을 데이터를 전송할 수 있습니다.

Window와 서비스 워커 통신의 추가 패턴은 다음을 참조하세요.

  • 명령적 캐싱 가이드: 페이지에서 서비스 워커를 호출하여 사전에 캐시 리소스를 캐시합니다 (예: 미리 가져오기 시나리오).
  • 양방향 통신: 작업을 서비스 워커 (예: 다운로드) 진행 상황에 대해 페이지에 계속 알려야 합니다.

추가 리소스