Rozszerzenia do Chrome: interfejs API rozszerzający o obsługę natychmiastowej nawigacji

Dave Tapuska
Dave Tapuska

TL;DR: zaktualizowaliśmy interfejs Extensions API, aby obsługiwać pamięć podręczną stanu strony internetowej i wstępnie wczytywać elementy nawigacyjne. Więcej informacji znajdziesz poniżej.

Zespół Chrome dokłada wszelkich starań, aby nawigacja była szybka. Technologie błyskawicznej nawigacji, takie jak pamięć podręczna stanu strony internetowej (wysłana w wersji na komputery w Chrome 96) i reguły spekulacyjne (dostępne w Chrome 103) usprawniają pracę zarówno w przyszłości, jak i w przyszłości. W tym poście omówimy zmiany wprowadzone w interfejsach API rozszerzeń przeglądarki, aby dostosować je do nowych przepływów pracy.

Typy stron

Przed wprowadzeniem pamięci podręcznej stanu strony internetowej i prerenderowania poszczególna karta miała tylko jedną aktywną stronę. Ta opcja była zawsze widoczna. Jeśli użytkownik wróci do poprzedniej strony, aktywna strona zostanie zniszczona (strona B), a poprzednia strona w historii zostanie całkowicie odtworzona (strona A). Rozszerzenia nie musiały się martwić, w której fazie cyklu życia znajdują się strony, ponieważ dla każdej karty był tylko jeden stan: aktywny lub widoczny.

Wyrzucenie aktywnej strony
Wyrzucenie aktywnej strony.

Dzięki pamięci podręcznej stanu strony internetowej i prerenderowaniu nie ma już relacji jeden do jednego między kartami a stronami. Teraz każda karta przechowuje wiele stron, a strony przechodzą między stanami, zamiast być usuwane i odtwarzane.

Na przykład strona może zacząć działać jako wstępnie wyrenderowana (niewidoczna) strona, przejście w aktywną (widoczną) stronę, gdy użytkownik kliknie link, i zapisana w pamięci podręcznej stanu strony internetowej (niewidoczna), gdy użytkownik przejdzie na inną stronę, bez jej zniszczenia. W dalszej części tego artykułu omówimy nowe właściwości, które pomogą rozszerzeniom określić, w jakiej stronie stanu się znajdują.

Typy stron
Typy stron

Pamiętaj, że karta może zawierać serię wstępnie renderowanych stron (a nie tylko jedną), jedną aktywną (widoczną) stronę oraz serię stron w pamięci podręcznej stanu strony internetowej.

Co się zmienia dla deweloperów rozszerzeń?

FrameId == 0

W Chromium najwyższą/główną ramką nazywamy ramką najbardziej zewnętrzną.

Autorzy rozszerzeń, którzy zakładają, że frameId najbardziej zewnętrznej ramki mają wartość 0 (wcześniejsza sprawdzona metoda), mogą napotkać problemy. Ponieważ karta może teraz mieć wiele zewnętrznych ramek (stron z wstępnie wyrenderowanymi i zapisanych w pamięci podręcznej), założenie, że karta ma jedną zewnętrzną ramkę, jest nieprawidłowe. frameId == 0 nadal będzie reprezentować najbardziej zewnętrzny element aktywnej strony, ale najbardziej zewnętrzne elementy innych stron na tej samej karcie będą inne niż 0. Aby rozwiązać ten problem, dodaliśmy nowe pole frameType. Przeczytaj sekcję „Jak określić, czy ramka jest najbardziej zewnętrzną?” tego wpisu.

Cykl życia ramek a dokumenty

Innym problemem związanym z rozszerzeniami jest cykl życia ramki. Ramka zawiera dokument (powiązany z zaakceptowanym adresem URL). Dokument może się zmieniać (np. podczas nawigacji), ale frameId pozostanie niezmieniony. Trudno więc powiązać coś, co dzieje się w konkretnym dokumencie, tylko z frameId. Wprowadzamy pojęcie documentId, które jest unikalnym identyfikatorem każdego dokumentu. Jeśli nastąpi przejście do ramki i otworzy się nowy dokument, identyfikator się zmieni. To pole jest przydatne do określania, kiedy strony zmieniają stan cyklu życia (między stanem wstępnym wyrenderowania, aktywnym i w pamięci podręcznej), ponieważ pozostaje ono takie samo.

Zdarzenia nawigacji internetowej

Zdarzenia w przestrzeni nazw chrome.webNavigation mogą być wywoływane wielokrotnie na tej samej stronie w zależności od cyklu życia. Zapoznaj się z sekcjami „Jak sprawdzić, na jakim etapie cyklu życia znajduje się strona?”„Jak określić, kiedy nastąpi przejście strony?”.

Jak mogę sprawdzić cykl życia strony?

Typ DocumentLifecycle został dodany do wielu interfejsów API rozszerzeń, w przypadku których frameId był wcześniej dostępny. Jeśli zdarzenie ma typ DocumentLifecycle (np. onCommitted), jego wartość to stan, w którym zostało wygenerowane. Zawsze możesz wysłać zapytanie o informacje z metod WebNavigation getFrame()getAllFrames(), ale zalecamy korzystanie z wartości z zdarzenia. Jeśli używasz którejś z tych metod, pamiętaj, że stan ramki może się zmienić między momentem wygenerowania zdarzenia a rozwiązaniem obietnic zwracanych przez obie metody.

DocumentLifecycle zawiera te wartości:

  • "prerender”: nie jest obecnie wyświetlany użytkownikowi, ale jest przygotowywany do wyświetlenia.
  • "active": aktualnie wyświetlane użytkownikowi.
  • "cached": przechowywane w pamięci podręcznej stanu strony internetowej.
  • "pending_deletion": dokument jest niszczony.

Jak mogę określić, czy ramka jest ramką zewnętrzną?

Wcześniej rozszerzenia mogły sprawdzać, czy frameId == 0, aby określić, czy zdarzenie dotyczy zewnętrznego elementu ramki. Ponieważ na jednej karcie znajduje się wiele stron, mamy teraz wiele najbardziej zewnętrznych ramek, dlatego definicja parametru frameId jest problematyczna. Nigdy nie otrzymasz zdarzeń dotyczących ramki w pamięci podręcznej stanu strony internetowej. Jednak w przypadku wstępnie wyrenderowanych klatek wartość frameId będzie różna od 0 w przypadku najbardziej zewnętrznej ramki. Dlatego użycie frameId == 0 jako sygnału do określenia, czy jest to najbardziej zewnętrzny element, jest nieprawidłowe.

Aby ułatwić to zadanie, wprowadziliśmy nowy typ o nazwie FrameType, dzięki czemu teraz łatwo określić, czy dany element jest rzeczywiście najbardziej zewnętrznym elementem. Wartości FrameType:

  • "outermost_frame": zwykle określana jako najwyższa klatka. Pamiętaj, że są one wielokrotnościami. Jeśli np. masz strony wstępnie renderowane i przechowywane w pamięci podręcznej, każda z nich ma najbardziej zewnętrzną ramkę, którą można nazwać najwyższą ramką.
  • "fenced_frame": zarezerwowany do użycia w przyszłości.
  • "sub_frame": zwykle element iframe.

Możemy połączyć DocumentLifecycleFrameType i określić, czy klatka jest aktywną zewnętrzną klatką. Na przykład: tab.documentLifecycle === “active” && frameType === “outermost_frame”

Jak rozwiązywać problemy z czasem użytkowania w przypadku ramek?

Jak już wspomnieliśmy, ramka może wyświetlać dokument i przechodzić do nowego dokumentu, ale frameId nie ulegnie zmianie. Powoduje to problemy, gdy otrzymasz zdarzenie z tylko frameId. Jeśli sprawdzisz adres URL ramki, może on być inny niż w momencie wystąpienia zdarzenia. Nazywamy to problemem związanym z czasem użycia.

Aby rozwiązać ten problem, wprowadziliśmy documentId (oraz parentDocumentId). Metoda webNavigation.getFrame() sprawia, że frameId jest opcjonalny, jeśli podano documentId. Pole documentId zmienia się przy każdym przejściu do ramki.

Jak określić, kiedy następuje przejście na inną stronę?

Istnieją wyraźne sygnały wskazujące na to, kiedy strona przechodzi między stanami.

Przyjrzyjmy się zdarzeniom WebNavigation.

Podczas pierwszej wizyty na dowolnej stronie zobaczysz 4 zdarzenia w kolejności podanej poniżej. Pamiętaj, że te 4 zdarzenia mogą wystąpić, gdy stan DocumentLifecycle ma wartość "prerender" lub "active".

onBeforeNavigate
onCommitted
onDOMContentLoaded
onCompleted

Na diagramie poniżej widać, jak documentId zmienia się na "xyz", gdy wstępnie renderowana strona staje się stroną aktywną.

Identyfikator documentId zmienia się, gdy wstępnie renderowana strona staje się stroną aktywną
W momencie, gdy wstępnie renderowana strona stanie się aktywną stroną, wartość documentId ulegnie zmianie.

Gdy strona przechodzi z pamięci podręcznej stanu strony internetowej lub prerenderowania do stanu aktywnego, występują 3 dodatkowe zdarzenia (ale DocumentLifecyle jest zastąpione przez "active").

onBeforeNavigate
onCommitted
onCompleted

Wartość documentId pozostanie taka sama jak w pierwotnych zdarzeniach. Powyższe przykłady pokazują, co się dzieje, gdy documentId = xyz. Pamiętaj, że wywoływane są te same zdarzenia nawigacji z wyjątkiem zdarzenia onDOMContentLoaded, ponieważ strona została już wczytana.

Jeśli masz jakieś pytania lub komentarze, możesz je zadać w grupie Chromium-extensions.