Ereignisse mit Service Workern verarbeiten

Anleitung mit Konzepten der Erweiterungsservice-Worker

Überblick

Diese Anleitung bietet eine Einführung in die Service Worker für Chrome-Erweiterungen. Im Rahmen dieser Anleitung erstellen Sie eine Erweiterung, mit der Nutzer über die Omnibox schnell zu Chrome API-Referenzseiten wechseln können. Sie werden Folgendes lernen:

  • Registrieren Sie Ihren Service Worker und importieren Sie Module.
  • Beheben Sie Fehler im Erweiterungsdienst-Worker.
  • Status und Ereignisse verwalten
  • Regelmäßige Ereignisse auslösen
  • Mit Inhaltsskripten kommunizieren

Vorbereitung

In diesem Leitfaden wird vorausgesetzt, dass Sie über Grundkenntnisse in der Webentwicklung verfügen. Wir empfehlen, unter Extensions 101 und Hello World eine Einführung in die Entwicklung von Erweiterungen zu lesen.

Erweiterung erstellen

Erstellen Sie zuerst ein neues Verzeichnis namens quick-api-reference, in dem die Erweiterungsdateien gespeichert werden, oder laden Sie den Quellcode aus unserem GitHub-Beispiel-Repository herunter.

Schritt 1: Service Worker registrieren

Erstellen Sie die Manifestdatei im Stammverzeichnis des Projekts und fügen Sie den folgenden Code hinzu:

manifest.json:

{
  "manifest_version": 3,
  "name": "Open extension API reference",
  "version": "1.0.0",
  "icons": {
    "16": "images/icon-16.png",
    "128": "images/icon-128.png"
  },
  "background": {
    "service_worker": "service-worker.js",
  },
}

Erweiterungen registrieren ihren Service Worker im Manifest, das nur eine JavaScript-Datei akzeptiert. Du musst navigator.serviceWorker.register() nicht aufrufen, wie du es auf einer Webseite tun würdest.

Erstellen Sie einen images-Ordner und laden Sie die Symbole in diesen herunter.

Sieh dir die ersten Schritte der Anleitung zur Lesezeit an, um mehr über die Metadaten und Symbole der Erweiterung im Manifest zu erfahren.

Schritt 2: Mehrere Service Worker-Module importieren

Unser Service Worker implementiert zwei Funktionen. Zur besseren Verwaltbarkeit implementieren wir jede Funktion in einem separaten Modul. Zuerst müssen wir den Service Worker in unserem Manifest als ES-Modul deklarieren, damit Module in unseren Service Worker importiert werden können:

manifest.json:

{
 "background": {
    "service_worker": "service-worker.js",
    "type": "module"
  },
}

Erstellen Sie die Datei service-worker.js und importieren Sie zwei Module:

import './sw-omnibox.js';
import './sw-tips.js';

Erstellen Sie diese Dateien und fügen Sie jeder ein Konsolenprotokoll hinzu.

sw-omnibox.js:

console.log("sw-omnibox.js")

sw-tips.js:

console.log("sw-tips.js")

Weitere Möglichkeiten zum Importieren mehrerer Dateien in einen Service Worker finden Sie unter Skripts importieren.

Optional: Fehler im Service Worker beheben

Ich erkläre Ihnen, wie Sie die Service Worker-Logs finden und wissen, wann sie beendet wurden. Folgen Sie zuerst der Anleitung zum Laden einer entpackten Erweiterung.

Nach 30 Sekunden wird die Meldung „Service Worker (inactive)“ angezeigt, was bedeutet, dass der Service Worker beendet wurde. Klicken Sie auf den Link „Service Worker (inaktiv)“, um ihn zu prüfen. Die folgende Animation veranschaulicht dies.

Haben Sie bemerkt, dass es durch eine Überprüfung des Service Workers aufgeweckt wurde? Wenn du den Service Worker in den Entwicklertools öffnest, bleibt er aktiv. Damit deine Erweiterung nach dem Beenden des Service Workers korrekt funktioniert, musst du die Entwicklertools schließen.

Beschädigen Sie die Erweiterung nun, um zu erfahren, wo Fehler zu finden sind. Eine Möglichkeit besteht darin, die JS-Datei aus dem './sw-omnibox.js'-Import in der Datei service-worker.js zu löschen. Chrome kann den Service Worker nicht registrieren.

Gehen Sie zurück zu chrome://extensions und aktualisieren Sie die Erweiterung. Es werden zwei Fehler angezeigt:

Service worker registration failed. Status code: 3.

An unknown error occurred when fetching the script.

Weitere Möglichkeiten zum Debuggen des Erweiterungsdienst-Workers finden Sie unter Debugging bei Erweiterungen.

Schritt 4: Status initialisieren

Chrome fährt Service Worker herunter, wenn sie nicht benötigt werden. Wir verwenden die chrome.storage API, um den Status über alle Service Worker-Sitzungen hinweg beizubehalten. Für den Speicherzugriff müssen wir die Berechtigung im Manifest anfordern:

manifest.json:

{
  ...
  "permissions": ["storage"],
}

Speichern Sie zuerst die Standardvorschläge im Speicher. Der Status kann initialisiert werden, wenn die Erweiterung zum ersten Mal installiert wird, indem das Ereignis runtime.onInstalled() erfasst wird:

sw-omnibox.js:

...
// Save default API suggestions
chrome.runtime.onInstalled.addListener(({ reason }) => {
  if (reason === 'install') {
    chrome.storage.local.set({
      apiSuggestions: ['tabs', 'storage', 'scripting']
    });
  }
});

Service Worker haben keinen direkten Zugriff auf das Fensterobjekt und können daher nicht mit window.localStorage Werte speichern. Außerdem sind Service Worker kurzlebige Ausführungsumgebungen. Sie werden während der Browsersitzung eines Nutzers wiederholt beendet und sind dann nicht mehr mit globalen Variablen kompatibel. Verwenden Sie stattdessen chrome.storage.local, um Daten auf dem lokalen Computer zu speichern.

Informationen zu anderen Speicheroptionen für Extension Service Worker finden Sie unter Daten beibehalten, anstatt globale Variablen zu verwenden.

Schritt 5: Veranstaltungen registrieren

Alle Event-Listener müssen im globalen Bereich des Service Workers statisch registriert sein. Mit anderen Worten: Event-Listener sollten nicht in asynchronen Funktionen verschachtelt sein. So kann Chrome sicherstellen, dass bei einem Service Worker-Neustart alle Event-Handler wiederhergestellt werden.

In diesem Beispiel verwenden wir die chrome.omnibox API, aber zuerst müssen wir im Manifest den Trigger für Omnibox-Keywords deklarieren:

manifest.json:

{
  ...
  "minimum_chrome_version": "102",
  "omnibox": {
    "keyword": "api"
  },
}

Registrieren Sie nun die Omnibox-Ereignis-Listener auf oberster Ebene des Skripts. Wenn der Nutzer das Omnibox-Keyword (api) in die Adressleiste und dann einen Tabulator oder ein Leertaste eingibt, zeigt Chrome eine Liste mit Vorschlägen an, die auf den Suchbegriffen im Speicher basieren. Das onInputChanged()-Ereignis, das die aktuelle Nutzereingabe und ein suggestResult-Objekt verwendet, ist für das Ausfüllen dieser Vorschläge verantwortlich.

sw-omnibox.js:

...
const URL_CHROME_EXTENSIONS_DOC =
  'https://developer.chrome.com/docs/extensions/reference/';
const NUMBER_OF_PREVIOUS_SEARCHES = 4;

// Display the suggestions after user starts typing
chrome.omnibox.onInputChanged.addListener(async (input, suggest) => {
  await chrome.omnibox.setDefaultSuggestion({
    description: 'Enter a Chrome API or choose from past searches'
  });
  const { apiSuggestions } = await chrome.storage.local.get('apiSuggestions');
  const suggestions = apiSuggestions.map((api) => {
    return { content: api, description: `Open chrome.${api} API` };
  });
  suggest(suggestions);
});

Nachdem der Nutzer einen Vorschlag ausgewählt hat, öffnet onInputEntered() die entsprechende Chrome API-Referenzseite.

sw-omnibox.js:

...
// Open the reference page of the chosen API
chrome.omnibox.onInputEntered.addListener((input) => {
  chrome.tabs.create({ url: URL_CHROME_EXTENSIONS_DOC + input });
  // Save the latest keyword
  updateHistory(input);
});

Die Funktion updateHistory() übernimmt die Eingabe in der Omnibox in storage.local. So kann der letzte Suchbegriff später als Omnibox-Vorschlag verwendet werden.

sw-omnibox.js:

...
async function updateHistory(input) {
  const { apiSuggestions } = await chrome.storage.local.get('apiSuggestions');
  apiSuggestions.unshift(input);
  apiSuggestions.splice(NUMBER_OF_PREVIOUS_SEARCHES);
  return chrome.storage.local.set({ apiSuggestions });
}

Schritt 6: Wiederkehrenden Termin einrichten

Die Methoden setTimeout() und setInterval() werden in der Regel verwendet, um verzögerte oder regelmäßige Aufgaben auszuführen. Diese APIs können jedoch fehlschlagen, da der Planer die Timer abbricht, wenn der Service-Worker beendet wird. Erweiterungen können stattdessen die chrome.alarms API verwenden.

Fordere zuerst im Manifest die Berechtigung "alarms" an. Damit Sie die Tipps zu Erweiterungen von einem remote gehosteten Standort abrufen können, müssen Sie außerdem die Hostberechtigung anfordern:

manifest.json:

{
  ...
  "permissions": ["storage", "alarms"],
  "permissions": ["storage"],
  "host_permissions": ["https://extension-tips.glitch.me/*"],
}

Die Erweiterung ruft alle Tipps ab, wählt nach dem Zufallsprinzip ein Tipps aus und speichert es im Speicher. Wir erstellen einen Alarm, der einmal täglich ausgelöst wird, um den Tipp zu aktualisieren. Wecker werden nicht gespeichert, wenn du Chrome schließt. Wir müssen also prüfen, ob der Alarm existiert, und ihn erstellen, falls er nicht existiert.

sw-tips.js:

// Fetch tip & save in storage
const updateTip = async () => {
  const response = await fetch('https://extension-tips.glitch.me/tips.json');
  const tips = await response.json();
  const randomIndex = Math.floor(Math.random() * tips.length);
  return chrome.storage.local.set({ tip: tips[randomIndex] });
};

const ALARM_NAME = 'tip';

// Check if alarm exists to avoid resetting the timer.
// The alarm might be removed when the browser session restarts.
async function createAlarm() {
  const alarm = await chrome.alarms.get(ALARM_NAME);
  if (typeof alarm === 'undefined') {
    chrome.alarms.create(ALARM_NAME, {
      delayInMinutes: 1,
      periodInMinutes: 1440
    });
    updateTip();
  }
}

createAlarm();

// Update tip once a day
chrome.alarms.onAlarm.addListener(updateTip);

Schritt 7: Mit anderen Kontexten kommunizieren

Erweiterungen nutzen Inhaltsskripts, um den Inhalt der Seite zu lesen und zu ändern. Besucht ein Nutzer eine Chrome API-Referenzseite, aktualisiert das Inhaltsskript der Erweiterung die Seite mit dem Tipp des Tages. Sie sendet eine Nachricht, um das Trinkgeld vom Service Worker anzufordern.

Deklarieren Sie zuerst das Inhaltsskript im Manifest und fügen Sie das Übereinstimmungsmuster hinzu, das der Referenzdokumentation zur Chrome API entspricht.

manifest.json:

{
  ...
  "content_scripts": [
    {
      "matches": ["https://developer.chrome.com/docs/extensions/reference/*"],
      "js": ["content.js"]
    }
  ]
}

Erstellen Sie eine neue Inhaltsdatei. Mit dem folgenden Code wird eine Nachricht an den Service Worker gesendet, in der der Tipp angefordert wird. Fügt dann eine Schaltfläche hinzu, mit der ein Pop-over mit dem Erweiterungstipp geöffnet wird. In diesem Code wird die neue Popover API der Webplattform verwendet.

content.js:

(async () => {
  // Sends a message to the service worker and receives a tip in response
  const { tip } = await chrome.runtime.sendMessage({ greeting: 'tip' });

  const nav = document.querySelector('.upper-tabs > nav');
  
  const tipWidget = createDomElement(`
    <button type="button" popovertarget="tip-popover" popovertargetaction="show" style="padding: 0 12px; height: 36px;">
      <span style="display: block; font: var(--devsite-link-font,500 14px/20px var(--devsite-primary-font-family));">Tip</span>
    </button>
  `);

  const popover = createDomElement(
    `<div id='tip-popover' popover style="margin: auto;">${tip}</div>`
  );

  document.body.append(popover);
  nav.append(tipWidget);
})();

function createDomElement(html) {
  const dom = new DOMParser().parseFromString(html, 'text/html');
  return dom.body.firstElementChild;
}

Im letzten Schritt fügen Sie unserem Service Worker einen Nachrichten-Handler hinzu, der eine Antwort mit dem täglichen Tipp an das Inhaltsskript sendet.

sw-tips.js:

...
// Send tip to content script via messaging
chrome.runtime.onMessage.addListener((message, sender, sendResponse) => {
  if (message.greeting === 'tip') {
    chrome.storage.local.get('tip').then(sendResponse);
    return true;
  }
});

Testen, ob es funktioniert

Überprüfen Sie, ob die Dateistruktur Ihres Projekts so aussieht:

Der Inhalt des Ordners der Erweiterung: „images“-Ordner, „manifest.json“, „service-worker.js“, „sw-Omnibox.js“, „sw-tips.js“ und „content.js“

Erweiterung lokal laden

Führen Sie die Schritte unter Hello world aus, um eine entpackte Erweiterung im Entwicklermodus zu laden.

Referenzseite öffnen

  1. Geben Sie „api“ in die Adressleiste des Browsers ein.
  2. Drücken Sie die Tabulatortaste oder die Leertaste.
  3. Geben Sie den vollständigen Namen der API ein.
    • ODER wähle aus einer Liste früherer Suchanfragen
  4. Die Chrome API-Referenzseite wird auf einer neuen Seite geöffnet.

Das sollte so aussehen:

Kurz-API-Referenz zum Öffnen der Laufzeit-API-Referenz
Schnelle API-Erweiterung zum Öffnen der Runtime API.

Tipp des Tages öffnen

Klicke in der Navigationsleiste auf die Schaltfläche Tipp , um den Tipp für die Erweiterung zu öffnen.

Täglichen Tipp öffnen in
Kurze API-Erweiterung zum Tipp des Tages.

🎯 Mögliche Verbesserungen

Basierend auf dem, was Sie heute gelernt haben, versuchen Sie Folgendes:

  • Entdecken Sie eine andere Möglichkeit, die Omnibox-Vorschläge zu implementieren.
  • Erstellen Sie Ihr eigenes benutzerdefiniertes Dialogfenster, in dem der Tipp zur Erweiterung angezeigt wird.
  • Öffne eine zusätzliche Seite mit den Referenz-API-Seiten der Web Extensions API des MDN.

Bau weiter!

Herzlichen Glückwunsch zum Abschluss dieses Tutorials 🎉. Absolvieren Sie weitere Tutorials für Einsteiger, um Ihre Fähigkeiten weiter zu verbessern:

Erweiterung Lerninhalte
Lesezeit Wenn Sie ein Element automatisch auf einer bestimmten Gruppe von Seiten einfügen möchten.
Tab-Manager Zum Erstellen eines Pop-ups, mit dem Browsertabs verwaltet werden.
Konzentrationsmodus Code auf der aktuellen Seite ausführen, nachdem auf die Erweiterungsaktion geklickt wurde

Weiter erkunden

In den folgenden Artikeln finden Sie weitere Informationen zu diesem Lernpfad: