Start · Sprachen · JavaScript · Referenz · ContentIndex

ContentIndex

Schnittstelle

Über <code>ContentIndex</code> meldet eine Web-App offline verfügbare Inhalte (Artikel, Videos, Audio) beim Browser an, damit er sie gesammelt anzeigen kann.

seit JavaScript Experimentell: nur Chromium (Chrome/Edge 84+, vor Kategorie: webapi

Signatur

interface ContentIndex

Beschreibung

Die Schnittstelle ContentIndex gehört zur Content Index API. Eine Progressive Web App kann damit dem Browser mitteilen, welche Inhalte sie bereits für die Offline-Nutzung zwischengespeichert hat. Chrome für Android zeigt diese Einträge zum Beispiel im Bereich „Artikel für dich“ bzw. unter den Downloads an. So finden Nutzer offline lesbare Artikel oder gespeicherte Videos auch dann, wenn sie die App gerade nicht geöffnet haben.

Es gibt keinen Konstruktor. Du erreichst die Instanz über die Eigenschaft index einer ServiceWorkerRegistration, also im Fenster über navigator.serviceWorker.ready und im Service Worker über self.registration.index. Die Schnittstelle hat drei Methoden:

  • add(description): registriert einen Inhalt. Gibt Promise<undefined> zurück. Existiert die id schon, wird der Eintrag ersetzt.
  • delete(id): entfernt einen Eintrag. Gibt Promise<undefined> zurück.
  • getAll(): liefert Promise<ContentDescription[]> mit allen registrierten Einträgen.

Die API ersetzt keinen Cache, sie ist nur ein Verzeichnis. Die eigentlichen Daten musst du selbst ablegen, etwa mit der Cache API oder in IndexedDB. Löscht der Nutzer einen Eintrag in der Browser-Oberfläche, bekommt der Service Worker das Ereignis contentdelete. Dort solltest du die zugehörigen Daten aus dem Cache entfernen.

Parameter

Name Typ Default Beschreibung
$description Pflicht ContentDescription (Object) Argument von add(): ein Objekt, das den Inhalt beschreibt. Seine Felder stehen in den folgenden Zeilen.
$description.id Pflicht string Eindeutige Kennung des Eintrags. Dieselbe Kennung brauchst du später für delete(id).
$description.title Pflicht string Titel, den der Browser anzeigt.
$description.description Pflicht string Kurzbeschreibung des Inhalts.
$description.url Pflicht string URL des Inhalts. Sie muss zur selben Herkunft gehören, im Geltungsbereich des Service Workers liegen und offline funktionieren.
$description.category '' | 'homepage' | 'article' | 'video' | 'audio' '' Art des Inhalts. Der Browser kann danach gruppieren.
$description.icons Array<{src: string, sizes?: string, type?: string}> [] Vorschaubilder im Format der Icons aus dem Web-App-Manifest.
$id Pflicht string Argument von delete(): die Kennung des Eintrags, der entfernt werden soll.

Beispiele

Unterstützung prüfen und einen offline gespeicherten Artikel registrieren

const speichereArtikelOffline = async (artikel) => {
  const registration = await navigator.serviceWorker.ready;

  // Funktionserkennung: die API gibt es nur in Chromium
  if (!('index' in registration)) {
    console.log('Content Index API wird nicht unterstützt');
    return;
  }

  // Zuerst die Seite wirklich cachen, sonst lehnt add() ab
  const cache = await caches.open('artikel-v1');
  await cache.add(artikel.url);

  await registration.index.add({
    id: `artikel-${artikel.slug}`,
    title: artikel.titel,
    description: artikel.teaser,
    category: 'article',
    url: artikel.url,
    icons: [{ src: '/img/artikel-192.png', sizes: '192x192', type: 'image/png' }]
  });

  console.log('Registriert:', artikel.titel);
};

speichereArtikelOffline({
  slug: 'promises-erklaert',
  titel: 'Promises verständlich erklärt',
  teaser: 'Grundlagen zu then, catch und async/await',
  url: '/artikel/promises-erklaert'
});
Registriert: Promises verständlich erklärt

Alle registrierten Inhalte auflisten

const zeigeOfflineInhalte = async () => {
  const registration = await navigator.serviceWorker.ready;
  if (!('index' in registration)) return [];

  const eintraege = await registration.index.getAll();
  for (const { id, title, category } of eintraege) {
    console.log(`${id} [${category}]: ${title}`);
  }
  return eintraege;
};

zeigeOfflineInhalte();
artikel-promises-erklaert [article]: Promises verständlich erklärt

Eintrag löschen und auf Löschung durch den Nutzer reagieren (Service Worker)

// In der Seite: Eintrag und Cache-Daten gemeinsam entfernen
const entferneArtikel = async (id, url) => {
  const registration = await navigator.serviceWorker.ready;
  await registration.index.delete(id);
  const cache = await caches.open('artikel-v1');
  await cache.delete(url);
};

// In sw.js: Der Nutzer hat den Eintrag in der Browser-Oberfläche gelöscht
self.addEventListener('contentdelete', (event) => {
  // event.id enthält die Kennung des gelöschten Eintrags
  const slug = event.id.replace('artikel-', '');
  event.waitUntil(
    caches.open('artikel-v1').then((cache) => cache.delete(`/artikel/${slug}`))
  );
});

// Wichtig · Fallstricke

  • Experimentell: Die API gibt es nur in Chromium-Browsern, praktisch vor allem in Chrome für Android. Firefox und Safari unterstützen sie nicht. Prüfe die Unterstützung immer mit 'index' in registration und behandle die API als optionale Verbesserung.
  • Die API läuft nur in einem sicheren Kontext (HTTPS) und nur mit einem aktiven Service Worker.
  • Chrome prüft beim Aufruf von add(), ob die url offline tatsächlich ausgeliefert werden kann. Kann der fetch-Handler des Service Workers die Seite offline nicht liefern, wird das Promise mit einem TypeError abgelehnt. Speichere die Inhalte deshalb vor dem Aufruf von add() im Cache.
  • url und icons müssen zur selben Herkunft gehören. Die url muss außerdem im Geltungsbereich (Scope) des Service Workers liegen.
  • Das Verzeichnis und deine Cache-Daten laufen nicht automatisch synchron. Wenn du Cache-Einträge entfernst, rufe auch delete() auf. Umgekehrt solltest du auf contentdelete reagieren, sonst sieht der Nutzer tote Einträge oder es bleiben verwaiste Daten liegen.
  • Registriere nur Inhalte, die für Nutzer wirklich sinnvoll sind. Werbung oder Seiten mit dauernd wechselndem Inhalt gehören nicht hinein.