Optymalizowanie ładowania skryptów zewnętrznych w Next.js

Poznaj wizję komponentu skryptu Next.js, który zapewnia wbudowane rozwiązanie do optymalizacji wczytywania skryptów innych firm.

Około 45% żądań z witryn wyświetlanych na urządzeniach mobilnych i komputerach to żądania firm zewnętrznych, z czego 33% to skrypty. Rozmiar, czas oczekiwania i wczytywanie skryptów zewnętrznych może w znacznym stopniu wpłynąć na wydajność witryny. Komponent Next.js Script zawiera wbudowane sprawdzone metody i domyślne wartości, które pomagają deweloperom wprowadzać skrypty innych firm do aplikacji, a jednocześnie rozwiązywać potencjalne problemy ze skutecznością.

Skrypty innych firm i ich wpływ na wydajność

Skrypty innych firm umożliwiają deweloperom stron internetowych korzystanie z dotychczasowych rozwiązań do implementowania typowych funkcji i skracania czasu potrzebnego na tworzenie aplikacji. Twórcy tych skryptów nie mają jednak żadnej motywacji, aby uwzględniać wpływ na wydajność witryny, która korzysta z tych skryptów. Skrypty te są dla deweloperów czarną skrzynką.

Skrypty odpowiadają za znaczną liczbę bajtów danych innych firm pobieranych przez witryny z różnych kategorii żądań zewnętrznych. Domyślnie przeglądarka nadaje priorytety skryptom na podstawie ich położenia w dokumencie, co może opóźnić wykrycie lub wykonanie skryptów, które są kluczowe dla wygody użytkownika.

Biblioteki innych firm wymagane do układu powinny być wczytywane wcześnie, aby umożliwić renderowanie strony. Elementy stron trzecich, które nie są wymagane do początkowego renderowania, powinny być opóźnione, aby nie blokowały innych operacji przetwarzania w wątku głównym. Lighthouse przeprowadza 2 kontrole, aby oznaczać skrypty blokujące renderowanie lub blokujące główne wątki.

Audyty Lighthouse dotyczące wyeliminowania zasobów blokujących renderowanie i minimalizacji wykorzystania kodu zewnętrznego

Ważne jest, aby wziąć pod uwagę sekwencję wczytywania zasobów strony, aby kluczowe zasoby nie były opóźnione, a niekrytyczne nie blokowały zasobów o znaczeniu krytycznym.

Chociaż istnieją sprawdzone metody ograniczania wpływu firm zewnętrznych, nie każdy wie, jak je stosować w przypadku każdej używanej aplikacji. Może to być skomplikowane, ponieważ:

  • W przypadku witryn na urządzeniach mobilnych i komputerach w średnich witryny korzystają z 21–23 różnych usług zewnętrznych, w tym skryptów. Użytkowanie i zalecenia mogą się różnić w przypadku każdego z nich.
  • Implementacja wielu innych firm może różnić się w zależności od tego, czy używana jest konkretna platforma lub biblioteka UI.
  • Nowe biblioteki innych firm są często wprowadzane.
  • Różne wymagania biznesowe związane z tym samym zewnętrznym dostawcą utrudniają deweloperom ujednolicenie jego użycia.

Koncentracja Aurora na skryptach innych firm

W ramach współpracy z ramami i narzędziami do tworzenia stron internetowych open source Aurora zapewnia solidne domyślne ustawienia oraz narzędzia, które pomagają deweloperom poprawić aspekty wrażeń użytkowników, takie jak wydajność, dostępność, bezpieczeństwo i przygotowanie do korzystania na urządzeniach mobilnych. W 2021 r. skupiliśmy się na pomaganiu zespołom frameworków w ulepszaniu wrażeń użytkowników i ich danych dotyczących podstawowych wskaźników internetowych.

Jednym z najważniejszych kroków w kierunku osiągnięcia naszego celu, jakim jest poprawa wydajności frameworku, było zbadanie idealnej kolejności wczytywania skryptów innych firm w Next.js. Platformy takie jak Next.js są wyjątkowo dobrze przygotowane do udostępniania przydatnych domyślnych ustawień i funkcji, które pomagają deweloperom efektywnie wczytywać zasoby, w tym te pochodzące od innych firm. Przeanalizowaliśmy obszerne danearchiwum HTTP i Lighthouse, aby sprawdzić, które firmy zewnętrzne najczęściej blokują renderowanie w różnych ramach.

Aby rozwiązać problem blokowania skryptów innych firm używanych w aplikacji przez główny wątek, opracowaliśmy komponent skryptu. Komponent zawiera funkcje sekwencjonowania, dzięki czemu deweloperzy mają większą kontrolę nad ładowaniem skryptów innych firm.

Sekwencjonowanie skryptów innych firm bez komponentu frameworku

Dostępne wskazówki dotyczące ograniczania wpływu skryptów blokujących renderowanie zawierają następujące metody efektywnego wczytywania i porządkowania skryptów innych firm:

  1. Użyj atrybutu async lub defer z tagami <script>, które informują przeglądarkę o wczytaniu niekrytycznych skryptów innych firm bez blokowania parsowania dokumentu. Skrypty, które nie są wymagane do wstępnego wczytania strony lub pierwszej interakcji użytkownika, mogą być uznane za niekrytyczne.

       <script src="https://example.com/script1.js" defer></script>
       <script src="https://example.com/script2.js" async></script>
    
  2. Wcześniej nawiązuj połączenia z wymaganymi źródłami, korzystając z preconnect i dns-prefetch. Dzięki temu skrypty krytyczne będą mogły rozpocząć pobieranie wcześniej.

       <head>
           <link rel="preconnect" href="http://PreconnThis.com">
           <link rel="dns-prefetch" href="http://PrefetchThis.com">
       </head>
    
  3. Leniwe ładowanie zasobów i elementów zewnętrznych po zakończeniu wczytywania głównej treści strony lub gdy użytkownik przewinie stronę do miejsca, w którym się one znajdują.

Komponent skryptu Next.js

Komponent skryptu Next.js implementuje opisane wyżej metody sekwencyjności skryptów i zawiera szablon, który pozwala deweloperom zdefiniować strategię wczytywania. Gdy określisz odpowiednią strategię, będzie ona wczytywać się optymalnie, nie blokując innych kluczowych zasobów.

Komponent Skrypt opiera się na tagu HTML <script> i umożliwia określenie priorytetu wczytywania skryptów zewnętrznych za pomocą atrybutu strategii.

// Example for beforeInteractive:
<Script src="https://cdnjs.cloudflare.com/polyfill/v3/polyfill.min.js?features=IntersectionObserverEntry%2CIntersectionObserver" strategy="beforeInteractive" />

// Example for afterInteractive (default):
<Script src="https://example.com/samplescript.js" />

// Example for lazyonload:
<Script src="https://connect.facebook.net/en_US/sdk.js" strategy="lazyOnload" />

Atrybut strategia może przyjmować 3 wartości.

  1. beforeInteractive: ta opcja może być używana w przypadku ważnych skryptów, które powinny być wykonywane przed tym, jak strona stanie się interaktywna. Next.js zapewnia, że takie skrypty są wstrzykiwane do początkowego kodu HTML na serwerze i wykonywane przed innymi samodzielnie skompilowanymi skryptami JavaScript. Dobrze nadają się do tego celu mechanizmy zarządzania zgodą, skrypty do wykrywania botów lub biblioteki pomocnicze wymagane do renderowania ważnych treści.

  2. afterInteractive: to stosowana strategia domyślna i odpowiada wczytaniu skryptu z atrybutem odroczenia. Należy go używać w przypadku skryptów, które przeglądarka może uruchomić po tym, jak strona stanie się interaktywna, np. skryptów analitycznych. Skrypt Next.js wstawia te skrypty po stronie klienta, a są one uruchamiane po nawodnieniu strony. Dlatego, o ile nie określono inaczej, wszystkie skrypty innych firm zdefiniowane przy użyciu komponentu Script są odraczane przez Next.js, co zapewnia silną wartość domyślną.

  3. lazyOnload: ta opcja może służyć do wczytywania skryptów o niskim priorytecie z opóźnieniem, gdy przeglądarka jest nieaktywna. Funkcje dostarczane przez takie skrypty nie są wymagane od razu po tym, jak strona stanie się interaktywna. Dotyczy to np. czatu lub wtyczek mediów społecznościowych.

Deweloper może określić Next.js, jak jego aplikacja ma używać skryptu, podając strategię. Dzięki temu framework może stosować optymalizacje i sprawdzone metody wczytywania skryptu, zapewniając jednocześnie najlepszą sekwencję wczytywania.

Za pomocą komponentu skryptu deweloperzy mogą umieszczać skrypty innych firm w dowolnym miejscu w aplikacji, aby ładowały się one w późniejszym czasie, oraz na poziomie dokumentu w przypadku skryptów krytycznych. Oznacza to, że komponent skryptu może znajdować się w tym samym miejscu co komponent korzystający ze skryptu. Po nasyceniu skrypt zostanie wstrzyknięty do nagłówka początkowo wyrenderowanego dokumentu lub u dołu tekstu (w zależności od użytej strategii).

Pomiar wpływu

Na podstawie szablonów aplikacji handlowej i bloga wprowadzającego Next.js stworzyliśmy 2 aplikacje w wersji demonstracyjnej, które pomogły zmierzyć wpływ zastosowania skryptów innych firm. Często używane zewnętrzne usługi w Menedżerze tagów Google i w ramach wstawiania mediów społecznościowych zostały najpierw uwzględnione na stronach tych aplikacji bezpośrednio, a potem za pomocą komponentu skryptu. Następnie porównaliśmy skuteczność tych stron za pomocą narzędzia WebPageTest.

Skrypty innych firm w aplikacji handlu elektronicznego Next.js

W ramach tego demonstracyjnego szablonu aplikacji handlowej dodaliśmy do niego skrypty innych firm, jak pokazano poniżej.

Przed Po
Menedżer tagów Google z asynkronicznym tagiem Komponent skryptu z strategią = afterInteractive dla obu skryptów
Przycisk Obserwuj na Twitterze bez asynchronicznego lub opóźnionego działania
Konfiguracja skryptu i komponentu skryptu w wersji demonstracyjnej 1 z 2 skryptami.

Poniżej znajdziesz porównanie wizualne postępy w przypadku obu wersji handlowego pakietu startowego Next.js. Jak widać, LCP występuje prawie o 1 s wcześniej, gdy włączony jest komponent skryptu z właściwą strategią wczytywania.

Porównanie paska filmowego pokazujące improwizację w skali LCP

Skrypty innych firm na blogu Next.js

Do aplikacji demonstracyjnej bloga zostały dodane skrypty innych firm, jak pokazano poniżej.

Przed Po
Menedżer tagów Google z asynkronicznym tagiem Komponent skryptu ze strategią = leniwe ładowanie dla każdego z 4 skryptów
Przycisk Obserwuj na Twitterze z asynchronizacją
Przycisk subskrypcji w YouTube bez asynchroniczności lub opóźnienia
Przycisk Obserwuj LinkedIn bez synchronizacji i opóźniania
Konfiguracja skryptu i składnika skryptu w przypadku prezentacji 2 z 4 skryptami.
Film pokazujący postęp wczytywania strony indeksu z użyciem komponentu skryptu i bez niego Czas FCP komponentu skryptu został skrócony o 0,5 sekundy.

Jak widać na filmie, pierwsze wyrenderowanie treści (FCP) następuje po 0,9 sekundy na stronie bez komponentu skryptu i po 0,4 sekundy z tym komponentem.

Co dalej z komponentem skryptu

Opcje strategii afterInteractivelazyOnload zapewniają dużą kontrolę nad skryptami blokującymi renderowanie, ale badamy też inne opcje, które zwiększyłyby użyteczność komponentu Skrypt.

Korzystanie z procesów internetowych

Skrypty robocze mogą być używane do uruchamiania niezależnych skryptów w wątkach w tle, co może zwolnić wątek główny na potrzeby obsługi zadań związanych z przetwarzaniem interfejsu użytkownika i zwiększyć wydajność. Skrypty internetowe najlepiej nadają się do przenoszenia przetwarzania JavaScriptu, a nie do obsługi interfejsu użytkownika. Skrypty używane do obsługi klienta lub marketingu, które zwykle nie współpracują z interfejsem użytkownika, mogą być dobrymi kandydatami do wykonania w wątku w tle. Aby wyodrębnić takie skrypty z środowiska internetowego, można użyć lekkiej biblioteki zewnętrznej (PartyTown).

W przypadku obecnej implementacji komponentu skryptu Next.js zalecamy odroczenie tych skryptów w głównym wątku przez ustawienie strategii na afterInteractive lub lazyOnload. W przyszłości proponujemy wprowadzenie nowej opcji strategii 'worker', która pozwoli Next.js używać PartyTown lub rozwiązania niestandardowego do uruchamiania skryptów na elementach Web Worker. Zachęcamy deweloperów do komentowania tego RFC.

Minimalizowanie CLS

Treści zewnętrzne, takie jak reklamy, filmy lub kanały w mediach społecznościowych, mogą powodować zmiany układu podczas wczytywania opóźnionego. Ma to wpływ na wygodę użytkowników i dane skumulowane przesunięcie układu (CLS) w przypadku strony. CLS można zminimalizować, określając rozmiar kontenera, w którym zostanie wczytana osadzona treść.

Komponent skryptu może być używany do wczytywania elementów, które mogą powodować przesunięcia układu. Zastanawiamy się nad rozszerzeniem tego narzędzia o opcje konfiguracji, które pomogą zmniejszyć CLS. Może ona być dostępna w ramach komponentu skryptu lub jako komponent towarzyszący.

Komponenty opakowań

Składnia i strategia wczytywania służące do włączania popularnych skryptów innych firm, takich jak Google Analytics czy Menedżer tagów Google (GTM), są zwykle stałe. Można je dodatkowo opakować w poszczególne komponenty opakowania dla każdego typu skryptu. Deweloperom będzie dostępny tylko minimalny zestaw atrybutów związanych z aplikacją (np. identyfikator śledzenia). Komponenty obudowy ułatwiają deweloperom:

  1. Ułatwienie im dodawania popularnych tagów skryptu.
  2. Zapewnienie, że framework używa najbardziej optymalnej strategii.

Podsumowanie

Skrypty innych firm są zwykle tworzone, aby uwzględniać określone funkcje w witrynie, która je wykorzystuje. Aby zmniejszyć wpływ skryptów niekrytycznych, zalecamy ich opóźnianie, co komponent skryptu Next.js wykonuje domyślnie. Deweloperzy mają pewność, że zawarte skrypty nie spowodują opóźnienia w działaniu kluczowych funkcji, chyba że zastosują strategię beforeInteractive. Podobnie jak w przypadku komponentu Next.js Script, deweloperzy frameworków mogą też tworzyć te funkcje w ramach innych frameworków. Wspólnie z zespołem Nuxt.js aktywnie rozważamy wprowadzenie podobnego elementu. Na podstawie opinii użytkowników planujemy też wprowadzić dalsze ulepszenia elementu skryptu, aby objąć nim dodatkowe przypadki użycia.

Poświadczenia

Dziękujemy Karze Erickson, Janicklasowi Ralphowi, Katie Hempenius, Philipowi Waltonowi, Jeremy’emu WagnerowiAddy Osmani za opinie na temat tego posta.