즉각적인 탐색 환경

서비스 워커로 기존의 미리 가져오기 기술을 보완합니다.

데미안 렌줄리
데미안 렌줄리
지우베르토 꼬치
Gilberto Cocchi

사이트에서 작업을 실행하는 데는 일반적으로 여러 단계가 포함됩니다. 예를 들어 전자상거래 웹사이트에서 제품을 구매하는 과정에는 제품을 검색하고, 결과 목록에서 항목을 선택한 다음, 장바구니에 항목을 추가하고, 결제를 통해 작업을 완료하는 과정이 포함될 수 있습니다.

기술적으로 여러 페이지를 이동하는 것은 탐색 요청을 의미합니다. 일반적으로 탐색 요청의 HTML 응답을 캐시하는 데 수명이 긴 Cache-Control 헤더를 사용하면 안 됩니다. 후속 네트워크 요청 체인과 HTML이 (적당히) 최신 상태인지 확인하려면 일반적으로 Cache-Control: no-cache를 사용하여 네트워크를 통해 충족되어야 합니다. 사용자가 새 페이지로 이동할 때마다 네트워크를 거쳐야 하는 것은 각 탐색이 느릴 수 있다는 의미입니다. 즉, 적어도 안정적으로 빠르지 않을 수 있습니다.

이러한 요청의 속도를 높이기 위해 사용자의 작업을 예상할 수 있는 경우 이러한 페이지와 애셋을 미리 요청하고 사용자가 링크를 클릭할 때까지 잠시 동안 캐시에 보관할 수 있습니다. 이 기법을 미리 가져오기라고 하며 일반적으로 미리 가져올 리소스를 나타내는 <link rel="prefetch"> 태그를 페이지에 추가하여 구현됩니다.

이 가이드에서는 서비스 워커를 기존 미리 가져오기 기법을 보완하여 사용할 수 있는 다양한 방법을 살펴봅니다.

프로덕션 케이스

MercadoLibre는 중남미 최대 전자상거래 사이트입니다. 탐색 속도를 높이기 위해 흐름의 일부에 <link rel="prefetch"> 태그를 동적으로 삽입합니다. 예를 들어 등록정보 페이지에서 사용자가 등록정보 하단으로 스크롤하자마자 다음 결과 페이지를 가져옵니다.

MercadoLibre의 목록 페이지 1과 2와 두 페이지를 연결하는 Link Prefetch 태그의 스크린샷

미리 가져온 파일은 '가장 낮은' 우선순위로 요청되며 리소스가 캐시 가능한지 여부에 따라 HTTP 캐시 또는 메모리 캐시에 저장되며, 이 기간은 브라우저에 따라 다릅니다. 예를 들어 Chrome 85 기준으로 이 값은 5분입니다. 리소스는 5분 동안 유지되며, 그 후에는 리소스에 대한 일반적인 Cache-Control 규칙이 적용됩니다.

서비스 워커 캐싱을 사용하면 프리패치 리소스의 수명을 5분 이상으로 연장할 수 있습니다.

예를 들어 이탈리아 스포츠 포털인 Virgilio Sport는 서비스 워커를 사용하여 홈페이지에서 가장 인기 있는 게시물을 미리 가져옵니다. 또한 Network Information API를 사용하여 2G 연결을 사용하는 사용자의 미리 가져오기를 방지합니다.

Virgilio Sport 로고

그 결과 Virgilio Sport가 3주 동안 관찰한 결과 기사 탐색의 로드 시간이 78% 개선되었으며 기사 노출수가 45% 증가했습니다.

미리 가져오기 후 영향 측정항목이 있는 Virgilio Sport 홈 및 기사 페이지의 스크린샷

Workbox로 사전 캐싱 구현

다음 섹션에서는 Workbox를 사용하여 이 작업을 서비스 워커에 완전히 위임하여 <link rel="prefetch">를 보완하거나 대체할 수 있는 여러 캐싱 기법을 서비스 워커에서 구현하는 방법을 보여줍니다.

1. 정적 페이지 및 페이지 하위 리소스 사전 캐시

사전 캐싱은 서비스 워커가 설치 중에 파일을 캐시에 저장하는 기능입니다.

다음과 같은 경우에 사전 캐싱을 사용하여 탐색 속도 향상이라는 미리 가져오기와 유사한 목표를 달성합니다.

정적 페이지 사전 캐싱

빌드 시 생성되는 페이지 (예: about.html, contact.html) 또는 완전히 정적인 사이트에서 사이트의 문서를 사전 캐시 목록에 추가하기만 하면 사용자가 액세스할 때마다 캐시에서 이미 사용할 수 있습니다.

workbox.precaching.precacheAndRoute([
  {url: '/about.html', revision: 'abcd1234'},
  // ... other entries ...
]);

페이지 하위 리소스 사전 캐싱

사이트의 여러 섹션에서 사용할 수 있는 정적 애셋 (예: JavaScript, CSS 등)을 미리 캐시하는 것이 일반적인 권장사항이며 미리 가져오기 시나리오에 도움이 될 수 있습니다.

전자상거래 사이트에서 탐색 속도를 높이려면 등록정보 페이지에서 <link rel="prefetch"> 태그를 사용하여 등록정보 페이지의 처음 몇 가지 제품의 제품 세부정보 페이지를 미리 가져올 수 있습니다. 제품 페이지 하위 리소스를 이미 사전 캐시한 경우 이를 통해 더 빠르게 탐색할 수 있습니다.

구현 방법은 다음과 같습니다.

  • 페이지에 <link rel="prefetch"> 태그를 추가합니다.
 <link rel="prefetch" href="/phones/smartphone-5x.html" as="document">
  • 페이지 하위 리소스를 서비스 워커의 사전 캐시 목록에 추가합니다.
workbox.precaching.precacheAndRoute([
  '/styles/product-page.ac29.css',
  // ... other entries ...
]);

2. 미리 가져오기 리소스의 전체 기간 연장

앞서 언급했듯이 <link rel="prefetch">는 제한된 시간 동안 HTTP 캐시의 리소스를 가져와 보관합니다. 그 후에는 리소스의 Cache-Control 규칙이 적용됩니다. Chrome 85부터 이 값은 5분입니다.

서비스 워커를 사용하면 프리패치 페이지의 전체 기간을 연장하는 동시에 해당 리소스를 오프라인에서 사용할 수 있는 추가적인 이점을 제공할 수 있습니다.

이전 예에서는 Workbox 런타임 캐싱 전략으로 제품 페이지를 미리 가져오는 데 사용된 <link rel="prefetch">를 보완할 수 있습니다.

이를 구현하는 방법은 다음과 같습니다.

  • 페이지에 <link rel="prefetch"> 태그를 추가합니다.
 <link rel="prefetch" href="/phones/smartphone-5x.html" as="document">
  • 이러한 유형의 요청에 대해 서비스 워커에서 런타임 캐싱 전략을 구현합니다.
new workbox.strategies.StaleWhileRevalidate({
  cacheName: 'document-cache',
  plugins: [
    new workbox.expiration.Plugin({
      maxAgeSeconds: 30 * 24 * 60 * 60, // 30 Days
    }),
  ],
});

이 경우 비활성 상태 재검증 전략을 사용하기로 결정했습니다. 이 전략에서는 캐시와 네트워크 모두에서 페이지를 동시에 요청할 수 있습니다. 응답은 캐시(사용 가능한 경우)에서 가져오며, 그렇지 않은 경우 네트워크에서 가져옵니다. 캐시는 요청이 성공할 때마다 네트워크 응답에 따라 항상 최신 상태로 유지됩니다.

3. 미리 가져오기를 서비스 워커에 위임

대부분의 경우 가장 좋은 방법은 <link rel="prefetch">를 사용하는 것입니다. 태그는 미리 가져오기를 최대한 효율적으로 수행하도록 설계된 리소스 힌트입니다.

하지만 어떤 경우에는 이 작업을 서비스 워커에 완전히 위임하는 것이 더 나을 수도 있습니다. 예를 들어 클라이언트 측에서 렌더링된 제품 등록정보 페이지에서 처음 몇 개의 제품을 미리 가져오려면 API 응답에 따라 여러 <link rel="prefetch"> 태그를 페이지에 동적으로 삽입해야 할 수 있습니다. 이로 인해 페이지의 기본 스레드에서 잠시 시간이 소비되고 구현이 더 어려워질 수 있습니다.

이 경우, '페이지-서비스 워커 통신 전략'을 사용하여 프리패치 작업을 서비스 워커에 완전히 위임하세요. worker.postMessage()를 사용하면 이러한 유형의 통신을 수행할 수 있습니다.

서비스 워커와 양방향 통신을 하는 페이지의 아이콘입니다.

Workbox Window 패키지는 이러한 유형의 통신을 간소화하여 실행 중인 기본 호출에 관한 많은 세부정보를 추상화합니다.

작업 상자 창을 사용하여 미리 가져오기는 다음과 같은 방법으로 구현할 수 있습니다.

  • 페이지에서: 서비스 워커를 호출하여 메시지 유형과 미리 가져올 URL 목록을 전달합니다.
const wb = new Workbox('/sw.js');
wb.register();

const prefetchResponse = await wb.messageSW({type: 'PREFETCH_URLS', urls: […]});
  • 서비스 워커에서 메시지 핸들러를 구현하여 미리 가져올 각 URL의 fetch() 요청을 실행합니다.
addEventListener('message', (event) => {
  if (event.data.type === 'PREFETCH_URLS') {
    // Fetch URLs and store them in the cache
  }
});