즉시 서비스 워커 업데이트 처리

기본적으로 서비스 워커 수명 주기에서는 업데이트된 서비스 워커를 찾아 설치할 때 업데이트된 서비스 워커가 활성화되고 제어되기 전에 현재 서비스 워커가 제어하고 있는 모든 열린 탭을 닫거나 탐색하도록 요구합니다.

대부분의 경우 당연히 이 작업을 허용하는 것이 괜찮을 수도 있지만, 경우에 따라 사용자에게 대기 중인 서비스 워커 업데이트가 있음을 미리 알려주고 새 서비스 워커로 전환하는 프로세스를 자동화하고 싶을 수 있습니다. 이렇게 하려면 페이지에 코드를 몇 개 추가하고 서비스 워커를 추가해야 합니다.

페이지에 삽입할 코드

다음 코드는 CDN 호스팅 버전의 workbox-window에서 가져온 JavaScript 모듈을 사용하여 인라인 <script> 요소에서 실행됩니다. workbox-window를 사용하여 서비스 워커를 등록하고 서비스 워커가 대기 단계에서 멈추는 경우 반응합니다. 대기 중인 서비스 워커가 발견되면 이 코드는 사용자에게 사이트의 업데이트된 버전을 사용할 수 있음을 알리고 새로고침하라는 메시지를 표시합니다.

<!-- This script tag uses JavaScript modules, so the proper `type` attribute value is required -->
<script type="module">
  // This code sample uses features introduced in Workbox v6.
  import {Workbox} from 'https://storage.googleapis.com/workbox-cdn/releases/6.4.1/workbox-window.prod.mjs';

  if ('serviceWorker' in navigator) {
    const wb = new Workbox('/sw.js');
    let registration;

    const showSkipWaitingPrompt = async (event) => {
      // Assuming the user accepted the update, set up a listener
      // that will reload the page as soon as the previously waiting
      // service worker has taken control.
      wb.addEventListener('controlling', () => {
        // At this point, reloading will ensure that the current
        // tab is loaded under the control of the new service worker.
        // Depending on your web app, you may want to auto-save or
        // persist transient state before triggering the reload.
        window.location.reload();
      });

      // When `event.wasWaitingBeforeRegister` is true, a previously
      // updated service worker is still waiting.
      // You may want to customize the UI prompt accordingly.

      // This code assumes your app has a promptForUpdate() method,
      // which returns true if the user wants to update.
      // Implementing this is app-specific; some examples are:
      // https://open-ui.org/components/alert.research or
      // https://open-ui.org/components/toast.research
      const updateAccepted = await promptForUpdate();

      if (updateAccepted) {
        wb.messageSkipWaiting();
      }
    };

    // Add an event listener to detect when the registered
    // service worker has installed but is waiting to activate.
    wb.addEventListener('waiting', (event) => {
      showSkipWaitingPrompt(event);
    });

    wb.register();
  }
</script>

수락하면 messageSkipWaiting()는 대기 중인 서비스 워커에 self.skipWaiting()를 호출하도록 알립니다. 즉, 활성화가 시작됩니다. 활성화하면 새 서비스 워커가 기존 클라이언트를 제어하여 workbox-window에서 controlling 이벤트를 트리거합니다. 이 경우 현재 페이지가 사전 캐시된 모든 애셋의 최신 버전과 업데이트된 서비스 워커에서 발견된 새 라우팅 로직을 사용하여 다시 로드됩니다.

서비스 워커에 삽입할 코드

페이지에 이전 섹션의 코드를 얻었다면 대기 단계를 언제 건너뛰어야 하는지 알려주는 코드를 서비스 워커에 추가해야 합니다. workbox-build에서 generateSW를 사용 중이고 skipWaiting 옵션이 false (기본값)로 설정되어 있는 경우, 아래 코드가 생성된 서비스 워커 파일에 자동으로 포함되므로 계속 진행해도 됩니다.

injectManifest 모드의 Workbox 빌드 도구 중 하나와 함께 자체 서비스 워커를 작성하는 경우 다음 코드를 직접 추가해야 합니다.

addEventListener('message', (event) => {
  if (event.data && event.data.type === 'SKIP_WAITING') {
    self.skipWaiting();
  }
});

이 메서드는 workbox-window에서 type 값이 SKIP_WAITING인 서비스 워커로 전송된 메시지를 수신 대기하며 이때 self.skipWaiting()를 호출합니다. 이전 코드 샘플과 같이 workbox-windowmessageSkipWaiting() 메서드가 이 메시지를 전송합니다.

메시지를 표시해야 하나요?

이는 서비스 워커를 배포하는 모든 애플리케이션이 따라야 하는 패턴은 아닙니다. 이 가이드는 서비스 워커 업데이트 시 페이지를 다시 로드할 기회를 제공하지 못하면 예기치 않은 동작이 발생할 수 있는 일부 시나리오를 위한 것입니다. 새로고침 프롬프트의 표시 여부에 관한 엄격하고 빠른 규칙은 없지만, 다음과 같은 몇 가지 경우에 적합합니다.

  • 사전 캐싱을 광범위하게 사용합니다. 정적 애셋과 관련이 있는 경우, 탐색 요청에 네트워크 우선 또는 네트워크 전용 전략을 사용하지만 정적 애셋 지연 로드에서는 나중에 문제가 발생할 수 있습니다. 이로 인해 버전이 지정된 애셋이 변경될 수 있고 서비스 워커가 이를 사전 캐시하지 않은 상황이 발생할 수 있습니다. 여기에서 새로고침 버튼을 제공하면 예기치 않은 동작을 피할 수 있습니다.
  • 사전 캐시된 HTML을 게재하는 경우 이 경우 업데이트된 서비스 워커가 제어할 때까지 HTML에 대한 업데이트가 인식되지 않으므로 서비스 워커 업데이트 시 새로고침 버튼을 제공하는 것을 적극 고려하시기 바랍니다.
  • 런타임 캐싱에 주로 의존하지 않는 경우. 런타임에 리소스를 캐싱할 때 사용자에게 새로고침해야 한다고 알릴 필요가 없습니다. 탐색 요청이 네트워크 우선 또는 네트워크 전용 전략을 사용한다는 가정하에, 버전이 지정된 애셋은 변경될 때 런타임 캐시에 추가됩니다.
  • stale-when-revalidate 전략을 사용할 때는 workbox-broadcast-update 모듈을 사용해 서비스 워커 업데이트를 사용자에게 알릴 수 있습니다.

서비스 워커에 대한 업데이트를 사용자에게 알려야 하는지 여부는 애플리케이션과 애플리케이션의 고유 요구사항에 따라 다릅니다. 새 서비스 워커를 푸시할 때 사용자가 이상한 행동을 하는 것을 발견한 경우, 이는 사용자에게 이를 알려야 하는 최선의 신호일 것입니다.