Strona główna / Artykuły

Dziewięć sposobów na przyspieszenie budowania aplikacji w Next.js oraz pakietów produkcyjnych

Szybszy Next.js: używaj Turbopack, pomijaj pliki barrel, dziel kontrolę typów, utrzymuj komponenty klienckie w małych rozmiarach, ładuj w tle ciężkie biblioteki i redukuj pliki produkcyjne.

Wydawca: REACTAPP.TOP4 min czytania991 słów

Źródła: Speeding Up Your Next.js web app: Best Practices

Next.js oferuje routowanie, renderowanie na serwerze, ścieżki API oraz optymalizację obrazów w ramach Reactu, przy niemal żadnej konieczności konfiguracji, dlatego jest tak popularny, w tym w projektach generowanych przez AI. Jednak w miarę rozwoju projektu pojawiają się te same problemy: długie czasy kompilacji, opóźnienia przy aktualizacjach modułów w czasie rzeczywistym, a nawet niewielkie zmiany w interfejsie wydają się powolne. Dziesięciosekundowa kompilacja zamiast jednosekundowej skutkuje godzinami straconego czasu co miesiąc, a czekanie na to, aż asystent AI zastosuje zmianę podczas ponownej kompilacji strony, jest dodatkowo irytujące.

Zlecanie asystentowi AI audytu projektu

Z edytorem kodu opartym na sztucznej inteligencji nie musisz ręcznie stosować każdej porady. Poproś asystenta o porównanie bazy kodu z poniższymi praktykami. Korzystne żądanie polega na tym, aby sprawdził każdą z tych praktyk, wyjaśnił, dlaczego jest ważna, oszacował wpływ na szybkość rozwoju, czas budowania lub działania aplikacji, pokazał dokładną zmianę w kodzie oraz potwierdził wszystko na podstawie aktualnej oficjalnej dokumentacji Next.js i React. Powinien zaznaczyć porady, które stały się przestarzałe lub nie są już stosowane, i zamiast tego wskazać nowsze rozwiązania; nie powinien też wprowadzać optymalizacji spekulatywnych, których nie wspierają dokumentacje lub które nie pasują do projektu.

Przeczytaj dokładnie to, co wygenerował, przed fuzją. Frameworki rozwijają się szybko, więc to, co było przydatne rok temu, może teraz być bez znaczenia. Traktuj asystenta jak doświadczonego recenzenta, a nie orakula. Ostateczną decyzję podejmują oficjalna dokumentacja oraz potrzeby konkretnego aplikacji.

Dziewięć nawyków, które się opłacają

1. Uruchomianie rozwoju w Turbopack

W najnowszych wersjach Next.js Turbopack jest stabilny do lokalnego rozwoju. Jego włączenie odbywa się za pomocą flagi:

next dev --turbopack

Podczas gdy starszy serwer deweloperski oparty na Webpack przetwarza większość elementów projektu, Turbopack przebudowuje tylko te moduły, które uległy zmianie. W projektach średniej i dużej wielkości czas uruchamiania oraz funkcja HMR poprawiają się natychmiast. Budowy do produkcji nadal wykorzystują standardową ścieżkę przetwarzania, więc używanie jej w fazie rozwoju niesie małe ryzyko.

2. Przedkompiluj ciężkie zależności

Ponowne przetwarzanie rzadko zmienianych pakietów od dostawców zewnętrznych przy każdym uruchamianiu jest główną przyczyną wolnego startu. Material UI, Monaco Editor, Three.js, Chart.js oraz duże zbiory ikon wymagają dużo zasobów przy każdym uruchomieniu serwera deweloperskiego. Next.js może optymalizować importy dla pakietów o określonych nazwach:

experimental: {
    optimizePackageImports: [
        "@mui/material",
        "@mui/icons-material",
        "lodash"
    ]
}

Nie bierz też całego pakietu, jeśli wystarczy jeden narzędzie. Mniejszy graf zależności pozwala szybciej skompilować kod.

3. Pomiń pliki barrel

Jedyny plik index.ts, który ponownie eksportuje każdy komponent, sprawia, że importy wyglądają uporządkowanie, ale zmusza kompilator do przeglądania znacznie większej liczby plików niż to konieczne. Ten import przechodzi przez pliki barrel:

import { Button } from "@/components";

Lepiej jest importować z własnej ścieżki komponentu:

import Button from "@/components/Button";

To niewielka modyfikacja, która zmniejsza czas rozwiązywania modułów, szczególnie w większych aplikacjach.

4. Unikaj sprawdzania typów na serwerze deweloperskim

Wielu programistów blokuje działanie swojego serwera deweloperskiego pod kątem sprawdzania typów w TypeScript, które już są wykonywane przez edytor. Uruchom serwer oraz narzędzie do monitorowania TypeScript jako dwa oddzielne procesy:

next dev --turbopack
tsc --watch

Strona odświeża się natychmiast, a błędy wpisywania nadal są widoczne w czasie rzeczywistym.

5. Zachowuj małe komponenty klienckie

W App Routerze każdy plik oznaczony jako "use client" trafia do pliku bundle przeglądarki. Zastanów się, czy dany komponent rzeczywiście wymaga renderowania po stronie klienckiej. Statyczne layouty, nawigacja, strony z treścią oraz pobieranie danych często mogą pozostać komponentami serwerowymi, natomiast komponenty klienckie należy używać tylko w tych częściach, które naprawdę wymagają interaktywności. Dzięki temu do przeglądarki trafia mniej JavaScript-u, a także mniej modułów klienckich do odbudowy podczas rozwoju.

6. Ładuj ciężkie biblioteki na żądanie

Zależności, których nie potrzeba od razu po załadowaniu strony, mogą poczekać. Edytory, przeglądarki PDF, mapy, pakietów do tworzenia wykresów i wizualizacji to doskonałe przykłady elementów, które można ładować opóźnionie, tylko wtedy, gdy ktoś do nich się udaje:

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

Zarówno początkowy plik, jak i wersje po przekompilowaniu w trybie deweloperskim pozostają znacznie mniejsze.

7. Dzielenie dużych komponentów

Ogromne komponenty strony spowalniają pracę wszystkich. Strona składająca się z setek linijek JSX lepiej jest podzielona na mniejsze, wielokrotnie używalne elementy, które kompilator może łatwiej zapamiętać w pamięci podręcznej, które są prostsze do testowania i które szybciej się przekompilują, gdy coś się zmieni. Jeśli plik staje się trudny do nawigacji, to zazwyczaj sygnał, by go podzielić.

8. Wyłączanie niepotrzebnych usług w fazie rozwoju

Analizy, platformy logowania, odtwarzanie sesji, SDK do monitoringu oraz skrypty marketingowe są ważne w środowisku produkcyjnym i rzadko pomagają podczas tworzenia nowych funkcji. Uruchamiaj je tylko wtedy, gdy aplikacja działa w środowisku produkcyjnym:

if (process.env.NODE_ENV === "production") {
    initializeAnalytics();
    initializePWA();
}

Mniej inicjalizacji oznacza czystsze uruchamianie aplikacji lokalnie oraz brak połączeń z siecią podczas rozwoju.

9. Optymalizuj również wersję produkcyjną

Szybkość rozwoju to tylko połowa obrazu. Używaj komponentu Image z Next.js zamiast surowych tagów obrazków, przechowuj dane w pamięci cache tam, gdzie to możliwe, kompresuj zasoby i polegaj na Server Components, aby zmniejszyć ilość wysyłanego JavaScriptu. Od czasu do czasu sprawdzaj plik bundle za pomocą narzędzia do analizy bundle, aby wcześnie wykryć zaskakująco duże zależności. Wielkie ulepszenia wprowadzane stopniowo zwykle przewyższają jedną dużą optymalizację na końcu.

Gdzie zacząć

Celem jest ustalenie, gdzie faktycznie traci się czas – czy to podczas rozwoju, przy budowaniu aplikacji, czy w trakcie jej działania. Zacznij od podstaw: uporządkowanego grafu zależności, przemyślanego dzielenia kodu na części, minimalnej ilości JavaScriptu po stronie klienta oraz narzędzi już dostępnych w Next.js. Mierz efekty zmian, iteruj i ponownie przeanalizuj architekturę w miarę rozwoju aplikacji.

Next.js cały czas się rozwija, a zalecenia zmieniają się przy każdym wydaniu. Niezależnie od tego, czy zmiany pochodzą od ciebie, czy od asystenta AI, sprawdź je najpierw w najnowszych oficjalnych dokumentach Next.js i React. Najlepsza optymalizacja to ta, która jest odpowiednia dla wersji, na której obecnie pracujesz, a nie ta, która była popularna w zeszłym roku.