Extensiones de Chrome: Extensión de la API para admitir la navegación instantánea

Dave Tapuska
Dave Tapuska

Resumen: La API de Extensions se actualizó para admitir la memoria caché atrás/adelante y precarga las navegaciones. Consulta la siguiente información para obtener más detalles.

Chrome ha trabajado incansablemente para lograr que la navegación sea más rápida. Las tecnologías de navegación instantánea como la caché atrás/adelante (enviada para computadoras en Chrome 96) y las reglas de especulación (enviadas en Chrome 103) mejoran la experiencia de ir hacia atrás y hacia adelante. En esta publicación, exploraremos las actualizaciones que realizamos a las APIs de extensiones de navegador para admitir estos nuevos flujos de trabajo.

Información sobre los tipos de páginas

Antes de la introducción de la Memoria caché atrás/adelante y la renderización previa, una pestaña individual tenía solo una página activa. Este siempre era el que estaba visible. Si un usuario regresa a la página anterior, se destruirá la página activa (página B) y se reconstruirá por completo la página anterior del historial (página A). Las extensiones no necesitaban preocuparse por la parte de las páginas del ciclo de vida porque solo había una para cada pestaña: el estado activo/visible.

Expulsión de la página activa
Expulsión de la página activa.

Con la memoria caché atrás/adelante y la renderización previa, ya no existe una relación de uno a uno entre las pestañas y las páginas. Ahora, cada pestaña almacena varias páginas y transiciones de páginas entre estados en lugar de destruirse y reconstruirse.

Por ejemplo, una página podría comenzar su vida como una página renderizada previamente (no visible), pasar a una página activa (visible) cuando el usuario hace clic en un vínculo y, luego, almacenarse en la Memoria caché atrás/adelante (no visible) cuando el usuario navega a otra página, todo sin que la página se destruya. Más adelante en este artículo, veremos las nuevas propiedades que se exponen para ayudar a las extensiones a comprender en qué estado se encuentran las páginas.

Tipos de páginas
Tipos de páginas.

Ten en cuenta que una pestaña puede tener una serie de páginas renderizadas previamente (no solo una), una sola página activa (visible) y una serie de páginas almacenadas en caché atrás/adelante.

¿Qué cambiará para los desarrolladores de extensiones?

ID de marco == 0

En Chromium, nos referimos al marco superior o principal como el marco más externo.

Los autores de extensiones que suponen que el frameId del marco más externo es 0 (una práctica recomendada anterior) pueden tener problemas. Dado que una pestaña ahora puede tener varios marcos más externos (páginas renderizadas previamente y almacenadas en caché), la suposición de que hay un único marco externo para una pestaña es incorrecta. frameId == 0 seguirá representando el marco más externo de la página activa, pero los marcos más externos de otras páginas de la misma pestaña no serán cero. Se agregó un nuevo campo frameType para solucionar este problema. Consulta la sección "¿Cómo puedo determinar si un marco es el más externo?" de esta publicación.

Ciclo de vida de los marcos en comparación con los documentos

Otro concepto que resulta problemático con las extensiones es el ciclo de vida del fotograma. Un marco aloja un documento (que está asociado con una URL confirmada). El documento puede cambiar (por ejemplo, mediante la navegación), pero frameId no, por lo que es difícil asociar que ocurrió algo en un documento específico solo con frameIds. Presentamos el concepto de documentId, que es un identificador único para cada documento. Si se navega por un marco y se abre un documento nuevo, el identificador cambiará. Este campo es útil para determinar cuándo las páginas cambian su estado de ciclo de vida (entre renderización previa/activa/almacenada en caché) porque se mantiene igual.

Eventos de navegación web

Los eventos del espacio de nombres chrome.webNavigation pueden activarse varias veces en la misma página según el ciclo de vida en el que se encuentren. Consulta las secciones "¿Cómo determino el ciclo de vida en el que se encuentra la página?" y "¿Cómo determino el momento en que transiciona una página?".

¿Cómo puedo saber en qué ciclo de vida se encuentra la página?

Se agregó el tipo DocumentLifecycle a varias APIs de extensiones en las que frameId estaba disponible anteriormente. Si el tipo DocumentLifecycle está presente en un evento (como onCommitted), su valor es el estado en el que se generó el evento. Siempre puedes consultar información desde los métodos WebNavigation getFrame() y getAllFrames(), pero siempre se prefiere el valor del evento. Si usas cualquiera de los dos métodos, ten en cuenta que el estado del fotograma puede cambiar entre el momento en que se genera el evento y el momento en que se resuelven las promesas que muestran ambos métodos.

El objeto DocumentLifecycle tiene los siguientes valores:

  • "prerender" : Actualmente no se presenta al usuario, pero se prepara para mostrarse al usuario.
  • "active": Se muestra al usuario.
  • "cached": Almacenado en la Memoria caché atrás/adelante.
  • "pending_deletion": Se está destruyendo el documento.

¿Cómo puedo determinar si un marco es el más externo?

Anteriormente, es posible que las extensiones hayan verificado si frameId == 0 a fin de determinar si el evento que ocurre es para el marco más externo o no. Como hay varias páginas en una pestaña, ahora tenemos varios marcos externos, por lo que la definición de frameId es problemática. Nunca recibirás eventos sobre un marco en caché atrás/adelante. Sin embargo, en el caso de los marcos renderizados previamente, el valor de frameId no será cero para el marco más externo. Por lo tanto, usar frameId == 0 como indicador para determinar si es el marco más externo es incorrecto.

Para ayudar con esto, presentamos un nuevo tipo llamado FrameType, de modo que determinar si el marco es el más externo ahora es fácil. FrameType tiene los siguientes valores:

  • "outermost_frame": Por lo general, se denomina el marco superior. Ten en cuenta que hay múltiplos de ellos. Por ejemplo, si tienes páginas almacenadas previamente y almacenadas en caché, cada una tendrá un marco más externo que podría llamarse el marco superior.
  • "fenced_frame": Reservado para uso futuro
  • "sub_frame": Por lo general, es un iframe.

Podemos combinar DocumentLifecycle con FrameType y determinar si un fotograma es el más externo activo. Por ejemplo: js tab.documentLifecycle == “active” && frameType == “outermost_frame”

¿Cómo resuelvo los problemas de tiempo de uso con los fotogramas?

Como se mencionó anteriormente, un marco aloja un documento y este puede navegar a un documento nuevo, pero la frameId no cambiará. Esto crea problemas cuando recibes un evento con solo un frameId. Si buscas la URL del marco puede ser diferente de cuando ocurrió el evento, esto se denomina un problema de hora de uso.

Para abordar esto, presentamos documentId (y parentDocumentId). El método webNavigation.getFrame() ahora hace que la frameId sea opcional si se proporciona un documentId. documentId cambiará cada vez que se navegue por un fotograma.

¿Cómo puedo determinar cuándo se realiza una transición de página?

Hay indicadores explícitos para determinar cuándo una página pasa de un estado a otro.

Veamos los eventos WebNavigation.

Para navegar por una página por primera vez, verás cuatro eventos en el orden que se indica a continuación. Ten en cuenta que estos cuatro eventos pueden ocurrir y el estado DocumentLifecycle puede ser "prerender" o "active".

onBeforeNavigate
onCommitted
onDOMContentLoaded
onCompleted

Esto se ilustra en el siguiente diagrama, en el que se muestra el cambio de documentId a "xyz" cuando la página renderizada previamente se convierte en la página activa.

El documentId cambia cuando la página renderizada previamente se convierte en la página activa.
documentId cambia cuando la página renderizada previamente se convierte en la página activa.

Cuando una página pase de la memoria caché atrás/adelante o la renderización previa al estado activo, habrá tres eventos más (pero DocumentLifecyle será "active").

onBeforeNavigate
onCommitted
onCompleted

El evento documentId se mantendrá igual que en los eventos originales. Esto se ilustra arriba cuando se activa documentId == xyz. Ten en cuenta que se activan los mismos eventos de navegación, excepto el evento onDOMContentLoaded, debido a que la página ya se cargó.

Si tienes comentarios o preguntas, no dudes en preguntar en el grupo chromium-extensions.