Jak przyspieszyć działanie aplikacji Next.js dzięki podziałowi kodu i strategiom inteligentnego ładowania.
Czego się nauczysz?
W tym poście opisujemy różne typy dzielenia kodu oraz wyjaśniamy, jak używać dynamicznych importów, aby przyspieszyć działanie aplikacji Next.js.
Podział kodu na podstawie ścieżki i komponentów
Domyślnie Next.js dzieli kod JavaScript na osobne fragmenty dla każdej ścieżki. Gdy użytkownicy wczytują Twoją aplikację, Next.js wysyła tylko kod potrzebny do początkowej trasy. Gdy użytkownicy poruszają się po aplikacji, pobierają fragmenty powiązane z innymi ścieżkami. Dzielenie kodu na podstawie trasy minimalizuje ilość kodu, który musi zostać przeanalizowany i skompilowany jednocześnie, co powoduje szybsze wczytywanie stron.
Dzielenie kodu na podstawie trasy jest dobrym domyślnym ustawieniem, ale możesz dodatkowo zoptymalizować proces wczytywania, dzieląc kod na poziomie komponentu. Jeśli w aplikacji masz duże komponenty, warto podzielić je na osobne fragmenty. Dzięki temu duże komponenty, które nie są kluczowe lub renderują się tylko w przypadku określonych interakcji użytkownika (np. kliknięcia przycisku), mogą być ładowane z opóźnieniem.
Next.js obsługuje dynamiczne import()
, co pozwala na importowanie modułów JavaScript (w tym komponentów React) dynamicznie i wczytywanie każdego importu jako osobnego fragmentu. Umożliwia to dzielenie kodu na poziomie komponentu i kontrolowanie wczytywania zasobów, tak aby użytkownicy pobierali tylko kod potrzebny do wyświetlania danej części witryny. W Next.js te komponenty są domyślnie renderowane po stronie serwera (SSR).
Importowanie dynamiczne w akcji
Ten post zawiera kilka wersji przykładowej aplikacji, która składa się z jednej prostej strony z jednym przyciskiem. Gdy klikniesz przycisk, zobaczysz uroczego szczeniaczka. W każdej wersji aplikacji zobaczysz, czym importy dynamiczne różnią się od importów statycznych oraz jak z nimi pracować.
W pierwszej wersji aplikacji szczeniak mieszka w components/Puppy.js
. Aby wyświetlić szczeniaka na stronie, aplikacja importuje komponent Puppy
w index.js
za pomocą statycznego polecenia importowania:
import Puppy from "../components/Puppy";
Aby sprawdzić, jak Next.js łączy aplikację, sprawdź ślad sieci w Narzędziach deweloperskich:
Aby wyświetlić podgląd strony, kliknij Wyświetl aplikację. Następnie kliknij Pełny ekran .
Aby otworzyć Narzędzia dla programistów, naciśnij `Control+Shift+J` (lub `Command+Option+J` na Macu).
Kliknij kartę Sieć.
Zaznacz pole wyboru Disable cache (Wyłącz pamięć podręczną).
Odśwież stronę.
Gdy wczytasz stronę, cały niezbędny kod, w tym komponent Puppy.js
, jest zawarty w elementach index.js
:
Gdy klikniesz przycisk Kliknij mnie, do karty Sieć zostanie dodana tylko prośba o plik JPEG z szczeniaczkiem:
Minusem tego podejścia jest to, że nawet jeśli użytkownicy nie klikną przycisku, aby zobaczyć szczeniaka, muszą wczytać komponent Puppy
, ponieważ jest on zawarty w komponencie index.js
. W tym małym przykładzie nie ma to większego znaczenia, ale w rzeczywistych zastosowaniach często wczytywanie dużych komponentów tylko wtedy, gdy jest to konieczne, powoduje znaczną poprawę wydajności.
Teraz sprawdź drugą wersję aplikacji, w której import statyczny został zastąpiony importem dynamicznym. Next.js zawiera next/dynamic
, dzięki czemu możesz używać importów dynamicznych w przypadku dowolnych komponentów w Next:
import Puppy from "../components/Puppy";
import dynamic from "next/dynamic";
// ...
const Puppy = dynamic(import("../components/Puppy"));
Aby sprawdzić ślad sieci, wykonaj czynności opisane w pierwszym przykładzie.
Podczas pierwszego wczytywania aplikacji pobierany jest tylko index.js
. Tym razem plik jest mniejszy o 0,5 KB (z 37,9 KB do 37,4 KB), ponieważ nie zawiera kodu komponentu Puppy
:
Komponent Puppy
znajduje się teraz w oddzielnym fragmencie 1.js
, który jest wczytywany tylko wtedy, gdy naciśniesz przycisk:
W przypadku rzeczywistych aplikacji komponenty są często znacznie większe, a ich wczytywanie z opóźnieniem może zmniejszyć początkowy ładunek JavaScript o setki kilobajtów.
Importowanie dynamiczne z niestandardowym wskaźnikiem wczytywania
W przypadku wczytywania opóźnionego zasobów warto wyświetlić wskaźnik wczytywania na wypadek opóźnień. W Next.js możesz to zrobić, podając dodatkowy argument funkcji dynamic()
:
const Puppy = dynamic(() => import("../components/Puppy"), {
loading: () => <p>Loading...</p>
});
Aby zobaczyć działanie wskaźnika ładowania, symuluj powolne połączenie z internetem w DevTools:
Aby wyświetlić podgląd strony, kliknij Wyświetl aplikację. Następnie kliknij Pełny ekran .
Aby otworzyć Narzędzia dla programistów, naciśnij `Control+Shift+J` (lub `Command+Option+J` na Macu).
Kliknij kartę Sieć.
Zaznacz pole wyboru Disable cache (Wyłącz pamięć podręczną).
Z listy Ograniczanie wybierz Szybkie 3G.
Naciśnij przycisk Kliknij mnie.
Gdy klikniesz przycisk, komponent będzie się wczytywać, a aplikacja wyświetli komunikat „Ładowanie…”.
Importy dynamiczne bez SSR
Jeśli chcesz renderować komponent tylko po stronie klienta (np. widżet czatu), możesz to zrobić, ustawiając opcję ssr
na false
:
const Puppy = dynamic(() => import("../components/Puppy"), {
ssr: false,
});
Podsumowanie
Dzięki obsłudze importowania dynamicznego Next.js umożliwia dzielenie kodu na poziomie komponentu, co może zminimalizować ładunki JavaScript i przyspieszyć wczytywanie aplikacji. Wszystkie komponenty są domyślnie renderowane po stronie serwera, ale w razie potrzeby możesz wyłączyć tę opcję.