Extensions Chrome: API étendue pour prendre en charge la navigation instantanée

Dave Tapuska
Dave Tapuska

Résumé: L'API Extensions a été mise à jour pour prendre en charge le cache amélioré et précharger les navigations. Pour en savoir plus, reportez-vous aux informations ci-dessous.

Chrome s'efforce de rendre la navigation plus rapide. Les technologies de navigation instantanée telles que le cache avant/arrière (livré sur ordinateur dans Chrome 96) et les règles de spéculation (livrées dans Chrome 103) améliorent à la fois l'expérience de navigation avant et arrière. Dans cet article, nous allons examiner les modifications que nous avons apportées aux API des extensions de navigateur pour prendre en charge ces nouveaux workflows.

Comprendre les types de pages

Avant l'introduction du cache amélioré et du prérendu, un onglet individuel ne comportait qu'une seule page active. C'était toujours celui qui était visible. Si un utilisateur revient à la page précédente, la page active est détruite (Page B) et la page précédente de l'historique est entièrement reconstruite (Page A). Les extensions n'avaient pas à se soucier de la partie des pages du cycle de vie, car il n'y avait qu'une seule partie pour un onglet, à savoir l'état actif/visible.

Éviction de la page active
Éviction de la page active.

Avec le cache amélioré et le prérendu, il n'y a plus de relation un à un entre les onglets et les pages. Désormais, chaque onglet stocke plusieurs pages, et les pages passent d'un état à un autre au lieu d'être détruites et reconstruites.

Par exemple, une page peut commencer sa vie en tant que page pré-rendue (non visible), passer à une page active (visible) lorsque l'utilisateur clique sur un lien, puis être stockée dans le cache "Retour/Avance" (non visible) lorsque l'utilisateur accède à une autre page, sans que la page ne soit jamais détruite. Plus loin dans cet article, nous verrons les nouvelles propriétés exposées pour aider les extensions à comprendre l'état des pages.

Types de page
Types de pages.

Notez qu'un onglet peut comporter une série de pages prérendues (et pas seulement une), une seule page active (visible) et une série de pages mises en cache pour les fonctions Précédent/Suivant.

Qu'est-ce qui change pour les développeurs d'extensions ?

ID frame == 0

Dans Chromium, le cadre supérieur/principal est le cadre le plus externe.

Les auteurs d'extensions qui supposent que le frameId du frame le plus externe est 0 (bonne pratique précédente) peuvent rencontrer des problèmes. Étant donné qu'un onglet peut désormais comporter plusieurs cadres les plus externes (pages prérendues et mises en cache), l'hypothèse selon laquelle il existe un seul cadre le plus externe pour un onglet est incorrecte. frameId == 0 continuera de représenter le frame le plus externe de la page active, mais les frames les plus externes des autres pages du même onglet ne seront pas nuls. Un nouveau champ frameType a été ajouté pour résoudre ce problème. Consultez la section "Comment déterminer si un frame est le frame le plus externe ?" de cet article.

Cycle de vie des cadres par rapport aux documents

Un autre concept problématique avec les extensions est le cycle de vie du frame. Un frame héberge un document (qui est associé à une URL validée). Le document peut changer (en naviguant, par exemple), mais pas frameId. Il est donc difficile d'associer un événement dans un document spécifique aux seuls frameIds. Nous introduisons le concept d'un documentId, qui est un identifiant unique pour chaque document. Si un cadre est parcouru et ouvre un nouveau document, l'identifiant change. Ce champ est utile pour déterminer quand les pages changent d'état de cycle de vie (entre préchargement/actif/mise en cache), car il reste le même.

Événements de navigation Web

Les événements de l'espace de noms chrome.webNavigation peuvent se déclencher plusieurs fois sur la même page en fonction du cycle de vie dans lequel ils se trouvent. Consultez les sections Comment savoir dans quel cycle de vie se trouve la page ? et Comment déterminer à quel moment une page effectue une transition ?.

Comment savoir dans quelle phase du cycle de vie se trouve la page ?

Le type DocumentLifecycle a été ajouté à un certain nombre d'API d'extensions où frameId était auparavant disponible. Si le type DocumentLifecycle est présent sur un événement (par exemple, onCommitted), sa valeur correspond à l'état dans lequel l'événement a été généré. Vous pouvez toujours interroger des informations à partir des méthodes WebNavigation getFrame() et getAllFrames(), mais il est toujours préférable d'utiliser la valeur de l'événement. Si vous utilisez l'une de ces méthodes, sachez que l'état du frame peut changer entre le moment où l'événement a été généré et le moment où les promesses renvoyées par les deux méthodes sont résolues.

DocumentLifecycle peut avoir les valeurs suivantes :

  • "prerender" : actuellement non présenté à l'utilisateur, mais en préparation pour être éventuellement affiché.
  • "active": actuellement affiché à l'utilisateur.
  • "cached" : stocké dans le cache "Retour/Avance".
  • "pending_deletion" : le document est en cours de destruction.

Comment déterminer si un frame est le frame le plus externe ?

Auparavant, les extensions pouvaient vérifier si frameId == 0 pour déterminer si l'événement qui se produit concerne le frame le plus externe ou non. Avec plusieurs pages dans un onglet, nous avons désormais plusieurs cadres les plus externes. La définition de frameId est donc problématique. Vous ne recevrez jamais d'événements concernant un frame mis en cache amélioré. Toutefois, pour les frames prérendus, frameId ne sera pas nul pour le frame le plus externe. Il est donc incorrect d'utiliser frameId == 0 comme signal pour déterminer s'il s'agit de la trame la plus externe.

Pour vous aider, nous avons introduit un nouveau type appelé FrameType. Il est ainsi facile de déterminer si le frame est effectivement le frame le plus externe. FrameType peut avoir les valeurs suivantes :

  • "outermost_frame" : généralement appelé "frame" le plus élevé. Notez qu'il existe des multiples de ces valeurs. Par exemple, si vous avez des pages prérendues et mises en cache, chacune d'elles comporte un cadre externe qui peut être appelé "cadre le plus élevé".
  • "fenced_frame": réservé pour une utilisation ultérieure.
  • "sub_frame" : généralement un iFrame.

Nous pouvons combiner DocumentLifecycle avec FrameType et déterminer si un frame est le frame externe actif. Par exemple, tab.documentLifecycle === “active” && frameType === “outermost_frame”.

Comment résoudre les problèmes liés aux heures creuses avec les cadres ?

Comme indiqué ci-dessus, un frame héberge un document et peut accéder à un nouveau document, mais le frameId ne change pas. Cela crée des problèmes lorsque vous recevez un événement avec un seul frameId. Si vous recherchez l'URL du frame, il est possible qu'elle soit différente de celle au moment de l'événement. Il s'agit d'un problème de moment d'utilisation.

Pour y remédier, nous avons introduit documentId (et parentDocumentId). La méthode webNavigation.getFrame() rend désormais frameId facultatif si un documentId est fourni. Le documentId change chaque fois qu'un frame est navigué.

Comment déterminer quand une page passe à une autre ?

Des signaux explicites permettent de déterminer quand une page passe d'un état à un autre.

Examinons les événements WebNavigation.

Lors de la toute première navigation sur une page, quatre événements s'affichent dans l'ordre indiqué ci-dessous. Notez que ces quatre événements peuvent se produire lorsque l'état DocumentLifecycle est "prerender" ou "active".

onBeforeNavigate
onCommitted
onDOMContentLoaded
onCompleted

Cette approche est illustrée dans le diagramme ci-dessous, qui montre que documentId passe à "xyz" lorsque la page prérendu devient la page active.

Le documentId change lorsque la page prérendue devient la page active.
documentId change lorsque la page prérendue devient la page active.

Lorsqu'une page passe du cache "Retour/Avance" ou du préchargement à l'état actif, trois autres événements se produisent (mais DocumentLifecyle est "active").

onBeforeNavigate
onCommitted
onCompleted

Le documentId restera le même que dans les événements d'origine. Ceci est illustré ci-dessus, lorsque documentId == xyz s'active. Notez que les mêmes événements de navigation se déclenchent, à l'exception de l'événement onDOMContentLoaded, car la page a déjà été chargée.

Si vous avez des commentaires ou des questions, n'hésitez pas à les poser sur le groupe chromium-extensions.