Gérer les événements avec les service workers

Tutoriel sur les concepts des service workers d'extensions

Présentation

Ce tutoriel présente les service workers d'extensions Chrome. Dans le cadre de ce vous allez créer une extension permettant aux utilisateurs d'accéder rapidement à la documentation de référence de l'API Chrome. à l'aide de l'omnibox. Vous allez apprendre à effectuer les tâches suivantes :

  • Enregistrez le service worker et les modules d'importation.
  • Déboguer votre service worker d'extension.
  • Gérer l'état et gérer les événements
  • Déclencher des événements périodiques
  • Communiquer avec des scripts de contenu

Avant de commencer

Dans ce guide, nous partons du principe que vous avez des connaissances de base en développement Web. Nous vous recommandons de consulter Extensions 101 et Hello World, pour une présentation le développement d'extensions.

Créer l'extension

Commencez par créer un répertoire nommé quick-api-reference qui contiendra les fichiers d'extension. téléchargez le code source depuis notre dépôt d'exemples GitHub.

Étape 1: Enregistrez le service worker

Créez le fichier manifest à la racine du projet et ajoutez le code suivant:

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"
  }
}

Les extensions enregistrent leur service worker dans le fichier manifeste, qui n'accepte qu'un seul fichier JavaScript. Il n'est pas nécessaire d'appeler navigator.serviceWorker.register(), comme vous le feriez sur une page Web.

Créez un dossier images, puis téléchargez les icônes dans celui-ci.

Consultez les premières étapes du tutoriel "Temps de lecture" pour en savoir plus sur les métadonnées et les icônes de l'extension dans le fichier manifeste.

Étape 2: Importez plusieurs modules de service worker

Notre service worker implémente deux fonctionnalités. Pour faciliter la gestion, nous implémenterons chaque fonctionnalité dans un module distinct. Tout d'abord, nous devons déclarer le service worker en tant que module ES dans notre fichier manifeste, ce qui nous permet d'importer des modules dans notre service worker:

manifest.json:

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

Créez le fichier service-worker.js et importez deux modules:

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

Créez ces fichiers et ajoutez-y un journal de console.

sw-omnibox.js :

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

sw-tips.js :

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

Reportez-vous à la rubrique Importation de scripts pour découvrir d'autres manières d'importer plusieurs fichiers dans un service worker.

Facultatif: Déboguer le service worker

Je vais vous expliquer comment trouver les journaux de service worker et savoir quand ils sont arrêtés. Tout d'abord, suivez les instructions pour charger une extension non empaquetée.

Au bout de 30 secondes, le message "Service worker (inactive)" s'affiche. ce qui signifie que le service worker a été arrêté. Cliquez sur le service worker (inactif) pour l'inspecter. L'animation suivante le montre.

Avez-vous remarqué que l'inspection du service worker l'a réveillé ? Si vous ouvrez le service worker dans les outils de développement, il restera actif. Pour vous assurer que votre extension se comporte correctement lorsque votre service worker est arrêté, pensez à fermer les outils de développement.

À présent, cassez l'extension pour savoir où localiser les erreurs. Pour ce faire, vous pouvez supprimer ".js" à partir de l'importation './sw-omnibox.js' dans le fichier service-worker.js. Chrome ne pourra pas enregistrer le service worker.

Revenez à chrome://extensions et actualisez l'extension. Deux erreurs s'affichent:

Service worker registration failed. Status code: 3.

An unknown error occurred when fetching the script.

Consultez la section Déboguer les extensions pour découvrir d'autres méthodes pour déboguer le service worker d'extension.

Étape 4: Initialiser l'état

Chrome arrêtera les service workers dont ils n'ont plus besoin. Nous utilisons l'API chrome.storage pour conserver l'état sur les sessions de service workers. Pour accéder à l'espace de stockage, nous devons demander l'autorisation dans le fichier manifeste:

manifest.json:

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

Commencez par enregistrer les suggestions par défaut dans l'espace de stockage. Nous pouvons initialiser l'état lorsque l'extension est installée pour la première fois en écoutant l'événement 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']
    });
  }
});

Les service workers ne disposent pas d'un accès direct à l'objet window et ne peuvent donc pas utiliser window.localStorage pour stocker des valeurs. Par ailleurs, les service workers sont des environnements d'exécution à courte durée de vie. ils sont arrêtés à plusieurs reprises pendant la session de navigateur de l'utilisateur, ce qui les rend incompatibles avec variables globales. Utilisez plutôt chrome.storage.local, qui stocke les données sur la machine locale.

Pour en savoir plus sur les autres options de stockage pour les service workers d'extensions, consultez la section Persistance des données plutôt que d'utiliser des variables globales.

Étape 5: Enregistrez vos événements

Tous les écouteurs d'événements doivent être enregistrés de manière statique dans le champ d'application global du service worker. En d'autres termes, les écouteurs d'événements ne doivent pas être imbriqués dans des fonctions asynchrones. De cette façon, Chrome peut s'assurer que tous les gestionnaires d'événements sont restaurés en cas de redémarrage d'un service worker.

Dans cet exemple, nous allons utiliser l'API chrome.omnibox, mais nous devons d'abord déclarer le déclencheur de mot clé de l'omnibox dans le fichier manifeste:

manifest.json:

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

À présent, enregistrez les écouteurs d'événements de l'omnibox au premier niveau du script. Lorsque l'utilisateur saisit le mot clé de l'omnibox (api) dans la barre d'adresse, puis sur la touche de tabulation ou d'un espace, Chrome affiche une liste de suggestions basées sur les mots clés dans l'espace de stockage. L'événement onInputChanged(), qui utilise l'entrée utilisateur actuelle et un objet suggestResult, est chargé de renseigner ces 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);
});

Une fois que l'utilisateur a sélectionné une suggestion, onInputEntered() ouvre la page de référence de l'API Chrome correspondante.

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);
});

La fonction updateHistory() récupère les données saisies dans l'omnibox et les enregistre dans storage.local. Le terme de recherche le plus récent peut ainsi être utilisé ultérieurement comme suggestion dans l'omnibox.

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 });
}

Étape 6: Configurez un événement périodique

Les méthodes setTimeout() ou setInterval() sont couramment utilisées pour exécuter des requêtes différées ou périodiques tâches. Toutefois, ces API peuvent échouer, car le programmeur annule les minuteurs lorsque le service le nœud de calcul est arrêté. À la place, les extensions peuvent utiliser l'API chrome.alarms.

Commencez par demander l'autorisation "alarms" dans le fichier manifeste. De plus, pour récupérer les conseils sur les extensions à partir d'un emplacement hébergé à distance, vous devez demander une autorisation d'hébergement:

manifest.json:

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

L'extension récupère tous les conseils, en sélectionne un au hasard et l'enregistre dans l'espace de stockage. Nous allons créer une alarme qui se déclenchera une fois par jour pour mettre à jour le pourboire. Les alarmes ne sont pas enregistrées lorsque vous fermez Chrome. Nous devons donc vérifier si l'alarme existe et la créer si ce n'est pas le cas.

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);

Étape 7: Communiquez avec d'autres contextes

Les extensions utilisent des scripts de contenu pour lire et modifier le contenu de la page. Lorsqu'un utilisateur consulte une page de référence de l'API Chrome, le script de contenu de l'extension met à jour la page avec le conseil du jour. Il envoie un message pour demander le pourboire du jour au service worker.

Commencez par déclarer le script de contenu dans le fichier manifeste et ajoutez le modèle de correspondance correspondant à la documentation de référence de l'API Chrome.

manifest.json:

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

Créez un fichier de contenu. Le code suivant envoie un message au service worker demandant le pourboire. Ensuite, ajoute un bouton qui ouvrira un pop-up contenant le conseil de l'extension. Ce code utilise la nouvelle plate-forme Web API Popover.

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;
}

La dernière étape consiste à ajouter à notre service worker un gestionnaire de messages qui envoie une réponse au script de contenu avec le pourboire quotidien.

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;
  }
});

Tester son fonctionnement

Vérifiez que la structure de fichiers de votre projet se présente comme suit:

Contenu du dossier de l&#39;extension: dossier images, manifest.json, service-worker.js, sw-omnibox.js, sw-tips.js
et content.js

Charger votre extension en local

Pour charger une extension non empaquetée en mode développeur, suivez les étapes décrites dans Hello World.

Ouvrir une page de référence

  1. Saisissez le mot clé "api". dans la barre d'adresse du navigateur.
  2. Appuyer sur la touche de tabulation ou "espace".
  3. Saisissez le nom complet de l'API.
    • OU choisissez-en une dans une liste de recherches précédentes
  4. Une nouvelle page s'ouvre et affiche la documentation de référence de l'API Chrome.

Elle devrait se présenter comme ceci :

<ph type="x-smartling-placeholder">
</ph> Guide de référence rapide de l&#39;API pour ouvrir la documentation de référence de l&#39;API Runtime <ph type="x-smartling-placeholder">
</ph> Extension Quick API ouvrant l'API Runtime.

Ouvrir le conseil du jour

Cliquez sur le bouton Astuce situé dans la barre de navigation pour ouvrir l'astuce de l'extension.

<ph type="x-smartling-placeholder">
</ph> Afficher le conseil du jour dans <ph type="x-smartling-placeholder">
</ph> Extension d'API rapide ouvrant le conseil du jour.

🛍 Améliorations potentielles

En vous basant sur ce que vous avez appris aujourd'hui, essayez de réaliser l'une des tâches suivantes:

  • Découvrez un autre moyen d'implémenter les suggestions de l'omnibox.
  • Créez votre propre modale personnalisée pour afficher le conseil d'extension.
  • Ouvrez une page supplémentaire vers les pages de l'API de référence des extensions Web du MDN.

Continuez à développer !

Félicitations, vous avez terminé ce tutoriel 🎉. Continuez à améliorer vos compétences en terminant d'autres tutoriels pour débutants:

Extension Objectifs de l'atelier
Temps de lecture Pour insérer automatiquement un élément sur un ensemble spécifique de pages.
Gestionnaire d'onglets Pour créer un pop-up qui gère les onglets du navigateur :
Mode Sans distractions Permet d'exécuter du code sur la page actuelle après avoir cliqué sur l'action de l'extension.

Continuer à explorer

Pour poursuivre votre parcours de formation sur les service workers d'extensions, nous vous recommandons de consulter les articles suivants: