Pakiet Next.js do zarządzania bibliotekami innych firm

W 2021 r. zespół Chrome Aurora wprowadził komponent skryptu, aby poprawić wydajność wczytywania skryptów innych firm w Next.js. Od czasu jego wprowadzenia rozszerzyliśmy jego możliwości, aby ułatwić i przyspieszyć wczytywanie zasobów innych firm.

W tym poście na blogu omawiamy nowe funkcje, które wprowadziliśmy, w tym przede wszystkim bibliotekę @next/third-parties, a także zapowiadamy przyszłe inicjatywy.

Wpływ skryptów innych firm na skuteczność

41% wszystkich żądań zewnętrznych w witrynach Next.js to skrypty. W odróżnieniu od innych typów treści pobieranie i wykonywanie skryptów może zająć sporo czasu, co może blokować renderowanie i opóźniać interakcje z użytkownikiem. Dane z raportu na temat użytkowania Chrome (CrUX) wskazują, że witryny Next.js, które wczytują więcej skryptów innych firm, mają niższe współczynniki interakcji do następnego wyrenderowania (INP)największego wyrenderowania treści (LCP).

Wykres słupkowy pokazujący spadek odsetka aplikacji Next.js osiągających dobre wyniki w przypadku INP i LCP w zależności od liczby wczytanych zasobów stron trzecich
Raport CrUX z grudnia 2023 r. (110 823 witryn)

Korelacja widoczna na tym wykresie nie oznacza związku przyczynowo-skutkowego. Jednak lokalne eksperymenty dostarczają dodatkowych dowodów na to, że skrypty innych firm znacząco wpływają na wydajność strony. Na przykład wykres poniżej porównuje różne metryki laboratoryjne, gdy do Taxonomy, popularnej przykładowej aplikacji Next.js, dodawany jest kontener Menedżera tagów Google, który składa się z 18 losowo wybranych tagów.

Wykres słupkowy przedstawiający różnice w różnych danych testowych podczas wczytywania witryny z Menedżerem tagów Google i bez niego
WebPageTest (mobilna sieć 4G – Wirginia, USA)

Szczegółowe informacje o sposobie pomiaru tych wartości znajdziesz w dokumentacji WebPageTest. Na pierwszy rzut oka widać, że na wszystkie te dane laboratoryjne wpływa kontener Menedżera tagów Google. Na przykład wskaźnik Total Blocking Time (TBT) – przydatna wartość zastępcza, która przybliża wartość INP – wzrósł prawie 20-krotnie.

Komponent skryptu

Gdy wprowadziliśmy komponent <Script> w Next.js, zadbaliśmy o to, aby był on dostępny za pomocą przyjaznego dla użytkownika interfejsu API, który przypomina tradycyjny element <script>. Dzięki temu deweloperzy mogą umieszczać skrypt firmy zewnętrznej w dowolnym komponencie aplikacji, a Next.js zajmie się sekwencyjnością skryptu po załadowaniu kluczowych zasobów.

<!-- By default, script will load after page becomes interactive -->
<Script src="https://example.com/sample.js" />

<!-- Script is injected server-side and fetched before any page hydration occurs -->
<Script strategy=”beforeInteractive” src="https://example.com/sample.js" />

<!-- Script is fetched later during browser idle time -->
<Script strategy=”lazyOnload” src="https://example.com/sample.js" />

Składnik <Script> wykorzystują dziesiątki tysięcy aplikacji Next.js, w tym popularne witryny, takie jak Patreon, Target i Notion. Pomimo skuteczności tej metody niektórzy deweloperzy wyrazili obawy dotyczące następujących kwestii:

  • Gdzie umieścić komponent <Script> w aplikacji Next.js, przestrzegając różnych instrukcji instalacji od różnych zewnętrznych dostawców (doświadczenie dewelopera).
  • Którą strategię ładowania warto zastosować w przypadku różnych skryptów zewnętrznych (wygody użytkowników).

Aby rozwiązać te problemy, uruchomiliśmy @next/third-parties – wyspecjalizowaną bibliotekę zawierającą zestaw zoptymalizowanych komponentów i narzędzi dostosowanych do popularnych bibliotek innych firm.

Ułatwienie deweloperom zarządzania bibliotekami innych firm

Wiele skryptów innych firm jest używanych w znaczącym odsetku witryn Next.js, a najpopularniejszy jest Menedżer tagów Google, który jest używany w 66% witryn. @next/third-parties opiera się na komponencie <Script>, wprowadzając owijarki wyższego poziomu, które mają uprościć korzystanie z tych typowych zastosowań.

import { GoogleAnalytics } from "@next/third-parties/google";

export default function RootLayout({ children }) {
  return (
    <html lang="en">
      <body>{children}</body>
      <GoogleTagManager gtmId="GTM-XYZ" />
    </html>
  );
}

Google Analytics to kolejny często używany skrypt zewnętrzny (52% witryn Next.js), który ma też swój własny komponent.

import { GoogleAnalytics } from "@next/third-parties/google";

export default function RootLayout({ children }) {
  return (
    <html lang="en">
      <body>{children}</body>
      <GoogleAnalytics gaId="G-XYZ" />
    </html>
  );
}

@next/third-parties upraszcza proces wczytywania często używanych skryptów, ale zwiększa też nasze możliwości tworzenia narzędzi dla innych kategorii innych firm, takich jak wstawianie. Na przykład w 8%4% witryn Next.js odpowiednio wstawiane są Mapy Google i YouTube. Wprowadziliśmy też komponenty, które ułatwiają ich wczytywanie.

import { GoogleMapsEmbed } from "@next/third-parties/google";
import { YouTubeEmbed } from "@next/third-parties/google";

export default function Page() {
  return (
    <>
      <GoogleMapsEmbed
        apiKey="XYZ"
        height={200}
        width="100%"
        mode="place"
        q="Brooklyn+Bridge,New+York,NY"
      />
      <YouTubeEmbed videoid="ogfYd705cRs" height={400} params="controls=0" />
    </>
  );
}

Wrażenia użytkowników: szybsze wczytywanie bibliotek innych firm

W idealnym świecie każda powszechnie stosowana biblioteka zewnętrzna byłaby w pełni zoptymalizowana, co uczyniłoby niepotrzebnymi wszelkie abstrakcje poprawiające jej wydajność. Do tego czasu możemy jednak spróbować poprawić wrażenia użytkowników, integrując się z popularnymi frameworkami, takimi jak Next.js. Możemy eksperymentować z różnymi technikami wczytywania, sprawdzać, czy skrypty są uporządkowane we właściwy sposób, i w końcu przekazywać opinie dostawcom zewnętrznym, aby zachęcić ich do wprowadzania zmian na poziomie źródłowym.

Weźmy na przykład wstawianie filmów z YouTube. Niektóre alternatywne implementacje mają znacznie lepszą skuteczność niż wbudowane. Obecnie komponent <YouTubeEmbed> wyeksportowany przez @next/third-parties korzysta z lite-youtube-embed, który, jak pokazano na przykładzie aplikacji „Hello, World” w Next.js, wczytuje się znacznie szybciej.

GIF pokazujący porównanie czasu wczytywania strony między komponentem z wstawką z YouTube a zwykłym iframem YouTube
WebPageTest (mobilna sieć 4G – Wirginia, USA)

Podobnie w przypadku Map Google domyślnym atrybutem umieszczania jest loading="lazy", aby mapy wczytywały się tylko wtedy, gdy znajdują się w określonej odległości od widocznego obszaru. Może się wydawać, że jest to oczywisty atrybut do uwzględnienia, zwłaszcza że dokumentacja Map Google zawiera go w przykładowym fragmencie kodu, ale tylko 45% witryn Next.js, które zawierają mapy Google, używa loading="lazy".

Uruchamianie skryptów zewnętrznych w procesie web worker

Jedną z zaawansowanych technik, którą badamy w @next/third-parties, jest ułatwienie przekazywania skryptów innych firm do web workera. Jest to rozwiązanie popularyzowane przez biblioteki takie jak Partytown. Może ono znacznie ograniczyć wpływ skryptów innych firm na wydajność strony, ponieważ przenosi je całkowicie poza główny wątek.

Ten animowany GIF pokazuje różnice w czasie blokowania przez główny wątek długich zadań i czas blokowania przez niego wątku, gdy stosujesz różne strategie <Script> w kontenerze GTM w witrynie Next.js. Pamiętaj, że przełączanie się między opcjami strategii opóźnia tylko czas wykonywania tych skryptów, a przeniesienie ich do web workera całkowicie eliminuje ich czas w głównym wątku.

GIF pokazujący różnice w czasie blokowania głównego wątku w przypadku różnych strategii skryptu
WebPageTest (mobilna sieć 4G – Wirginia, USA)

W tym konkretnym przykładzie przeniesienie wykonania kontenera Menedżera tagów Google i powiązanych z nim skryptów tagów do web workera zmniejszyło TBT o 92%.

Warto pamiętać, że jeśli nie będziesz ostrożnie zarządzać tą techniką, może ona bez Twojej wiedzy spowodować nieprawidłowe działanie wielu skryptów innych firm, co utrudni debugowanie. W najbliższych miesiącach sprawdzimy, czy komponenty zewnętrzne oferowane przez @next/third-parties działają prawidłowo, gdy są uruchamiane w web workerze. Jeśli tak, postaramy się udostępnić deweloperom łatwy i opcjonalny sposób korzystania z tej techniki.

Dalsze kroki

W trakcie tworzenia tego pakietu okazało się, że trzeba scentralizować rekomendacje dotyczące ładowania z użyciem zewnętrznych bibliotek, aby inne platformy mogły korzystać z tych samych podstawowych technik. Doprowadziło to nas do stworzenia biblioteki Third Party Capital, która używa JSON do opisywania technik ładowania zewnętrznych. Obecnie stanowi ona podstawę dla @next/third-parties.

W następnych krokach będziemy nadal skupiać się na ulepszaniu komponentów udostępnianych w ramach Next.js oraz na zwiększaniu liczby podobnych narzędzi w innych popularnych frameworkach i platformach CMS. Obecnie współpracujemy z osobami zajmującymi się utrzymaniem Nuxt i planujemy w najbliższej przyszłości udostępnić podobne narzędzia innych firm dostosowane do ich ekosystemu.

Jeśli jedna z aplikacji innych firm używanych w aplikacji Next.js jest obsługiwana przez @next/third-parties, zainstaluj ten pakiet i spróbuj go użyć. Chętnie poznamy Twoją opinię na GitHub.