플러그인 사용

Workbox를 사용할 때 요청 및 응답을 가져오거나 캐시할 때 이를 조작해야 할 수도 있습니다. Workbox 플러그인을 사용하면 최소한의 추가 상용구로 서비스 워커에 추가 동작을 추가할 수 있습니다. 자체 프로젝트에서 패키징하여 다시 사용할 수도 있고 다른 사람들이 사용하도록 공개적으로 출시할 수도 있습니다.

Workbox는 즉시 사용 가능한 여러 플러그인을 제공하며, 능숙한 개발자라면 애플리케이션 요구사항에 맞는 맞춤 플러그인을 작성할 수 있습니다.

사용 가능한 Workbox 플러그인

Workbox는 서비스 워커에서 사용할 수 있는 다음과 같은 공식 플러그인을 제공합니다.

Workbox 플러그인은 위에 나열된 플러그인 중 하나든 맞춤 플러그인이든 전략의 plugins 속성에 플러그인 인스턴스를 추가하여 Workbox 전략과 함께 사용됩니다.

import {registerRoute} from 'workbox-routing';
import {CacheFirst} from 'workbox-strategies';
import {ExpirationPlugin} from 'workbox-expiration';

registerRoute(
  ({request}) => request.destination === 'image',
  new CacheFirst({
    cacheName: 'images',
    plugins: [
      new ExpirationPlugin({
        maxEntries: 60,
        maxAgeSeconds: 30 * 24 * 60 * 60, // 30 Days
      }),
    ],
  })
);

커스텀 플러그인 메서드

Workbox 플러그인은 하나 이상의 콜백 함수를 구현해야 합니다. 전략에 플러그인을 추가하면 콜백 함수가 적절한 시점에 자동으로 실행됩니다. Strategy는 현재 요청 및 응답에 대한 콜백 함수 관련 정보를 전달하여 플러그인에서 작업을 실행하는 데 필요한 컨텍스트를 제공합니다. 다음과 같은 콜백 함수가 지원됩니다.

  • cacheWillUpdate: Response가 캐시를 업데이트하는 데 사용되기 전에 호출됩니다. 이 메서드에서 응답을 캐시에 추가하기 전에 변경할 수도 있고, 캐시 전체를 업데이트하지 않도록 null를 반환할 수도 있습니다.
  • cacheDidUpdate: 새 항목이 캐시에 추가되거나 기존 항목이 업데이트될 때 호출됩니다. 이 메서드를 사용하는 플러그인은 캐시 업데이트 후 작업을 실행하려는 경우에 유용할 수 있습니다.
  • cacheKeyWillBeUsed: 요청이 캐시 키로 사용되기 전에 호출됩니다. 이는 캐시 조회 (mode'read'일 때) 및 캐시 쓰기 (mode'write'일 때)에서 모두 발생합니다. 이 콜백은 URL을 사용하여 캐시에 액세스하기 전에 URL을 재정의하거나 정규화해야 하는 경우에 유용합니다.
  • cachedResponseWillBeUsed: 캐시의 응답이 사용되기 직전에 호출되므로 응답을 검사할 수 있습니다. 이 시점에서는 다른 응답을 반환하거나 null를 반환할 수 있습니다.
  • requestWillFetch: 요청이 네트워크로 이동하려고 할 때마다 호출됩니다. Request가 네트워크로 가기 직전에 변경해야 할 때 유용합니다.
  • fetchDidFail: 네트워크 연결이 끊어졌을 때 네트워크 요청이 실패할 때 호출되며 브라우저에서 네트워크에 연결되어 있을 때는 실행되지 않지만 오류 (예: 404 Not Found)를 수신한 경우에는 실행되지 않습니다.
  • fetchDidSucceed: HTTP 응답 코드와 관계없이 네트워크 요청이 성공할 때마다 호출됩니다.
  • handlerWillStart: 핸들러 로직이 실행되기 전에 호출되며, 초기 핸들러 상태를 설정해야 하는 경우 유용합니다. 예를 들어 핸들러가 응답을 생성하는 데 걸린 시간을 알고 싶다면 이 콜백에서 시작 시간을 기록해 둘 수 있습니다.
  • handlerWillRespond: 전략의 handle() 메서드가 응답을 반환하기 전에 호출됩니다. 이는 RouteHandler 또는 다른 맞춤 로직으로 반환하기 전에 응답을 수정해야 하는 경우 유용합니다.
  • handlerDidRespond: 전략의 handle() 메서드가 응답을 반환한 후에 호출됩니다. 최종 응답 세부정보를 기록하는 것이 유용할 수도 있습니다 (예: 다른 플러그인에서 변경한 후).
  • handlerDidComplete: 전략 호출에서 이벤트에 추가된 모든 수명 연장 프로미스가 결정된 후 호출됩니다. 이 기능은 캐시 적중 상태, 캐시 지연 시간, 네트워크 지연 시간, 기타 유용한 정보를 계산하기 위해 핸들러가 완료될 때까지 기다려야 하는 데이터를 보고해야 하는 경우에 유용합니다.
  • handlerDidError: 핸들러가 모든 소스에서 유효한 응답을 제공할 수 없는 경우 호출됩니다. 이는 완전히 실패하는 대신 일종의 대체 응답을 제공하기에 가장 적합한 시기입니다.

이러한 콜백은 모두 async이므로 캐시 또는 가져오기 이벤트가 관련 콜백의 관련 지점에 도달할 때마다 await를 사용해야 합니다.

플러그인에서 위의 콜백을 모두 사용한 경우 결과 코드는 다음과 같습니다.

const myPlugin = {
  cacheWillUpdate: async ({request, response, event, state}) => {
    // Return `response`, a different `Response` object, or `null`.
    return response;
  },
  cacheDidUpdate: async ({
    cacheName,
    request,
    oldResponse,
    newResponse,
    event,
    state,
  }) => {
    // No return expected
    // Note: `newResponse.bodyUsed` is `true` when this is called,
    // meaning the body has already been read. If you need access to
    // the body of the fresh response, use a technique like:
    // const freshResponse = await caches.match(request, {cacheName});
  },
  cacheKeyWillBeUsed: async ({request, mode, params, event, state}) => {
    // `request` is the `Request` object that would otherwise be used as the cache key.
    // `mode` is either 'read' or 'write'.
    // Return either a string, or a `Request` whose `url` property will be used as the cache key.
    // Returning the original `request` will make this a no-op.
    return request;
  },
  cachedResponseWillBeUsed: async ({
    cacheName,
    request,
    matchOptions,
    cachedResponse,
    event,
    state,
  }) => {
    // Return `cachedResponse`, a different `Response` object, or null.
    return cachedResponse;
  },
  requestWillFetch: async ({request, event, state}) => {
    // Return `request` or a different `Request` object.
    return request;
  },
  fetchDidFail: async ({originalRequest, request, error, event, state}) => {
    // No return expected.
    // Note: `originalRequest` is the browser's request, `request` is the
    // request after being passed through plugins with
    // `requestWillFetch` callbacks, and `error` is the exception that caused
    // the underlying `fetch()` to fail.
  },
  fetchDidSucceed: async ({request, response, event, state}) => {
    // Return `response` to use the network response as-is,
    // or alternatively create and return a new `Response` object.
    return response;
  },
  handlerWillStart: async ({request, event, state}) => {
    // No return expected.
    // Can set initial handler state here.
  },
  handlerWillRespond: async ({request, response, event, state}) => {
    // Return `response` or a different `Response` object.
    return response;
  },
  handlerDidRespond: async ({request, response, event, state}) => {
    // No return expected.
    // Can record final response details here.
  },
  handlerDidComplete: async ({request, response, error, event, state}) => {
    // No return expected.
    // Can report any data here.
  },
  handlerDidError: async ({request, event, error, state}) => {
    // Return a `Response` to use as a fallback, or `null`.
    return fallbackResponse;
  },
};

위에 나열된 콜백에서 사용할 수 있는 event 객체는 가져오기 또는 캐시 작업을 트리거한 원래 이벤트입니다. 경우에 따라 기존 이벤트가 없는 경우도 있으므로 코드에서 이벤트를 참조하기 전에 먼저 존재하는지 확인해야 합니다.

모든 플러그인 콜백에는 특정 플러그인 및 이 플러그인이 호출하는 전략에 고유한 state 객체도 전달됩니다. 즉, 동일한 플러그인의 다른 콜백이 실행한 작업에 따라 한 콜백이 조건부로 작업을 실행할 수 있는 플러그인을 작성할 수 있습니다 (예: requestWillFetch() 실행과 fetchDidSucceed() 또는 fetchDidFail() 실행 간의 차이 계산).

서드 파티 플러그인

개발한 플러그인을 프로젝트 외부에서 사용할 수 있다고 생각되면 모듈로 게시하는 것이 좋습니다. 다음은 커뮤니티에서 제공하는 Workbox 플러그인의 간단한 목록입니다.

npm 저장소에서 검색하여 커뮤니티에서 제공하는 더 많은 Workbox 플러그인을 확인할 수 있습니다.

마지막으로 Workbox 플러그인을 빌드하여 공유하려는 경우 게시할 때 workbox-plugin 키워드를 추가합니다. 참여가 필요하다면 트위터(@WorkboxJS)를 통해 알려주세요.