Учебное пособие, охватывающее концепции работы сотрудника службы расширения.
Обзор
В этом руководстве представлено введение в сервис-воркеры расширений Chrome. В рамках этого руководства вы создадите расширение, которое позволит пользователям быстро переходить к страницам справочника API Chrome с помощью адресной строки. Вы узнаете, как:
- Зарегистрируйте свой сервис-воркер и импортируйте модули.
- Отладьте работу службы расширения.
- Управление состоянием и обработка событий.
- Запускать периодические события.
- Общайтесь с помощью скриптов контента.
Прежде чем начать
Данное руководство предполагает наличие у вас базового опыта веб-разработки. Мы рекомендуем ознакомиться с курсами «Основы разработки расширений» и «Привет, мир!» для ознакомления с основами разработки расширений.
Создайте расширение
Для начала создайте новую директорию с именем quick-api-reference для хранения файлов расширения или загрузите исходный код из нашего репозитория примеров на GitHub .
Шаг 1: Зарегистрируйте работника службы поддержки.
Создайте файл манифеста в корне проекта и добавьте следующий код:
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"
}
}
Extensions register their service worker in the manifest, which only takes a single JavaScript file. There's no need to call navigator.serviceWorker.register() , like you would in a web page.
Создайте папку images , а затем загрузите в неё значки .
Ознакомьтесь с первыми шагами руководства по времени чтения, чтобы узнать больше о метаданных и значках расширения в манифесте.
Шаг 2: Импорт нескольких модулей сервис-воркеров.
Наш сервис-воркер реализует две функции. Для большей удобства сопровождения мы реализуем каждую функцию в отдельном модуле. Во-первых, нам нужно объявить сервис-воркер как модуль Elasticsearch в нашем манифесте, что позволит нам импортировать модули в наш сервис-воркер:
manifest.json:
{
"background": {
"service_worker": "service-worker.js",
"type": "module"
},
}
Создайте файл service-worker.js и импортируйте два модуля:
import './sw-omnibox.js';
import './sw-tips.js';
Создайте эти файлы и добавьте в каждый из них запись в консоль.
sw-omnibox.js:
console.log("sw-omnibox.js");
sw-tips.js:
console.log("sw-tips.js");
См. раздел «Импорт скриптов» , чтобы узнать о других способах импорта нескольких файлов в сервис-воркер.
Необязательно: отладка сервис-воркера.
Я объясню, как найти логи сервис-воркера и узнать, когда он завершил работу. Сначала следуйте инструкциям по загрузке распакованного расширения .
Через 30 секунд вы увидите сообщение "service worker (inactive)", что означает, что сервис-воркер завершил работу. Щелкните ссылку "service worker (inactive)", чтобы проверить это. Следующая анимация демонстрирует это.
Вы заметили, что проверка сервис-воркера активировала его? Открытие сервис-воркера в инструментах разработчика позволит ему оставаться активным. Чтобы убедиться, что ваше расширение работает корректно после завершения работы сервис-воркера, не забудьте закрыть инструменты разработчика.
Теперь давайте разберемся с расширением, чтобы понять, где искать ошибки. Один из способов сделать это — удалить ".js" из импорта './sw-omnibox.js' в файле service-worker.js . Chrome не сможет зарегистрировать сервис-воркер.
Вернитесь по адресу chrome://extensions и обновите страницу расширения. Вы увидите две ошибки:
Service worker registration failed. Status code: 3.
An unknown error occurred when fetching the script.
Дополнительные способы отладки обработчика службы расширений см. в разделе «Отладка расширений».
Шаг 4: Инициализация состояния
Chrome отключит сервис-воркеры, если они не нужны. Мы используем API chrome.storage для сохранения состояния между сессиями сервис-воркеров. Для доступа к хранилищу необходимо запросить разрешение в манифесте:
manifest.json:
{
...
"permissions": ["storage"],
}
Сначала сохраните предлагаемые по умолчанию варианты в хранилище. Мы можем инициализировать состояние при первой установке расширения, прослушивая событие 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']
});
}
});
Сервис-воркеры не имеют прямого доступа к объекту window и, следовательно, не могут использовать window.localStorage для хранения значений. Кроме того, сервис-воркеры представляют собой кратковременные среды выполнения; они многократно завершаются в течение сеанса работы браузера пользователя, что делает их несовместимыми с глобальными переменными. Вместо этого используйте chrome.storage.local , который хранит данные на локальном компьютере.
См. раздел «Сохранение данных вместо использования глобальных переменных» , чтобы узнать о других вариантах хранения данных для сотрудников служб распространения сельскохозяйственных знаний.
Шаг 5: Зарегистрируйте свои мероприятия
Все обработчики событий должны быть статически зарегистрированы в глобальной области видимости сервис-воркера. Другими словами, обработчики событий не должны быть вложены в асинхронные функции. Таким образом, Chrome сможет гарантировать восстановление всех обработчиков событий в случае перезагрузки сервис-воркера.
В этом примере мы будем использовать API chrome.omnibox , но сначала необходимо объявить ключевое слово trigger для omnibox в манифесте:
manifest.json:
{
...
"minimum_chrome_version": "102",
"omnibox": {
"keyword": "api"
},
}
Now, register the omnibox event listeners at the top level of the script. When the user enters the omnibox keyword ( api ) in the address bar followed by tab or space, Chrome will display a list of suggestions based on the keywords in storage. The onInputChanged() event, which takes the current user input and a suggestResult object, is responsible for populating these suggestions.
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);
});
После того, как пользователь выберет предложенный вариант, onInputEntered() откроет соответствующую страницу справочника API Chrome.
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);
});
Функция updateHistory() принимает данные из адресной строки и сохраняет их в storage.local . Таким образом, последний найденный запрос можно будет использовать позже в качестве подсказки для адресной строки.
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 });
}
Шаг 6: Настройте повторяющееся событие
Методы setTimeout() или setInterval() обычно используются для выполнения задач с задержкой или периодических действий. Однако эти API могут давать сбои, поскольку планировщик отменит таймеры при завершении работы сервис-воркера. Вместо этого расширения могут использовать API chrome.alarms .
Для начала запросите разрешение на отправку "alarms" в манифесте:
manifest.json:
{
...
"permissions": ["storage"],
"permissions": ["storage", "alarms"],
}
Расширение будет собирать все советы, выбирать один случайным образом и сохранять его в хранилище. Мы создадим будильник, который будет срабатывать раз в день для обновления совета. Будильники не сохраняются при закрытии Chrome. Поэтому нам нужно проверять, существует ли будильник, и создавать его, если нет.
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);
Шаг 7: Взаимодействие с другими контекстами
Расширения используют скрипты содержимого для чтения и изменения содержимого страницы. Когда пользователь посещает страницу со справочником API Chrome, скрипт содержимого расширения обновляет страницу, добавляя совет дня. Он отправляет сообщение с запросом на получение совета дня от сервис-воркера.
Для начала объявите скрипт содержимого в манифесте и добавьте шаблон соответствия, соответствующий справочной документации по API Chrome .
manifest.json:
{
...
"content_scripts": [
{
"matches": ["https://developer.chrome.com/docs/extensions/reference/*"],
"js": ["content.js"]
}
]
}
Создайте новый файл контента. Следующий код отправляет сообщение сервис-воркеру с запросом на подсказку. Затем добавляет кнопку, которая откроет всплывающее окно с подсказкой расширения. Этот код использует новый API всплывающих окон веб-платформы.
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;
}
Последний шаг — добавить обработчик сообщений в наш сервис-воркер, который будет отправлять ответ скрипту контента с ежедневной подсказкой.
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;
}
});
Проверьте, работает ли это.
Убедитесь, что файловая структура вашего проекта выглядит следующим образом:

Загрузите расширение локально.
Чтобы загрузить распакованное расширение в режиме разработчика, выполните действия, описанные в статье "Hello world" .
Откройте справочную страницу
- Введите ключевое слово "api" в адресную строку браузера.
- Нажмите клавишу «таб» или «пробел».
- Введите полное название API.
- ИЛИ выберите из списка предыдущих поисков
- Откроется новая страница со справочником по API Chrome.
Это должно выглядеть примерно так:

Откройте чаевые дня
Чтобы открыть подсказку по расширению, нажмите кнопку «Совет» на панели навигации.

🎯 Возможные улучшения
Исходя из того, что вы сегодня узнали, попробуйте выполнить одно из следующих заданий:
- Рассмотрите другой способ реализации подсказок в адресной строке.
- Создайте собственное модальное окно для отображения всплывающей подсказки о расширении.
- Откройте дополнительную страницу на страницах справочника API веб-расширений MDN.
Продолжайте строить!
Поздравляем с завершением этого урока 🎉. Продолжайте совершенствовать свои навыки, проходя другие уроки для начинающих:
| Расширение | Что вы узнаете |
|---|---|
| Время чтения | Для автоматической вставки элемента на определенный набор страниц. |
| Менеджер вкладок | Для создания всплывающего окна, управляющего вкладками браузера. |
| Режим фокусировки | Чтобы выполнить код на текущей странице после нажатия на действие расширения. |
Продолжайте исследование
Для продолжения обучения по программе подготовки специалистов по распространению знаний мы рекомендуем ознакомиться со следующими статьями: