Content Indexing API를 사용하여 오프라인 사용이 가능한 페이지의 색인 생성

서비스 워커를 활성화하여 오프라인으로 작동하는 페이지를 브라우저에 알림

Content Indexing API란 무엇인가요?

프로그레시브 웹 앱을 사용한다는 것은 네트워크 연결의 현재 상태와 관계없이 이미지, 동영상, 기사 등 사람들이 중요하게 생각하는 정보에 액세스할 수 있다는 것을 의미합니다. 서비스 워커, Cache Storage API, IndexedDB와 같은 기술은 사용자가 PWA와 직접 상호작용할 때 데이터를 저장하고 제공하기 위한 구성요소를 제공합니다. 하지만 고품질 오프라인 우선 PWA를 빌드하는 것은 전체 과정의 일부일 뿐입니다. 오프라인일 때도 웹 앱의 콘텐츠를 사용할 수 있다는 사실을 모르는 사용자는 해당 기능을 구현하는 데 투입한 작업을 최대한 활용하지 못할 수 있습니다.

이것이 검색 문제입니다. PWA를 통해 사용자가 오프라인 지원 콘텐츠를 인식하여 사용 가능한 콘텐츠를 검색하고 볼 수 있게 하려면 어떻게 해야 할까요? Content Indexing API로 이 문제를 해결할 수 있습니다. 이 솔루션의 개발자 대상 부분은 서비스 워커의 확장 프로그램이며, 이를 통해 개발자는 오프라인 지원 페이지의 URL과 메타데이터를 브라우저에서 유지 관리하는 로컬 색인에 추가할 수 있습니다. 이 개선사항은 Chrome 84 이상에서 사용할 수 있습니다.

색인이 PWA 및 기타 설치된 PWA의 콘텐츠로 채워지면 아래와 같이 브라우저에 표시됩니다.

Chrome 새 탭 페이지에 있는 다운로드 메뉴 항목의 스크린샷.
먼저 Chrome의 새 탭 페이지에서 다운로드 메뉴 항목을 선택합니다.
색인에 추가된 미디어 및 기사입니다.
색인에 추가된 미디어 및 기사는 추천 기사 섹션에 표시됩니다.

또한 Chrome은 사용자가 오프라인 상태인 것을 감지하면 콘텐츠를 사전에 추천할 수 있습니다.

Content Indexing API는 콘텐츠를 캐싱하는 또 다른 방법이 아닙니다. 서비스 워커가 이미 캐시한 페이지에 대한 메타데이터를 제공하는 방법으로, 사용자가 원할 때 브라우저에서 페이지를 표시할 수 있습니다. Content Indexing API를 사용하면 캐시된 페이지의 검색 가능성을 높일 수 있습니다.

실제 사례 보기

Content Indexing API를 익히는 가장 좋은 방법은 샘플 애플리케이션을 사용해 보는 것입니다.

  1. 지원되는 브라우저와 플랫폼을 사용하고 있는지 확인하세요. 현재 Android의 Chrome 84 이상으로 제한됩니다. about://version로 이동하여 사용 중인 Chrome 버전을 확인하세요.
  2. https://contentindex.dev로 이동합니다.
  3. 목록에서 하나 이상의 항목 옆에 있는 + 버튼을 클릭합니다.
  4. (선택사항) 기기의 Wi-Fi 및 모바일 데이터 연결을 중지하거나 비행기 모드를 사용 설정하여 브라우저를 오프라인 상태로 전환하는 것을 시뮬레이션합니다.
  5. Chrome 메뉴에서 다운로드를 선택하고 추천 기사 탭으로 전환합니다.
  6. 이전에 저장한 콘텐츠를 탐색합니다.

GitHub에서 샘플 애플리케이션의 소스를 확인할 수 있습니다.

또 다른 샘플 애플리케이션인 스크랩북 PWA에서는 Content Indexing API를 Web Share Target API와 함께 사용하는 방법을 보여줍니다. 이 코드는 Cache Storage API를 사용하여 Content Indexing API를 웹 앱에서 저장한 항목과 동기화된 상태로 유지하는 기법을 보여줍니다.

API 사용

API를 사용하려면 앱에 서비스 워커와 오프라인으로 탐색할 수 있는 URL이 있어야 합니다. 웹 앱에 현재 서비스 워커가 없는 경우 Workbox 라이브러리를 사용해 서비스 워커를 간단하게 만들 수 있습니다.

오프라인 지원으로 색인을 생성할 수 있는 URL 유형은 무엇인가요?

API는 HTML 문서에 해당하는 URL 색인 생성을 지원합니다. 예를 들어 캐시된 미디어 파일의 URL은 직접 색인을 생성할 수 없습니다. 대신 미디어를 표시하고 오프라인에서 작동하는 페이지의 URL을 제공해야 합니다.

권장되는 패턴은 기본 미디어 URL을 쿼리 매개변수로 허용할 수 있는 '뷰어' HTML 페이지를 만든 다음 페이지의 추가 컨트롤이나 콘텐츠와 함께 파일의 콘텐츠를 표시하는 것입니다.

웹 앱은 현재 서비스 워커의 범위 내에 있는 콘텐츠 색인에만 URL을 추가할 수 있습니다. 즉, 웹 앱은 완전히 다른 도메인에 속하는 URL을 콘텐츠 색인에 추가할 수 없습니다.

개요

Content Indexing API는 메타데이터 추가, 나열, 삭제의 세 가지 작업을 지원합니다. 이러한 메서드는 ServiceWorkerRegistration 인터페이스에 추가된 새 속성 index에서 노출됩니다.

콘텐츠 색인 생성의 첫 번째 단계는 현재 ServiceWorkerRegistration의 참조를 가져오는 것입니다. navigator.serviceWorker.ready를 사용하는 것이 가장 간단한 방법입니다.

const registration = await navigator.serviceWorker.ready;

// Remember to feature-detect before using the API:
if ('index' in registration) {
  // Your Content Indexing API code goes here!
}

웹페이지 내부가 아닌 서비스 워커 내에서 Content Indexing API를 호출하는 경우 registration를 통해 직접 ServiceWorkerRegistration를 참조할 수 있습니다. ServiceWorkerGlobalScope.의 일부로 이미 정의되어 있습니다.

색인에 추가

URL 및 관련 메타데이터의 색인을 생성하려면 add() 메서드를 사용합니다. 항목이 색인에 추가되는 시점은 사용자가 선택할 수 있습니다. '오프라인 저장' 버튼 클릭과 같은 입력에 대한 응답으로 색인에 추가할 수 있습니다. 또는 캐시된 데이터가 주기적 백그라운드 동기화와 같은 메커니즘을 통해 업데이트될 때마다 자동으로 항목을 추가할 수 있습니다.

await registration.index.add({
  // Required; set to something unique within your web app.
  id: 'article-123',

  // Required; url needs to be an offline-capable HTML page.
  url: '/articles/123',

  // Required; used in user-visible lists of content.
  title: 'Article title',

  // Required; used in user-visible lists of content.
  description: 'Amazing article about things!',

  // Required; used in user-visible lists of content.
  icons: [{
    src: '/img/article-123.png',
    sizes: '64x64',
    type: 'image/png',
  }],

  // Optional; valid categories are currently:
  // 'homepage', 'article', 'video', 'audio', or '' (default).
  category: 'article',
});

항목을 추가하면 콘텐츠 색인에만 영향을 미치며 캐시에 아무것도 추가되지 않습니다.

특이 사례: 아이콘이 fetch 핸들러를 사용하는 경우 window 컨텍스트에서 add()를 호출합니다.

add()를 호출하면 Chrome은 색인이 생성된 콘텐츠 목록을 표시할 때 사용할 아이콘 사본이 있는지 확인하기 위해 각 아이콘의 URL을 요청합니다.

  • window 컨텍스트 (즉, 웹페이지에서)에서 add()를 호출하면 이 요청은 서비스 워커에서 fetch 이벤트를 트리거합니다.

  • 서비스 워커 내에서 (아마도 다른 이벤트 핸들러 내에서) add()를 호출하면 요청이 서비스 워커의 fetch 핸들러를 트리거하지 않습니다. 서비스 워커의 개입 없이 아이콘을 직접 가져옵니다. 아이콘이 fetch 핸들러를 사용하는 경우 이 점에 유의하세요. 아마도 아이콘이 네트워크가 아닌 로컬 캐시에만 존재하기 때문일 수 있습니다. 포함하는 경우 window 컨텍스트에서만 add()를 호출해야 합니다.

색인 콘텐츠 나열

getAll() 메서드는 색인이 생성된 항목과 해당 메타데이터의 반복 가능한 목록에 대한 프로미스를 반환합니다. 반환된 항목에는 add()로 저장된 모든 데이터가 포함됩니다.

const entries = await registration.index.getAll();
for (const entry of entries) {
  // entry.id, entry.launchUrl, etc. are all exposed.
}

색인에서 항목 삭제

색인에서 항목을 삭제하려면 삭제할 항목의 id와 함께 delete()를 호출합니다.

await registration.index.delete('article-123');

delete() 호출은 색인에만 영향을 미칩니다. 캐시에서 아무것도 삭제하지 않습니다.

사용자 삭제 이벤트 처리

브라우저가 색인이 생성된 콘텐츠를 표시할 때 Delete 메뉴 항목이 있는 자체 사용자 인터페이스를 포함하여 사용자가 이전에 색인이 생성된 콘텐츠를 모두 봤음을 나타낼 수 있습니다. Chrome 80의 삭제 인터페이스는 다음과 같이 표시됩니다.

삭제 메뉴 항목.

다른 사용자가 해당 메뉴 항목을 선택하면 웹 앱의 서비스 워커가 contentdelete 이벤트를 수신합니다. 이 이벤트를 처리하는 것은 선택사항이지만 서비스 워커는 로컬에 캐시된 미디어 파일과 같이 다른 사람이 처리했다고 표시한 콘텐츠를 '삭제'할 수 있습니다.

contentdelete 핸들러 내에서 registration.index.delete()를 호출할 필요는 없습니다. 이벤트가 발생했다면 브라우저에서 이미 관련 색인을 삭제한 것입니다.

self.addEventListener('contentdelete', (event) => {
  // event.id will correspond to the id value used
  // when the indexed content was added.
  // Use that value to determine what content, if any,
  // to delete from wherever your app stores it—usually
  // the Cache Storage API or perhaps IndexedDB.
});

API 설계에 관한 의견

API에 어색하거나 예상대로 작동하지 않는 문제가 있나요? 아니면 아이디어를 구현하는 데 필요한 누락된 부분이 있나요?

Content Indexing API 설명 GitHub 저장소에서 문제를 신고하거나 기존 문제에 관한 의견을 추가하세요.

구현에 문제가 있나요?

Chrome 구현에서 버그를 발견하셨나요?

https://new.crbug.com에서 버그를 신고합니다. 최대한 많은 세부정보와 간단한 재현 안내를 포함하고 구성요소Blink>ContentIndexing로 설정합니다.

API를 사용할 계획이신가요?

웹 앱에서 Content Indexing API를 사용할 계획인가요? 공개 지원은 Chrome에서 기능의 우선순위를 정하는 데 도움이 되며 다른 브라우저 공급업체에 이러한 기능을 지원하는 것이 얼마나 중요한지 알려줍니다.

  • 해시태그 #ContentIndexingAPI를 사용하여 @ChromiumDev로 트윗을 보내주시고 사용 중인 위치 및 방법에 대한 세부정보를 보내 주세요.

콘텐츠 색인 생성이 보안 및 개인 정보 보호에 미치는 영향은 무엇인가요?

W3C의 보안 및 개인 정보 보호 설문지에 나와 있는 답변을 확인하세요. 더 궁금한 점이 있으면 프로젝트의 GitHub 저장소를 통해 토론을 시작하세요.

Unsplash에 게재된 막심 카하리츠키의 히어로 이미지