Samouczek dotyczący koncepcji związanych z usługą rozszerzenia
Przegląd
Ten samouczek zawiera wprowadzenie do mechanizmów Service Worker w rozszerzeniach do Chrome. W ramach tego samouczka utworzysz rozszerzenie, które umożliwi użytkownikom szybkie przechodzenie do stron referencyjnych interfejsu Chrome API za pomocą paska adresu. Zapoznasz się z tymi zagadnieniami:
- Zarejestruj skrypt service worker i zaimportuj moduły.
- Debuguj skrypt service worker rozszerzenia.
- zarządzać stanem i obsługiwać zdarzenia,
- wywoływać zdarzenia okresowe;
- komunikować się ze skryptami treści;
Zanim rozpoczniesz
W tym przewodniku zakładamy, że masz podstawowe doświadczenie w zakresie tworzenia stron internetowych. Zalecamy zapoznanie się z artykułami Rozszerzenia 101 i Hello World, aby poznać podstawy tworzenia rozszerzeń.
Tworzenie rozszerzenia
Zacznij od utworzenia nowego katalogu o nazwie quick-api-reference
, w którym będą przechowywane pliki rozszerzenia, lub pobierz kod źródłowy z naszego repozytorium przykładowych rozszerzeń w GitHubie.
Krok 1. Zarejestruj service worker
Utwórz plik manifest w katalogu głównym projektu i dodaj ten kod:
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"
}
}
Rozszerzenia rejestrują swój service worker w pliku manifestu, który zawiera tylko jeden plik JavaScript.
Nie musisz wywoływać funkcji navigator.serviceWorker.register()
, jak w przypadku strony internetowej.
Utwórz folder images
, a następnie pobierz do niego ikony.
Zapoznaj się z pierwszymi krokami samouczka dotyczącego czasu czytania, aby dowiedzieć się więcej o metadanych i ikonach rozszerzenia w pliku manifestu.
Krok 2. Zaimportuj wiele modułów service worker
Service worker implementuje 2 funkcje. Aby ułatwić utrzymanie, każdą funkcję zaimplementujemy w osobnym module. Najpierw musimy zadeklarować w pliku manifestu, że nasz service worker jest modułem ES. Dzięki temu będziemy mogli importować moduły w naszym service workerze:
manifest.json:
{
"background": {
"service_worker": "service-worker.js",
"type": "module"
},
}
Utwórz plik service-worker.js
i zaimportuj 2 moduły:
import './sw-omnibox.js';
import './sw-tips.js';
Utwórz te pliki i dodaj do każdego z nich dziennik konsoli.
sw-omnibox.js:
console.log("sw-omnibox.js");
sw-tips.js:
console.log("sw-tips.js");
Więcej informacji o innych sposobach importowania wielu plików w usłudze znajdziesz w sekcji Importowanie skryptów.
Opcjonalnie: debugowanie service workera
Wyjaśnię, jak znaleźć logi service workera i kiedy się on zakończy. Najpierw postępuj zgodnie z instrukcjami wczytywania rozpakowanego rozszerzenia.
Po 30 sekundach zobaczysz komunikat „service worker (inactive)”, co oznacza, że proces service worker został zakończony. Aby go sprawdzić, kliknij link „service worker (inactive)” [usługa (nieaktywna)]. Pokazuje to poniższa animacja.
Czy widzisz, że sprawdzenie skryptu service worker spowodowało jego aktywację? Otwarcie service workera w narzędziach deweloperskich spowoduje, że pozostanie on aktywny. Aby mieć pewność, że rozszerzenie działa prawidłowo po zakończeniu działania procesu service worker, zamknij Narzędzia deweloperskie.
Teraz podziel rozszerzenie, aby dowiedzieć się, gdzie znajdują się błędy. Jednym ze sposobów jest usunięcie „.js” z importu './sw-omnibox.js'
w pliku service-worker.js
. Chrome nie będzie mógł zarejestrować skryptu service worker.
Wróć do chrome://extensions i odśwież rozszerzenie. Zobaczysz 2 błędy:
Service worker registration failed. Status code: 3.
An unknown error occurred when fetching the script.
Więcej sposobów debugowania skryptu service worker rozszerzenia znajdziesz w artykule Debugowanie rozszerzeń.
Krok 4. Zainicjuj stan
Chrome wyłącza procesy robocze, jeśli nie są potrzebne. Używamy interfejsu chrome.storage
API, aby utrwalać stan w sesjach service workerów. Aby uzyskać dostęp do pamięci, musimy poprosić o uprawnienia w pliku manifestu:
manifest.json:
{
...
"permissions": ["storage"],
}
Najpierw zapisz domyślne sugestie w pamięci. Stan możemy zainicjować podczas pierwszej instalacji rozszerzenia, nasłuchując zdarzenia runtime.onInstalled()
:
sw-omnibox.js:
...
// Save default API suggestions
chrome.runtime.onInstalled.addListener(({ reason }) => {
if (reason === 'install') {
chrome.storage.local.set({
apiSuggestions: ['tabs', 'storage', 'scripting']
});
}
});
Service workerzy nie mają bezpośredniego dostępu do obiektu window, dlatego nie mogą używać window.localStorage
do przechowywania wartości. Poza tym service worker to krótkotrwałe środowiska wykonawcze, które są wielokrotnie zamykane w trakcie sesji przeglądarki użytkownika, co sprawia, że są one niezgodne ze zmiennymi globalnymi. Zamiast tego użyj chrome.storage.local
, który przechowuje dane na urządzeniu lokalnym.
Więcej informacji o innych opcjach przechowywania danych w pracownikach usług rozszerzeń znajdziesz w artykule Przechowywanie danych zamiast używania zmiennych globalnych.
Krok 5. Zarejestruj zdarzenia
Wszystkie odbiorniki zdarzeń muszą być statycznie zarejestrowane w globalnym zakresie skryptu service worker. Innymi słowy, detektory zdarzeń nie powinny być zagnieżdżone w funkcjach asynchronicznych. Dzięki temu Chrome może mieć pewność, że w przypadku ponownego uruchomienia procesu service worker wszystkie moduły obsługi zdarzeń zostaną przywrócone.
W tym przykładzie użyjemy interfejsu chrome.omnibox
API, ale najpierw musimy zadeklarować aktywator słowa kluczowego w omniboksie w pliku manifestu:
manifest.json:
{
...
"minimum_chrome_version": "102",
"omnibox": {
"keyword": "api"
},
}
Teraz zarejestruj detektory zdarzeń paska adresu u góry skryptu. Gdy użytkownik wpisze słowo kluczowe omniboksu (api
) na pasku adresu, a następnie naciśnie klawisz Tab lub spację, Chrome wyświetli listę sugestii na podstawie słów kluczowych w pamięci. Za wypełnianie tych sugestii odpowiada zdarzenie onInputChanged()
, które przyjmuje bieżące dane wejściowe użytkownika i obiekt suggestResult
.
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);
});
Gdy użytkownik wybierze sugestię, onInputEntered()
otworzy odpowiednią stronę dokumentacji interfejsu Chrome API.
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);
});
Funkcja updateHistory()
pobiera dane z paska adresu i zapisuje je w storage.local
. Dzięki temu ostatnie wyszukiwane hasło będzie później dostępne jako sugestia w omniboksie.
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 });
}
Krok 6. Skonfiguruj wydarzenie cykliczne
Metody setTimeout()
i setInterval()
są często używane do wykonywania opóźnionych lub okresowych zadań. Jednak te interfejsy API mogą nie działać, ponieważ harmonogram anuluje timery po zakończeniu działania procesu usługi. Zamiast tego rozszerzenia mogą korzystać z interfejsu chrome.alarms
API.
Na początek poproś o uprawnienie "alarms"
w pliku manifestu:
manifest.json:
{
...
"permissions": ["storage"],
"permissions": ["storage", "alarms"],
}
Rozszerzenie pobierze wszystkie wskazówki, wybierze jedną losowo i zapisze ją w pamięci. Utworzymy alarm, który będzie włączać się raz dziennie, aby zaktualizować wskazówkę. Alarmy nie są zapisywane po zamknięciu Chrome. Musimy więc sprawdzić, czy alarm istnieje, a jeśli nie, utworzyć go.
sw-tips.js:
// Fetch tip & save in storage
const updateTip = async () => {
const response = await fetch('https://chrome.dev/f/extension_tips/');
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);
Krok 7. Komunikacja z innymi kontekstami
Rozszerzenia używają skryptów dotyczących zawartości do odczytywania i modyfikowania treści strony. Gdy użytkownik odwiedzi stronę referencyjną interfejsu Chrome API, skrypt treści rozszerzenia zaktualizuje ją, wyświetlając wskazówkę dnia. Wysyła wiadomość z prośbą o wskazówkę dnia do komponentu Service Worker.
Zacznij od zadeklarowania skryptu treści w pliku manifestu i dodania wzorca dopasowania odpowiadającego dokumentacji referencyjnej interfejsu Chrome API.
manifest.json:
{
...
"content_scripts": [
{
"matches": ["https://developer.chrome.com/docs/extensions/reference/*"],
"js": ["content.js"]
}
]
}
Utwórz nowy plik treści. Poniższy kod wysyła do service workera wiadomość z prośbą o napiwek. Następnie dodaje przycisk, który otwiera wyskakujące okienko z wskazówką dotyczącą rozszerzenia. Ten kod korzysta z nowego interfejsu Popover API platformy internetowej.
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;
}
Ostatnim krokiem jest dodanie do skryptu service worker funkcji obsługi wiadomości, która wysyła do skryptu treści odpowiedź z codzienną wskazówką.
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;
}
});
Sprawdzanie działania
Sprawdź, czy struktura plików projektu wygląda tak:
Wczytywanie rozszerzenia lokalnie
Aby załadować rozpakowane rozszerzenie w trybie programisty, wykonaj czynności opisane w sekcji Hello world.
Otwieranie strony referencyjnej
- Wpisz słowo kluczowe „api” na pasku adresu przeglądarki.
- Naciśnij „Tab” lub „spację”.
- Wpisz pełną nazwę interfejsu API.
- LUB wybierz z listy poprzednich wyszukiwań.
- Otworzy się nowa strona z dokumentacją interfejsu Chrome API.
Powinien on wyglądać podobnie do tego:

Otwieranie wskazówki dnia
Kliknij przycisk Wskazówka na pasku nawigacyjnym, aby otworzyć wskazówkę dotyczącą rozszerzenia.

🎯 Potencjalne ulepszenia
Na podstawie zdobytej dziś wiedzy spróbuj wykonać dowolne z tych zadań:
- Poznaj inny sposób wdrażania sugestii z omniboksu.
- Utwórz własne okno modalne do wyświetlania wskazówki dotyczącej rozszerzenia.
- Otwórz dodatkową stronę z dokumentacją interfejsu API rozszerzeń internetowych MDN.
Nie przestawaj budować!
Gratulujemy ukończenia tego samouczka 🎉. Rozwijaj dalej swoje umiejętności, korzystając z innych samouczków dla początkujących:
Rozszerzenie | Czego się nauczysz |
---|---|
Czas czytania | Aby automatycznie wstawić element na określonym zestawie stron. |
Menedżer kart | Aby utworzyć wyskakujące okienko, które zarządza kartami przeglądarki. |
Tryb pełnej koncentracji | Uruchamiać kod na bieżącej stronie po kliknięciu działania rozszerzenia. |
Przeglądaj dalej
Aby kontynuować naukę o procesach service worker rozszerzeń, zapoznaj się z tymi artykułami: