Ereignisse mit Service Workern verarbeiten

Anleitung zu Erweiterungs-Service-Worker-Konzepten

Übersicht

In dieser Anleitung erhalten Sie eine Einführung in die Service Worker von Chrome-Erweiterungen. Im Rahmen dieser Anleitung erstellen, erstellen Sie eine Erweiterung, mit der Nutzer schnell die Chrome API-Referenz aufrufen können über die Omnibox aufrufen. Nach Abschluss können Sie:

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

Vorbereitung

In diesem Leitfaden wird davon ausgegangen, dass Sie über grundlegende Kenntnisse in der Webentwicklung verfügen. Wir empfehlen Ihnen, Erweiterungen 101 und Hello World für eine Einführung in die Entwicklung von Erweiterungen.

Erweiterung erstellen

Erstellen Sie zuerst ein neues Verzeichnis namens quick-api-reference für die Erweiterungsdateien. Laden Sie den Quellcode aus unserem GitHub-Beispiel-Repository herunter.

Schritt 1: Service Worker registrieren

Erstellen Sie die manifest-Datei 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 einzige JavaScript-Datei benötigt. Du musst navigator.serviceWorker.register() nicht wie bei einer Webseite anrufen.

Erstellen Sie einen images-Ordner und laden Sie die Symbole 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 als ES Module in unserem Manifest deklarieren, mit dem wir Module in unseren Service Worker importieren 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");

Unter Skripts importieren finden Sie weitere Möglichkeiten zum Importieren mehrerer Dateien in einem Service Worker.

Optional: Fehler im Service Worker beheben

Ich werde Ihnen erklären, wie Sie die Service Worker-Logs finden und wissen, wann sie beendet wurden. Folgen Sie zuerst der Anleitung unter Entpackte Erweiterung laden.

Nach 30 Sekunden wird „Service Worker (inaktiv)“ angezeigt. Das bedeutet, dass der Service Worker beendet wurde. Klicken Sie auf den Service Worker (inaktiv) um es zu überprüfen. Die folgende Animation zeigt dies.

Haben Sie bemerkt, dass der Servicemitarbeiter ihn aufgeweckt hat? Wenn Sie den Service Worker in den Entwicklertools öffnen, bleibt er aktiv. Damit deine Erweiterung bei Beendigung des Service Workers korrekt funktioniert, musst du die Entwicklertools schließen.

Zerstören Sie nun die Erweiterung, um zu erfahren, wo Sie Fehler finden können. Löschen Sie z. B. „.js“, aus dem Import './sw-omnibox.js' in der Datei service-worker.js. 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 Informationen zur Fehlerbehebung im Erweiterungs-Service-Worker finden Sie unter Fehlerbehebung 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 mehrere Service-Worker-Sitzungen hinweg beizubehalten. Für den Speicherzugriff müssen wir die entsprechende Berechtigung im Manifest anfordern:

manifest.json:

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

Speichern Sie zuerst die Standardvorschläge. Wir können den Status initialisieren, wenn die Erweiterung zum ersten Mal installiert wird, indem wir das Ereignis runtime.onInstalled() überwachen:

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 keine window.localStorage zum Speichern von Werten. Außerdem sind Service Worker kurzlebige Ausführungsumgebungen. sie während der Browsersitzung des Nutzers wiederholt beendet werden, sodass sie nicht mehr kompatibel sind mit globalen Variablen. Verwenden Sie stattdessen chrome.storage.local, um Daten auf dem lokalen Computer zu speichern.

Weitere Informationen zu anderen Speicheroptionen für Erweiterungs-Service-Worker finden Sie unter Daten beibehalten anstatt globale Variablen zu verwenden.

Schritt 5: Veranstaltungen registrieren

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

In diesem Beispiel verwenden wir die chrome.omnibox API. Zuerst müssen Sie jedoch den Suchbegriff-Trigger für die Omnibox im Manifest deklarieren:

manifest.json:

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

Registrieren Sie jetzt die Omnibox-Ereignis-Listener auf der obersten Ebene des Skripts. Wenn der Nutzer das Wort für die Omnibox (api) in die Adressleiste eingibt, gefolgt von einem Tab oder einem Leerzeichen, zeigt Chrome eine Liste mit Vorschlägen an, die auf den im Speicher befindlichen Suchbegriffen basiert. Das Ereignis onInputChanged(), 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, wird über onInputEntered() die entsprechende Chrome API-Referenzseite geöffnet.

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() speichert die Omnibox-Eingabe unter 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 häufig verwendet, um verzögerte oder regelmäßige Durchführung von Aufgaben. Diese APIs können jedoch fehlschlagen, da der Planer die Timer abbricht, wenn der Dienst Worker beendet wird. Erweiterungen können stattdessen die chrome.alarms API verwenden.

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

manifest.json:

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

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

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 verwenden Inhaltsskripts, um den Inhalt der Seite zu lesen und zu ändern. Wenn ein Nutzer eine Chrome API-Referenzseite aufruft, aktualisiert das Inhaltsskript der Erweiterung die Seite mit dem Tipp des Tages. Er sendet eine Nachricht, um das Trinkgeld des Tages vom Service Worker anzufordern.

Deklarieren Sie zuerst das Content-Skript 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, um das Trinkgeld anzufordern. Fügen Sie dann eine Schaltfläche hinzu, mit der ein Pop-over mit dem Erweiterungstipp geöffnet wird. In diesem Code wird die Popover API der neuen 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;
}

Der letzte Schritt besteht darin, unserem Service Worker einen Nachrichten-Handler hinzuzufügen, 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:

Inhalt des Erweiterungsordners: „images“, „manifest.json“, „service-worker.js“, „sw-Omnibox.js“, „sw-tips.js“
und content.js

Erweiterung lokal laden

Wenn Sie eine entpackte Erweiterung im Entwicklermodus laden möchten, folgen Sie der Anleitung unter Hello World.

Referenzseite öffnen

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

Das sollte so aussehen:

<ph type="x-smartling-placeholder">
</ph> Kurze API-Referenz zum Öffnen der Laufzeit-API-Referenz <ph type="x-smartling-placeholder">
</ph> Schnelle API-Erweiterung zum Öffnen der Runtime API.

Tipp des Tages öffnen

Klicken Sie in der Navigationsleiste auf die Schaltfläche Tip, um den Erweiterungstipp zu öffnen.

<ph type="x-smartling-placeholder">
</ph> Tipp des Tages öffnen in <ph type="x-smartling-placeholder">
</ph> Schnelle API-Erweiterung, die den Tipp des Tages öffnet.

🎯 Mögliche Verbesserungen

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

  • Probieren Sie eine andere Möglichkeit aus, die Vorschläge der Omnibox zu implementieren.
  • Erstellen Sie ein eigenes benutzerdefiniertes modales Dialogfeld, um den Tipp für die Erweiterung anzuzeigen.
  • Zusätzliche Seite zu den Seiten der Web Extensions-API der MDN öffnen.

Bau weiter!

Sie haben diese Anleitung abgeschlossen 🎉. Verbessere deine Fähigkeiten weiter, indem du andere Anleitungen für Einsteiger:

Erweiterung Lerninhalte
Lesezeit Wenn Sie ein Element automatisch in eine bestimmte Gruppe von Seiten einfügen möchten.
Tabs-Manager Zum Erstellen eines Pop-ups, über das Browsertabs verwaltet werden.
Konzentrationsmodus Nach dem Klicken auf die Erweiterungsaktion wird der Code auf der aktuellen Seite ausgeführt.

Weiter erkunden

Wir empfehlen Ihnen, die folgenden Artikel zu lesen, um den Lernpfad für Erweiterungs-Service-Worker fortzusetzen: