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

Poznaj wizję komponentu skryptu Next.js, który udostępnia wbudowane rozwiązanie do optymalizacji wczytywania skryptów zewnętrznych.

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 mogą znacznie wpływać na wydajność witryny. Komponent Next.js Script zawiera wbudowane sprawdzone metody i ustawienia domyślne, aby pomóc deweloperom wprowadzać skrypty innych firm w aplikacjach, jednocześnie rozwiązując potencjalne problemy z wydajnością.

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

Skrypty innych firm umożliwiają programistom stron internetowych wykorzystanie istniejących rozwiązań do implementacji typowych funkcji i skrócenia czasu programowania. Jednak twórcy tych scenariuszy zwykle nie mają żadnej motywacji, aby brać pod uwagę wpływ tych działań na wydajność strony, z której korzystają. Skrypty te stanowią też czarną skrzynkę dla programistów, którzy z nich korzystają.

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 priorytet skryptom na podstawie tego, gdzie się znajdują w dokumencie, co może opóźniać wykrywanie lub wykonywanie skryptów krytycznych dla wygody użytkowników.

Biblioteki zewnętrzne wymagane do układu strony powinny być ładowane wcześnie, aby można było wyrenderować stronę. Zasoby zewnętrzne, które nie są wymagane do początkowego renderowania, powinny zostać odroczone, aby nie blokowały innego 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 pod kątem Eliminacji zasobów blokujących renderowanie i minimalizacji wykorzystania zasobów zewnętrznych

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 oddziaływania firm zewnętrznych, nie wszyscy wiedzą, jak je wdrożyć w każdej z tych firm. Może to być skomplikowane, ponieważ:

  • Witryny korzystają średnio z 21–23 różnych firm zewnętrznych (w tym skryptów) na urządzeniach mobilnych i komputerach. 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.
  • Często prezentowane są nowsze biblioteki innych firm.
  • Różne wymagania biznesowe związane z tą samą firmą zewnętrzną utrudniają deweloperom ustandaryzowanie jej stosowania.

Aurora skupia się na skryptach innych firm

W ramach współpracy Aurory z platformami i narzędziami internetowymi typu open source zapewniamy solidne ustawienia domyślne i sprawdzone narzędzia, które pomagają deweloperom poprawiać niektóre aspekty wygody użytkowników, takie jak wydajność, dostępność, bezpieczeństwo i gotowość do urządzeń mobilnych. W 2021 r. skupiliśmy się na pomaganiu platformom w zwiększaniu wygody użytkowników i potwierdzaniu ich podstawowych wskaźników internetowych.

Jednym z najważniejszych kroków w dążeniu do osiągnięcia naszego celu, jakim jest poprawa wydajności platformy, było znalezienie idealnej sekwencji wczytywania skryptów zewnętrznych w Next.js. Platformy takie jak Next.js mają wyjątkowe możliwości dostarczania przydatnych ustawień domyślnych i funkcji, które pomagają deweloperom skutecznie ładować zasoby, w tym zasoby innych firm. Przeanalizowaliśmy obszerne dane z archiwum HTTP i z Lighthouse, aby dowiedzieć się, które firmy zewnętrzne blokują renderowanie najczęściej na różnych platformach.

Aby rozwiązać problem blokujący wątki główne ze skryptami innych firm używanymi w aplikacji, stworzyliśmy komponent skryptu. Komponent zawiera funkcje sekwencjonowania, dzięki czemu deweloperzy mają większą kontrolę nad ładowaniem skryptów innych firm.

Sekwencjonowanie skryptów zewnętrznych bez komponentu platformy

Dostępne wskazówki dotyczące zmniejszania wpływu skryptów blokujących renderowanie zawierają następujące metody efektywnego wczytywania i sekwencjonowania skryptów zewnętrznych:

  1. Użyj atrybutu async lub defer z tagami <script>, które informują przeglądarkę, że ma wczytywać niekrytyczne skrypty zewnętrzne bez blokowania parsera dokumentów. Skrypty, które nie są wymagane do początkowego wczytania strony lub pierwszej interakcji użytkownika, mogą zostać uznane za niekrytyczne.

       <script src="https://example.com/script1.js" defer></script>
       <script src="https://example.com/script2.js" async></script>
    
  2. Nawiązuj wcześniejsze połączenia z wymaganymi źródłami za pomocą funkcji preconnect i dns-prefetch. Dzięki temu krytyczne skrypty mogą zacząć się wcześniej pobierać.

       <head>
           <link rel="preconnect" href="http://PreconnThis.com">
           <link rel="dns-prefetch" href="http://PrefetchThis.com">
       </head>
    
  3. Leniwe ładowanie zasobów innych firm i umieszczanie ich po zakończeniu wczytywania treści strony głównej lub po przewinięciu strony w dół do części strony, na której się znajdują.

Komponent Next.js Script

Komponent skryptu Next.js implementuje powyższe metody sekwencjonowania skryptów i zapewnia programistom szablon, który pozwala zdefiniować strategię wczytywania. Po określeniu odpowiedniej strategii będzie ona wczytywana optymalnie bez blokowania innych zasobów o kluczowym znaczeniu.

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 strategii może mieć 3 wartości.

  1. beforeInteractive: tej opcji można używać w przypadku krytycznych skryptów, które powinny zostać wykonane, zanim strona stanie się interaktywna. Next.js zapewnia, że skrypty te są wstrzykiwane do początkowego kodu HTML na serwerze i wykonywane przed innymi skryptami JavaScript, które zostały dodane samodzielnie. Dobrymi aplikacjami dla tej strategii są funkcje zarządzania zgodą użytkowników, skrypty wykrywania botów i biblioteki pomocnicze wymagane do renderowania krytycznych treści.

  2. afterInteractive: to stosowana strategia domyślna i odpowiada wczytaniu skryptu z atrybutem odroczenia. Powinien być używany w przypadku skryptów, które przeglądarka może uruchamiać po interakcji ze stroną – na przykład 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 za pomocą komponentu Script są odraczane przez Next.js, co zapewnia silną wartość domyślną.

  3. lazyOnload: tej opcji można używać do leniwego ładowania skryptów o niskim priorytecie, gdy przeglądarka jest bezczynna. 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.

Deweloperzy mogą określić strategię, by poinformować Next.js, jak ich aplikacja używa skryptu. Dzięki temu platforma może stosować optymalizacje i sprawdzone metody wczytywania skryptu, a jednocześnie zapewnia najlepszą sekwencję wczytywania.

Korzystając z komponentu Skrypt, programiści mogą umieścić skrypt innej firmy w dowolnym miejscu w aplikacji (aby ładować strony z opóźnieniem), a na poziomie dokumentu – w przypadku skryptów o znaczeniu krytycznym. Oznacza to, że za pomocą skryptu komponent Skrypt może być umieszczony razem z nim. Po nawodnieniu skrypt zostanie wstrzykiwany w nagłówku początkowo renderowanego dokumentu lub na dole treści, 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. Strony firm zewnętrznych najczęściej używane do obsługi Menedżera tagów Google i umieszczenia w mediach społecznościowych zostały umieszczone na stronach tych aplikacji bezpośrednio, a potem za pomocą komponentu Script. Następnie porównaliśmy skuteczność tych stron w narzędziu WebPageTest.

Skrypty innych firm w aplikacji handlowej Next.js

Skrypty innych firm zostały dodane do szablonu aplikacji handlowej na potrzeby wersji demonstracyjnej w sposób podany poniżej.

Przed Po
Menedżer tagów Google z aplikacją asynchroniczną Komponent skryptu ze strategią = afterInteractive w przypadku obu skryptów
Przycisk Obserwuj na Twitterze bez synchronizacji i opóźniania
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 niemal 1 s wcześniej, gdy komponent skryptu jest włączony i ma odpowiednią strategię wczytywania.

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

Skrypty innych firm na blogu Next.js

Do wersji demonstracyjnej blogu zostały dodane skrypty innych firm w sposób podany poniżej.

Przed Po
Menedżer tagów Google z aplikacją asynchroniczną Komponent skryptu ze strategią = leniwe ładowanie dla każdego z 4 skryptów
Przycisk Obserwuj na Twitterze z asynchronizacją
Przycisk subskrypcji w YouTube bez synchronizacji i odroczenia
Przycisk Obserwuj LinkedIn bez synchronizacji i opóźniania
Konfiguracja skryptu i komponentu skryptu w wersji demonstracyjnej 2 z 4 skryptami.
Film pokazujący postęp wczytywania strony indeksu z komponentem skryptu i bez niego. FCP po zastosowaniu komponentu skryptu poprawia wynik o 0,5 sekundy.

Jak widać na tym filmie, pierwsze wyrenderowanie treści (FCP) następuje w czasie 0,9 sekundy po wyświetleniu strony bez komponentu Script i w 0,4 sekundy z komponentem Script.

Co dalej z komponentem Skrypt

Opcje strategii dla afterInteractive i lazyOnload zapewniają znaczącą kontrolę nad skryptami blokującymi renderowanie, ale pracujemy też nad innymi opcjami, które zwiększyłyby użyteczność komponentu Skrypt.

Korzystanie z instancji roboczych

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 wchodzą w interakcję z interfejsem, nadają się do wykonania w wątku w tle. Aby wyodrębnić takie skrypty z środowiska internetowego, można użyć lekkiej biblioteki zewnętrznej (PartyTown).

Przy obecnej implementacji komponentu skryptu Next.js zalecamy odroczenie tych skryptów na wątek główny przez ustawienie strategii na afterInteractive lub lazyOnload. W przyszłości proponujemy wprowadzenie nowej opcji strategii – 'worker', która pozwoli Next.js na używanie PartyTown lub niestandardowego rozwiązania do uruchamiania skryptów w środowiskach wykonawczych. Zachęcamy deweloperów do przekazywania komentarzy na temat tego dokumentu RFC.

Minimalizowanie CLS

Elementy umieszczone przez inne firmy (np. reklamy, filmy lub kanały społecznościowe) mogą powodować przesunięcia układu, gdy wczytywanie jest leniwe. 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 kreacja.

Komponent Skrypt można wykorzystać do wczytywania elementów umieszczanych na stronie, które mogą powodować przesunięcia układu. Rozważamy jej rozszerzenie, aby udostępnić opcje konfiguracji, które pomogą ograniczyć CLS. Można go udostępnić w komponencie Script lub jako komponent towarzyszący.

Komponenty opakowań

Składnia i strategia ładowania, która umożliwia uwzględnianie popularnych skryptów zewnętrznych, takich jak Google Analytics czy Menedżer tagów Google (GTM), jest zwykle poprawiona. Mogą one być dalej zawarte w poszczególnych komponentach kodu w przypadku każdego typu skryptu. Deweloperzy będą mieli dostęp tylko do minimalnego zestawu atrybutów związanych z aplikacją (np. identyfikatora śledzenia). Komponenty opakowań pomogą programistom:

  1. Ułatwia to dodawanie popularnych tagów skryptu.
  2. Zadbanie o to, aby system wykorzystywał optymalną strategię w mechanizmie.

Podsumowanie

Skrypty zewnętrzne są zwykle tworzone w taki sposób, aby zawierały określone funkcje na stronie korzystającej z usługi. Aby ograniczyć wpływ mniej istotnych skryptów, zalecamy ich odroczenie – jest to domyślnie wykonywane przez komponent Next.js Script. Deweloperzy mogą zagwarantować, że uwzględnione skrypty nie będą opóźniać krytycznej funkcjonalności, chyba że jednoznacznie zastosują strategię beforeInteractive. Podobnie jak w przypadku komponentu Next.js Script, programiści platformy mogą również rozważyć utworzenie tych funkcji na innych platformach. Wspólnie z zespołem Nuxt.js aktywnie rozważamy wprowadzenie podobnego elementu. Dzięki opiniom użytkowników chcemy dalej ulepszać komponent skryptu, aby obejmował dodatkowe przypadki użycia.

Poświadczenia

Dziękujemy Karze Erickson, Janicklas Ralph, Katie Hempenius, Philip Walton, Jeremy Wagner i Addy Osmani za opinie na temat tego posta.