Podział kodu z dynamicznymi importami w Next.js

Jak przyspieszyć działanie aplikacji Next.js za pomocą podziału kodu i strategii inteligentnego wczytywania.

Czego się nauczysz?

W tym poście omówiliśmy różne typy kodu dzieląc dane i sposób korzystania z nich, aby przyspieszyć działanie aplikacji Next.js.

Dzielenie kodu na podstawie trasy i komponentu

Domyślnie Next.js dzieli kod JavaScript na osobne fragmenty dla każdej trasy. Gdy użytkownicy wczytują aplikację, Next.js wysyła tylko kod niezbędny dla parametru trasy początkowej. Podczas poruszania się po aplikacji użytkownicy pobierają fragmenty powiązane z innymi trasami. Dzielenie kodu na podstawie trasy minimalizuje liczbę skryptów do przeanalizowania i skompilowania jednocześnie, co daje szybszego wczytywania stron.

Chociaż dzielenie kodu na podstawie trasy jest dobrym ustawieniem domyślnym, możesz jeszcze bardziej zoptymalizować z podziałem kodu na poziomie komponentu. W przypadku dużych aplikacji, warto podzielić je na mniejsze fragmenty. Dzięki temu wszystkie duże komponenty, które nie są kluczowe lub są renderowane tylko na określonych interakcje użytkownika (np. kliknięcie przycisku) mogą być leniwe.

Next.js obsługuje dynamiczne import(), który pozwala importować moduły JavaScript (w tym komponenty React). dynamicznie i wczytywać każdy import jako oddzielny fragment. Dzięki temu podziału kodu na poziomie komponentu i umożliwia kontrolowanie wczytywania zasobów. że użytkownicy pobierają potrzebny kod tylko w tej części witryny, co oglądają. W Next.js komponenty te są renderowane po stronie serwera (SSR) domyślnie.

Importy dynamiczne w praktyce

Znajdziesz w nim kilka wersji przykładowej aplikacji składającej się z prostego z jednym przyciskiem. Po kliknięciu przycisku zobaczysz słodki szczeniaczek. Jako możesz sprawdzić, jak importowanie dynamiczne różni się od statycznego importy i jak współpracować z nimi.

W pierwszej wersji aplikacji szczeniaczek mieszka w: components/Puppy.js. Do wyświetla szczeniaka na stronie, aplikacja zaimportuje komponent Puppy w index.js za pomocą statycznej instrukcji importu:

import Puppy from "../components/Puppy";

Aby zobaczyć, jak Next.js tworzy pakiet aplikacji, sprawdź ślad sieciowy w Narzędziach deweloperskich:

  1. Aby wyświetlić podgląd strony, kliknij Wyświetl aplikację. Następnie naciśnij Pełny ekran pełny ekran

  2. Naciśnij „Control + Shift + J” (lub „Command + Option + J” na Macu), aby otworzyć Narzędzia deweloperskie.

  3. Kliknij kartę Sieć.

  4. Zaznacz pole wyboru Wyłącz pamięć podręczną.

  5. Odśwież stronę.

Po załadowaniu strony cały niezbędny kod, w tym Puppy.js komponent jest w pakiecie w index.js:

Karta Network (Sieć) w Narzędziach deweloperskich z widoczną 6 plikami JavaScript: index.js, app.js, webpack.js, main.js, 0.js i dll (biblioteką linków dynamicznych).

Gdy naciśniesz przycisk Kliknij mnie, zostanie wysłana tylko prośba o plik JPEG dla szczeniaka dodano do karty Network (Sieć):

Karta Network (Sieć) w Narzędziach deweloperskich po kliknięciu przycisku, zawierająca te same 6 plików JavaScript i 1 obraz.

Wadą tego rozwiązania jest to, że nawet jeśli użytkownicy nie klikają przycisku, na jego widok, muszą załadować komponent Puppy, ponieważ jest on index.js W tym przykładzie to nie jest szkoda, ale w praktyce. dla aplikacji często znacznie łatwiej jest ładować duże komponenty tylko wtedy, niezbędną.

Przyjrzyjmy się teraz drugiej wersji aplikacji, w której importowany statyczny zastąpiono importem dynamicznym. Next.js zawiera kod next/dynamic, dzięki czemu jest możliwe użycie dynamicznych importów dla dowolnych komponentów w Next:

import Puppy from "../components/Puppy";
import dynamic from "next/dynamic";

// ...

const Puppy = dynamic(import("../components/Puppy"));

Wykonaj czynności z pierwszego przykładu, aby zbadać śledzenie sieci.

Przy pierwszym wczytaniu aplikacji pobierany jest tylko index.js. Tym razem O 0,5 KB (zmniejszono go z 37,9 KB do 37,4 KB), ponieważ nie zawiera kodu komponentu Puppy:

Sieć narzędzi deweloperskich wyświetla te same 6 plików JavaScript, ale plik index.js jest mniejszy o 0,5 KB.

Komponent Puppy jest teraz w osobnym fragmencie 1.js, który jest ładowany tylko po naciśnięciu przycisku:

Karta Network (Sieć) w Narzędziach deweloperskich po kliknięciu przycisku, na której widać dodatkowy plik 1.js i obraz dodany u dołu listy plików.

W prawdziwych zastosowaniach komponenty są często bardzo często większe i leniwe ładowanie. umożliwia skrócenie początkowego ładunku JavaScript o setki kilobajtów.

Importy dynamiczne z niestandardowym wskaźnikiem wczytywania

W przypadku leniwego ładowania zasobów warto podać wskaźnik ładowania na wypadek opóźnień. W Next.js możesz to zrobić, dodając tag dodatkowy argument do funkcji dynamic():

const Puppy = dynamic(() => import("../components/Puppy"), {
  loading: () => <p>Loading...</p>
});

Aby zobaczyć działanie wskaźnika wczytywania, symuluj wolne połączenie sieciowe w Narzędzia deweloperskie:

  1. Aby wyświetlić podgląd strony, kliknij Wyświetl aplikację. Następnie naciśnij Pełny ekran pełny ekran

  2. Naciśnij „Control + Shift + J” (lub „Command + Option + J” na Macu), aby otworzyć Narzędzia deweloperskie.

  3. Kliknij kartę Sieć.

  4. Zaznacz pole wyboru Wyłącz pamięć podręczną.

  5. Na liście Throttling (Throttling) wybierz Fast 3G (Szybkie 3G).

  6. Kliknij przycisk Kliknij mnie.

Teraz, gdy klikniesz przycisk, załadowanie komponentu i aplikacji może trochę potrwać. wyświetla się komunikat „Wczytuję...” .

Ciemny ekran z tekstem

Importy dynamiczne bez SSR

Jeśli chcesz renderować komponent tylko po stronie klienta (np. czat widżet), możesz to zrobić, ustawiając opcję ssr na false:

const Puppy = dynamic(() => import("../components/Puppy"), {
  ssr: false,
});

Podsumowanie

Dzięki obsłudze importu dynamicznego Next.js udostępnia kod na poziomie komponentu podział, który może zminimalizować ładunki JavaScript i ulepszyć aplikację czas wczytywania strony. Wszystkie komponenty są domyślnie renderowane po stronie serwera. Możesz wyłącz tę opcję w razie potrzeby.