Extensões do Chrome: ampliação da API para oferecer suporte à navegação instantânea

Dave Tapuska
Dave Tapuska

Resumo: a API Extensions foi atualizada para oferecer suporte ao cache de avanço e retorno, carregando as navegações. Veja os detalhes abaixo.

O Chrome está trabalhando muito para tornar a navegação rápida. Tecnologias de navegação instantânea, como o cache de avanço e retorno (enviado no Chrome 96 para computadores) e as regras de especulação (enviado no Chrome 103) melhoram a experiência de voltar e avançar. Nesta postagem, vamos explorar as atualizações feitas nas APIs de extensões de navegador para acomodar esses novos fluxos de trabalho.

Entender os tipos de páginas

Antes da introdução do cache de avanço e retorno e da pré-renderização, uma guia individual tinha apenas uma página ativa. Esse era sempre o que aparecia. Se um usuário retornar à página anterior, a página ativa será destruída (página B) e a página anterior no histórico será totalmente reconstruída (página A). As extensões não precisavam se preocupar com a parte do ciclo de vida em que as páginas estavam porque havia apenas uma guia, o estado ativo/visível.

Remoção da página ativa
Expulsão da página ativa.

Com o cache de avanço e retorno e a pré-renderização, não há mais uma relação um para um entre guias e páginas. Agora, cada guia armazena várias páginas e transições entre estados, em vez de serem destruídas e reconstruídas.

Por exemplo, uma página pode começar a vida como uma página pré-renderizada (não visível), fazer a transição para uma página ativa (visível) quando o usuário clicar em um link e ser armazenada no cache de avanço e retorno (não visível) quando o usuário navegar para outra página, tudo sem que a página seja destruída. Mais adiante neste artigo, vamos analisar as novas propriedades expostas para ajudar as extensões a entender em que estado as páginas estão.

Tipos de páginas
Tipos de páginas.

Uma guia pode ter uma série de páginas pré-renderizadas (não apenas uma), uma única página ativa (visível) e uma série de páginas em cache de avanço/retorno.

O que vai mudar para os desenvolvedores de extensões?

FrameId == 0

No Chromium, chamamos o frame principal/superior de frame externo.

Os autores de extensão que presumem que o frameId do frame mais externo é 0 (uma prática recomendada anterior) podem ter problemas. Como uma guia agora pode ter vários frames externos (páginas pré-renderizadas e em cache), a suposição de que há um único frame externo para uma guia está incorreta. O frameId == 0 ainda vai representar o frame externo da página ativa, mas os frames externos de outras páginas na mesma guia não serão iguais a zero. Um novo campo frameType foi adicionado para corrigir esse problema. Consulte a seção "Como determinar se um frame é o mais externo?" desta postagem.

Ciclo de vida de frames versus documentos

Outro conceito problemático com extensões é o ciclo de vida do frame. Um frame hospeda um documento (que está associado a um URL confirmado). O documento pode mudar (por exemplo, ao navegar), mas o frameId não muda. Por isso, é difícil associar que algo aconteceu em um documento específico com apenas frameIds. Estamos introduzindo o conceito de documentId, que é um identificador exclusivo para cada documento. Se um frame for navegado e abrir um novo documento, o identificador vai mudar. Esse campo é útil para determinar quando as páginas mudam de estado do ciclo de vida (entre prerender/ativa/em cache) porque ele permanece o mesmo.

Eventos de navegação na Web

Os eventos no namespace chrome.webNavigation podem ser acionados várias vezes na mesma página, dependendo do ciclo de vida em que estão. Consulte as seções "Como saber em qual ciclo de vida a página está?" e "Como determinar quando uma página faz a transição?".

Como saber em qual ciclo de vida a página está?

O tipo DocumentLifecycle foi adicionado a várias APIs de extensões em que o frameId estava disponível anteriormente. Se o tipo DocumentLifecycle estiver presente em um evento (como onCommitted), o valor será o estado em que o evento foi gerado. É possível consultar informações dos métodos WebNavigation getFrame() e getAllFrames(), mas o uso do valor do evento é sempre a melhor opção. Se você usar qualquer um dos métodos, saiba que o estado do frame pode mudar entre o momento em que o evento foi gerado e quando as promessas retornadas por ambos os métodos são resolvidas.

O DocumentLifecycle tem os seguintes valores:

  • "prerender": não está sendo apresentado ao usuário no momento, mas está se preparando para ser exibido.
  • "active": atualmente exibido para o usuário.
  • "cached": armazenado no cache de avanço e retorno.
  • "pending_deletion": O documento está sendo destruído.

Como determinar se um frame é o mais externo?

Anteriormente, as extensões podiam verificar se frameId == 0 para determinar se o evento que está ocorrendo é para o frame mais externo ou não. Com várias páginas em uma guia, agora temos vários frames externos, então a definição de frameId é problemática. Você nunca vai receber eventos sobre um frame de avanço/retorno em cache. No entanto, para frames pré-renderizados, o frameId será diferente de zero para o frame mais externo. Portanto, usar frameId == 0 como um sinal para determinar se ele é o frame mais externo está incorreto.

Para ajudar com isso, lançamos um novo tipo chamado FrameType para que determinar se o frame é realmente o mais externo seja fácil. FrameType tem os seguintes valores:

  • "outermost_frame": normalmente conhecido como o frame superior. Observe que há vários deles. Por exemplo, se você tiver páginas pré-renderizadas e armazenadas em cache, cada uma terá um frame externo, que pode ser chamado de frame principal.
  • "fenced_frame": reservado para uso futuro.
  • "sub_frame": normalmente um iframe.

Podemos combinar DocumentLifecycle com FrameType e determinar se um frame é o frame externo ativo. Exemplo: tab.documentLifecycle === “active” && frameType === “outermost_frame”

Como resolver problemas de tempo de uso com frames?

Como dissemos acima, um frame hospeda um documento, e o frame pode navegar para um novo documento, mas o frameId não muda. Isso cria problemas quando você recebe um evento com apenas um frameId. Se você procurar o URL do frame, ele pode ser diferente do que ocorreu no evento. Isso é chamado de problema de tempo de uso.

Para resolver esse problema, introduzimos documentId (e parentDocumentId). O método webNavigation.getFrame() agora torna o frameId opcional se um documentId for fornecido. O documentId vai mudar sempre que um frame for navegado.

Como determino quando uma página faz uma transição?

Há sinais explícitos para determinar quando uma página faz a transição entre estados.

Vamos analisar os eventos WebNavigation.

Na primeira navegação de qualquer página, você verá quatro eventos na ordem listada abaixo. Esses quatro eventos podem ocorrer com o estado DocumentLifecycle sendo "prerender" ou "active".

onBeforeNavigate
onCommitted
onDOMContentLoaded
onCompleted

Isso é ilustrado no diagrama abaixo, que mostra o documentId mudando para "xyz" quando a página pré-renderizada se torna a página ativa.

O documentId muda quando a página pré-renderizada se torna a página ativa
O documentId muda quando a página pré-renderizada se torna a página ativa.

Quando uma página transita do cache de avanço e retorno ou da renderização prévia para o estado ativo, há mais três eventos (mas com DocumentLifecyle sendo "active").

onBeforeNavigate
onCommitted
onCompleted

O documentId vai permanecer o mesmo que nos eventos originais. Isso é ilustrado acima quando documentId == xyz é ativado. Os mesmos eventos de navegação são acionados, exceto o evento onDOMContentLoaded, porque a página já foi carregada.

Se você tiver comentários ou dúvidas, entre em contato com o grupo chromium-extensions.