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에서 샘플 애플리케이션의 소스를 볼 수 있습니다.

다른 샘플 애플리케이션인 Scrapbook PWAWeb Share Target API와 함께 Content Indexing API를 사용하는 방법을 보여줍니다. 이 코드는 Content Indexing API를 Cache Storage 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()를 호출하면 색인에만 영향을 미칩니다. 캐시에서 아무것도 삭제하지 않습니다.

사용자 삭제 이벤트 처리

브라우저가 색인이 생성된 콘텐츠를 표시할 때 삭제 메뉴 항목이 포함된 자체 사용자 인터페이스를 포함할 수 있으므로 사용자가 이전에 색인이 생성된 콘텐츠를 더 이상 보지 않겠다고 표시할 수 있습니다. 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에서 기능의 우선순위를 정하는 데 도움이 되며 다른 브라우저 공급업체에 기능을 지원하는 것이 얼마나 중요한지 보여줍니다.

콘텐츠 색인 생성이 보안 및 개인정보 보호에 미치는 영향

W3C의 보안 및 개인 정보 보호 설문조사에 대한 응답으로 제공된 답변을 확인하세요. 다른 궁금한 점이 있으면 프로젝트의 GitHub 저장소를 통해 논의를 시작해 주세요.

Unsplash의 Maksym Kaharlytskyi님 제공 히어로 이미지