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

Dave Tapuska
Dave Tapuska

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

Chrome se esforzó mucho para que la navegación fuera rápida. Las tecnologías de navegación instantánea, como la memoria caché atrás/adelante (enviada para computadoras en Chrome 96) y las reglas de especulación (enviadas en Chrome 103) mejoran tanto la experiencia posterior como la posterior. En esta publicación, exploraremos las actualizaciones que implementamos en las APIs de extensiones del navegador para adaptarse a estos nuevos flujos de trabajo.

Comprender 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 solo tenía una página activa. Esta siempre era la 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
Expulsació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 bien, cada pestaña almacena varias páginas, y las páginas pasan de un estado a otro 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 haga clic en un vínculo y, luego, almacenarse en la Memoria caché atrás/adelante (no visible) cuando el usuario navegue a otra página, todo sin que la página nunca se destruya. Más adelante en este artículo, analizaremos las nuevas propiedades expuestas para ayudar a que las extensiones comprendan 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é para 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 fotogramas más externos (páginas renderizadas previamente y almacenadas en caché), la suposición de que hay un solo marco más 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 en la misma pestaña no serán cero. Se agregó un nuevo campo frameType para solucionar este problema. Consulta la sección "¿Cómo determino 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 genera problemas con las extensiones es el ciclo de vida del marco. Un marco aloja un documento (que está asociado con una URL confirmada). El documento puede cambiar (por ejemplo, navegando), pero el frameId no lo hará, por lo que es difícil asociar que algo sucedió en un documento específico con solo frameIds. Presentamos un 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 o almacenada en caché) porque permanece igual.

Eventos de navegación web

Los eventos en el 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 puedo saber en qué ciclo de vida se encuentra la página?" y "¿Cómo determino la transición de 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 de los métodos WebNavigation getFrame() y getAllFrames(), pero siempre se prefiere usar 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 generó el evento y el momento en que se resuelven las promesas que muestran ambos métodos.

DocumentLifecycle tiene los siguientes valores:

  • "prerender" : Actualmente no se presenta al usuario, pero se está preparando para mostrárselo.
  • "active": Actualmente se muestra al usuario.
  • "cached": Se almacena en la Memoria caché atrás/adelante.
  • "pending_deletion": El documento se está destruyendo.

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

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

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

  • "outermost_frame": Por lo general, se lo denomina marco superior. Ten en cuenta que son múltiplos de estos. Por ejemplo, si tienes páginas renderizadas previamente y almacenadas en caché, cada una tiene un marco externo que podría llamarse su 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 fotograma aloja un documento y puede navegar a un documento nuevo, pero frameId no cambiará. Esto crea problemas cuando recibes un evento con solo un frameId. Si buscas la URL del fotograma, puede ser diferente de cuando ocurrió el evento. Esto se denomina un problema de tiempo de uso.

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

¿Cómo determino la transición de una página?

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

Analicemos los eventos WebNavigation.

La primera vez que navegas por una página, verás cuatro eventos en el orden que se indica a continuación. Ten en cuenta que estos cuatro eventos podrían ocurrir con el estado DocumentLifecycle 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 de la renderización previa al estado activo, habrá tres eventos más (pero DocumentLifecyle será "active").

onBeforeNavigate
onCommitted
onCompleted

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

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