Jak przyspieszyć działanie aplikacji Next.js za pomocą dzielenia kodu i inteligentnych strategii wczytywania.
Data publikacji: 8 listopada 2019 r.
Dowiedz się więcej o różnych typach dzielenia kodu i o tym, jak używać importów dynamicznych, aby przyspieszyć działanie aplikacji Next.js.
Dzielenie kodu na podstawie tras i komponentów
Domyślnie Next.js dzieli JavaScript na osobne fragmenty dla każdej trasy. Gdy użytkownicy wczytują aplikację, Next.js wysyła tylko kod potrzebny do początkowej ścieżki. Gdy użytkownicy poruszają się po aplikacji, pobierają fragmenty powiązane z innymi ścieżkami. Dzielenie kodu na poziomie przekierowań minimalizuje ilość skryptu, który musi być analizowany i kompilowany jednocześnie, co skutkuje szybszym wczytywaniem stron.
Podział kodu na podstawie trasy to dobra opcja domyślna, ale możesz jeszcze bardziej zoptymalizować proces wczytywania, dzieląc kod na poziomie komponentu. Jeśli w aplikacji masz duże komponenty, warto podzielić je na osobne części. Dzięki temu duże komponenty, które nie są kluczowe lub są renderowane tylko w przypadku określonych interakcji użytkownika (np. kliknięcia przycisku), mogą być ładowane z opóźnieniem.
Next.js obsługuje dynamiczneimport(), które umożliwia dynamiczne importowanie modułów JavaScript (w tym komponentów React) i wczytywanie każdego importu jako osobnego fragmentu. Umożliwia to dzielenie kodu na poziomie komponentów i kontrolowanie ładowania zasobów, dzięki czemu użytkownicy pobierają tylko kod potrzebny do wyświetlenia części witryny, którą przeglądają. W Next.js te komponenty są domyślnie renderowane po stronie serwera.
Dynamiczne importy w praktyce
Ten post zawiera kilka wersji przykładowej aplikacji, która składa się z prostej strony z jednym przyciskiem. Gdy klikniesz przycisk, zobaczysz uroczego szczeniaka. Przechodząc przez kolejne wersje aplikacji, zobaczysz, czym importy dynamiczne różnią się od importów statycznych i jak z nich korzystać.
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ą statycznej instrukcji importu:
import Puppy from "../components/Puppy";
Aby zobaczyć, jak Next.js łączy aplikację w pakiet, sprawdź log czasu sieci w Narzędziach deweloperskich:
Aby wyświetlić podgląd strony, kliknij Wyświetl aplikację, a następnie Pełny ekran
.
Aby otworzyć Narzędzia dla programistów, naciśnij Ctrl+Shift+J (lub Command+Option+J na Macu).
Kliknij kartę Sieć.
Zaznacz pole wyboru Wyłącz pamięć podręczną.
Odśwież stronę.
Gdy wczytasz stronę, cały niezbędny kod, w tym komponent Puppy.js, zostanie spakowany w index.js:
Gdy klikniesz przycisk Click me (Kliknij mnie), na karcie Sieć pojawi się tylko żądanie pliku JPEG z szczeniakiem:
Wadą tego podejścia jest to, że nawet jeśli użytkownicy nie klikną przycisku, aby zobaczyć szczeniaka, muszą załadować komponent Puppy, ponieważ jest on uwzględniony w index.js. W tym prostym przykładzie nie ma to większego znaczenia, ale w rzeczywistych aplikacjach wczytywanie dużych komponentów tylko wtedy, gdy jest to konieczne, często stanowi ogromne ulepszenie.
Teraz sprawdź drugą wersję aplikacji, w której import statyczny został zastąpiony importem dynamicznym. Next.js zawiera next/dynamic, co umożliwia używanie dynamicznych importów 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 z pierwszego przykładu.
Przy pierwszym wczytaniu aplikacji pobierany jest tylko index.js. Tym razem jest o 0,5 KB mniejszy (zmniejszył się z 37,9 KB do 37,4 KB), ponieważ nie zawiera kodu komponentu Puppy:
Komponent Puppy znajduje się teraz w osobnym bloku 1.js, który jest wczytywany tylko wtedy, gdy naciśniesz przycisk:
W rzeczywistych aplikacjach komponenty są często znacznie większe, a ich leniwe wczytywanie może zmniejszyć początkowy ładunek JavaScript o setki kilobajtów.
Importy dynamiczne z niestandardowym wskaźnikiem wczytywania
Podczas leniwego wczytywania zasobów warto podać 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ć wskaźnik ładowania w działaniu, zasymuluj wolne połączenie sieciowe w Narzędziach deweloperskich:
Aby wyświetlić podgląd strony, kliknij Wyświetl aplikację, a następnie Pełny ekran
.
Aby otworzyć Narzędzia dla programistów, naciśnij Ctrl+Shift+J (lub Command+Option+J na Macu).
Kliknij kartę Sieć.
Zaznacz pole wyboru Wyłącz pamięć podręczną.
Z listy Ograniczanie przepustowości wybierz Szybkie 3G.
Naciśnij przycisk Kliknij mnie.
Teraz, gdy klikniesz przycisk, wczytanie komponentu zajmie trochę czasu, a w tym czasie aplikacja wyświetli komunikat „Wczytywanie…”.
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 importów dynamicznych Next.js umożliwia dzielenie kodu na poziomie komponentów, co może zminimalizować ładunki JavaScript i skrócić czas wczytywania aplikacji. Wszystkie komponenty są domyślnie renderowane po stronie serwera. W razie potrzeby możesz wyłączyć tę opcję.