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 internetowych wyświetlanych na urządzeniach mobilnych i komputerach to żądania pochodzące od stron trzecich, z których 33% to skrypty. Rozmiar, opóźnienie i wczytywanie skryptów innych firm mogą mieć znaczący wpływ na wydajność witryny. Komponent Next.js Script zawiera wbudowane zalecane metody i domyślne wartości, które pomagają deweloperom wprowadzać skrypty innych firm do ich aplikacji, a jednocześnie rozwiązywać potencjalne problemy ze skutecznością.

Skrypty firm zewnętrznych i ich wpływ na wydajność

Skrypty innych firm umożliwiają deweloperom stron internetowych korzystanie z dotychczasowych rozwiązań do implementowania typowych funkcji i skrócenia czasu programowania. 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 pochodzących z innych firm pobranych przez witryny w różnych kategoriach żądań pochodzących z innych firm. 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 wyświetlania 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 zawiera 2 audyty, które oznaczają skrypty blokujące renderowanie lub blokujące wątek główny.

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

Pamiętaj, aby zwrócić uwagę na kolejność wczytywania zasobów na stronie, tak aby zasoby kluczowe nie były opóźnione, a zasoby niekluczowe nie blokowały zasobów kluczowych.

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. Sposób korzystania z każdego z nich i zalecenia mogą się różnić.
  • Wdrożenie wielu usług zewnętrznych może się różnić w zależności od tego, czy używasz określonej platformy lub biblioteki interfejsu użytkownika.
  • 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 poprawiać aspekty wrażeń użytkowników, takie jak wydajność, dostępność, bezpieczeństwo i gotowość do działania 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 sekwencji wczytywania skryptów innych firm w Next.js. Platformy takie jak Next.js są w wyjątkowej pozycji, aby udostępniać przydatne domyślne wartości i funkcje, 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 sekwencji, aby zapewnić deweloperom większą kontrolę nad wczytywaniem 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 początkowego 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 korzysta z tagu HTML <script> i zawiera opcję ustawienia priorytetu wczytywania skryptów innych firm za pomocą atrybutu strategy.

// 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 zostać wykonane, zanim 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: jest to domyślna strategia stosowana równoważnie z wczytywaniem skryptu z atrybutem opóźnienia. 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. Next.js wstrzykuje te skrypty po stronie klienta i uruchamia je po załadowaniu strony. Dlatego, o ile nie określono inaczej, wszystkie skrypty innych firm zdefiniowane za pomocą komponentu Skrypt są opóźniane przez Next.js, co zapewnia silne ustawienie domyślne.

  3. lazyOnload: ta opcja może służyć do wczytywania z opóźnieniem skryptów o niskim priorytecie, gdy przeglądarka jest nieaktywna. Funkcje, które zapewniają takie skrypty, nie są wymagane od razu, gdy strona staje się interaktywna. Dotyczy to na przykład czatów lub wtyczek mediów społecznościowych.

Deweloper może określić, 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

Użyliśmy szablonów aplikacji handlowej Next.js oraz bloga startowego, aby utworzyć 2 aplikacje demonstracyjne, które pomogły nam zmierzyć wpływ włączenia 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 wydajność tych stron za pomocą narzędzia WebPageTest.

Skrypty innych firm w aplikacji handlu elektronicznego Next.js

W ramach tego demonstracyjnego szablonu aplikacji do handlu dodano 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 składnika skryptu w przypadku demonstracji 1 z 2 skryptami.

Poniższe porównanie pokazuje postępy w przypadku obu wersji komercyjnego 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 miniatur pokazujące poprawę 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 z strategią lazyonload dla każdego z 4 skryptów
Przycisk Obserwuj na Twitterze z asynkronicznym działaniem
Przycisk subskrypcji w YouTube bez asynchroniczności lub opóźnienia
Przycisk Obserwuj na LinkedIn bez asynchroniczności ani opóźnienia
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 Dzięki komponentowi skryptu udało się skrócić czas FCP 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ą znaczną 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

Praca wątek w tle może służyć do uruchamiania niezależnych skryptów w wątkach w tle, co może zwolnić wątek główny do obsługi zadań związanych z przetwarzaniem interfejsu użytkownika i poprawić wydajność. Wątki internetowe najlepiej nadają się do przenoszenia przetwarzania JavaScriptu, a nie pracy związanej z interfejsem użytkownika, z wątku głównego. 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. Do izolowania takich skryptów w procesie web workera możesz użyć lekkiej biblioteki zewnętrznej PartyTown.

W przypadku obecnej implementacji komponentu skryptu Next.js zalecamy opóźnienie tych skryptów w głównym wątku, ustawiając strategię 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 wrażenia użytkowników i dane zbiorcze przesunięcie układu (CLS) na stronie. Wartość CLS można zminimalizować, określając rozmiar kontenera, w którym ma być wyświetlony element.

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 opakowania

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 opakowujące 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 pracujemy nad wprowadzeniem podobnego komponentu. 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.