Let's talk
  • [ Tech ]
  • [ JavaScript ]

React.js: zmniejsz rozmiar paczki JavaScript dzięki dzieleniu kodu

Kaliop

Opublikowano 28 maja 2019

Użytkownicy coraz bardziej dbają o wydajność. Budujemy rozbudowane aplikacje, a wraz z ich rozwojem rośnie również rozmiar paczki JavaScript.

Podczas tworzenia aplikacji jednostronicowych, tworzymy mnóstwo komponentów. Każdy z tych komponentów ma własne zależności, biblioteki pomocnicze i tak dalej. Kontynuujemy rozwijanie funkcji i w pewnym momencie uświadamiamy sobie, że nasza strona internetowa działa wolno. 🙀. Podczas badania problemu uświadamiamy sobie, że nasza paczka JavaScript jest zbyt duża. Można to stwierdzić na kilka sposobów:

  • Zbyt długi czas ładowania przy wolnym połączeniu sieciowym. Możemy to łatwo przetestować, korzystając z narzędzi deweloperskich chrome dev tools i zakładki sieć.
  • Sam Webpack informuje nas, że paczka jest zbyt duża:
WARNING in entrypoint size limit: The following entrypoint(s) combined asset size exceeds the recommended limit (244 KiB). This can impact web performance.
 
  • Narzędzia do analizy stron internetowych takie jak lighthouse informują nas o konieczności zmniejszenia rozmiaru paczki:
Consider reducing the time spent parsing, compiling and executing JS. You may find delivering smaller JS payloads helps with this.

Jeśli znalazłeś się w jednej z tych sytuacji, kolejnym pytaniem, jakie możesz sobie zadać, jest: „Dobrze, mam problem z wydajnością przez rozmiar paczki. Ale jak mam sobie z tym poradzić?”.

Pomiar. Analiza. Działanie.

Użyjemy prostej aplikacji React z dwiema ścieżkami:  Home and Heavy , with React router. Komponent Heavy będzie wykorzystywał biblioteki lodash i moment tylko po to, aby uczynić go tak dużym, jak to tylko możliwe (pod kątem rozmiaru paczki).

Pomiar

Zawsze należy zmierzyć wpływ problemu przed przystąpieniem do jakichkolwiek przedwczesnych optymalizacji. Możemy użyć narzędzia source-map-explorer aby zbadać nasze paczki JavaScript, a następnie podjąć odpowiednie kroki.

Uwaga: Używam source-map-explorer because ponieważ jest to narzędzie zalecane dla Reacta i nie wymaga "wysuwania" konfiguracji. Dla tych, którym trudno go czytać - jak mi - (like myself), możesz użyć webpack-bundle-analyzer, ale jego użycie może wymusić na Was modyfikację wewnętrznej konfiguracji projektu.

npm install --save source-map-explorer
 

Musimy dodać nowy skrypt w pliku package.json.

"scripts": {
  "analyze": "source-map-explorer 'build/static/js/*.js'",
  ...
}
 

Możemy wtedy uruchomić:

npm run build
npm run analyze
 

Bundle

Analiza

Patrząc na dane wyjściowe analizatora, widzimy, że lodash i moment zajmują sporo miejsca w naszej paczce. Kiedy ładujemy stronę główną, przesyłamy je niepotrzebnie – komponent strony głównej nie wymaga tych bibliotek. 

W tym przypadku, jeśli wydzielimy komponent Heavy z głównej paczki, usuniemy z niej biblioteki lodash i moment co zmniejszy rozmiar paczki o ponad połowę.

To są właśnie te działania, które potrafią drastycznie odchudzić Twoje paczki JavaScript. Pamiętaj jednak, że optymalizacja powinna wymagać jak najmniejszego wysiłku i przynosić znaczące efekty. Nie trać czasu na optymalizację fragmentów ważących po 3 KiB – celuj w „grube ryby”.

Podejmij działanie

Naszym celem jest oddzielenie komponentu Heavy (wraz z jego zależnościami) od reszty paczki. Wykorzystamy do tego funkcję code splitting. Najpierw zobaczmy, jak ta funkcja działa poza kontekstem Reacta.

Note: W przypadku korzystania z create-react-app, webpack jest już skonfigurowany tak, aby wspierać dzielenie kodu za pomocą dynamicznego importu.

Webpack obsługuje składnię dynamicznego importu, wykorzystując wewnętrznie mechanizm obietnic. Oto różnica między importem statycznym a dynamicznym:

  • Import statyczny zwraca to, co zostało wyeksportowane przez moduł jako eksport domyślny default export.
  • Import dynamiczny zwraca obietnicę, która rozwiązuje się do obiektu z właściwością default. Wartością tej właściwości jest właśnie to, co moduł eksportuje jako domyślny eksport. Gdy Webpack napotka dynamiczny import, pakuje wszystko, co nie jest zaimportowane statycznie w głównej paczce, do oddzielnego fragmentu

Powrót do kontekstu naszej aplikacji

Najpierw sprawdźmy, jak wygląda ruch sieciowy przed wydzieleniem komponentu:

Traffic network

Widzimy, że fragment 2.xxxx waży 263kb (as we saw in the analyzer) i jego ładowanie zajmuje 7.36s przy wolnym połączeniu 3G. Teraz wydzielmy „ciężki” komponent i zobaczmy, co się stanie.

Możemy do tego wykorzystać lazy oraz Suspense. Funkcja Lazy pozwala wyrenderować dynamicznie zaimportowany komponent tak, jakby był zwykłym komponentem, natomiast Suspense pozwala zdefiniować treść zastępczą, która będzie wyświetlana podczas ładowania tego komponentu.

Następnie użyjemy tego komponentu w naszym routerze.

Teraz przebudujmy i ponownie przeanalizujmy naszą paczkę.

npm run build
npm run analyze
 

Bundle bis

Ten widok jest nieco bardziej szczegółowy w odniesieniu do głównej paczki, ponieważ przybliżenie zadziałało inaczej, ale nie jest to istotne

Najważniejszą rzeczą, na którą należy zwrócić uwagę, jest fakt, że mamy teraz dwa różne fragmenty (2.xxxx and 3.xxxx). Fragment 3.xxxx został utworzony, ponieważ użyliśmy dynamicznego importu, o czym wspominaliśmy w poprzedniej sekcji. Ten fragment 3.xxxx zawiera komponent Heavy i nie zostanie załadowany, jeśli nie będzie potrzebny. Dzięki temu podziałowi nasz fragment 2.xxxx waży teraz tylko 148kb, co jest wynikiem znacznie lepszym niż poprzednie 263kb.

Oto co się dzieje, gdy ładujemy stronę główną:

Loading traffic

Strona ładuje się o ponad 2 sekundy szybciej, ponieważ paczka jest lżejsza. Teraz, jeśli przejdziemy do trasy heavy, fragment ten zostanie automatycznie pobrany:

Loading traffic 2

Podsumowanie

  • Dzielenie kodu jest użyteczne, ponieważ pozwala zmniejszyć rozmiar paczki poprzez wydzielenie jej dużych części i ładowanie ich tylko wtedy, gdy są naprawdę potrzebne.
  • Funkcje lazy i Suspense pomagają w dzieleniu komponentów, ale opierają się one na dynamicznym imporcie, który jest funkcjonalnością Webpacka. Możesz korzystać z tej techniki wszędzie tam, gdzie używasz Webpacka – nawet w aplikacjach, które nie wykorzystują Reacta.
  • Zawsze wykonuj analizę przed próbą poprawy wydajności i skupiaj się na najprostszych zadaniach, które mają największy wpływ na szybkość działania aplikacji.

Podobne treści