Frontend

Tree-shaking. Jak wyeliminować nieużywany kod z naszego bundle.js?

Tree-shaking to jedna z funkcji, z której korzystają bundlery takie jak webpack, rollup czy parcel, która pozwala nam zmniejszyć wagę kodu wynikowego naszej aplikacji, a co za tym idzie zwiększyć tzw. performance aplikacji. Dzieje się to poprzez przefiltrowanie zaimportowanych przez nas zależności i wykluczenie z kodu wynikowego kodu tych, które są zbędne.

Module bundlers

Żeby wytłumaczyć jak działa tree-shaking, przypomnijmy sobie w ogóle czym są wspomniane bundlery. W kontekście aplikacji JavaScriptowych są to narzędzia, które biorą plik lub pliki JavaScriptowe wraz z ich zależnościami i łączą je w najczęściej jeden lub kilka plików wynikowych, często stosując przy tym różne optymalizacje, np:

  • konkatenacja – łączenie wielu plików w jeden, żeby ograniczyć ilość requestów,
  • minifikacja – pozbycie się zbędnych znaków z kodu, aby zmniejszyć jego wagę,
  • skracanie nazw zmiennych,
  • code-splitting – dzielenie kodu na kilka plików wynikowych, które są wczytywane na żądanie tylko w tych miejscach aplikacji, w których są potrzebne,
  • tree-shaking – pozbywanie się nieużywanych części kodu – przydatne np. kiedy korzystamy tylko z kilku funkcji biblioteki jQuery, a nie chcemy włączać całej, sporo ważącej biblioteki do naszego kodu wynikowego.

Dlaczego tree-shaking?

Nazwa tree-shaking jest bardzo trafna. Wyobraźcie sobie, że drzewo zależności naszej aplikacji to takie niewielkich rozmiarów prawdziwe drzewko, które jesteśmy w stanie wziąć do ręki – wszystkie zależności, z których korzystamy to zielone, świetnie się mające rozwinięte gałęzie i liście, a te zależności, z których nie korzystamy w aplikacji, a które zaimportowaliśmy w kodzie źródłowym to te wyschnięte, ledwo się trzymające. Jeśli takim drzewem potrząchniemy to te ledwo trzymające się gałęzie – czyli nasz nieużywany kod, po prostu odpadnie.

Bez tree-shakingu

Załóżmy, że nie korzystamy z bundlera, który oferuje tree-shaking, budujemy aplikacje i mamy taki plik z matematycznymi funkcjami pomocniczymi, które stworzyliśmy sobie już kiedyś, podesłał nam znajomy lub pobraliśmy go z menadżera pakietów, np. npm. Teraz załóżmy, że w naszej aplikacji chcemy skorzystać z funkcji add.

Importujemy funkcję za pomocą słowa kluczowego import, add(1, 2) powinno nam zwrócić 3, a więc wszystko działa jak należy.

Jest tu jednak pewien haczyk.

Mimo że użyliśmy destrukturyzacji i na pierwszy rzut oka wygląda jakbyśmy importowali tylko funkcję add to tak naprawdę do pakietu wynikowego dołączany jest cały plik mathUtils, a więc również funkcje minus, multiple i divide, z których w naszej aplikacji zupełnie nie korzystamy co niepotrzebnie zwiększa wagę naszej aplikacji.

Z tree-shakingiem

Teraz wyobraźmy sobie scenariusz, w którym nasz bundler korzysta z tree-shakingu.

Możemy zrobić nawet coś takiego jak poniżej, czyli zaimportować funkcję divide, a obecnie najnowsza wersja webpacka pozbędzie się z kodu wynikowego nie tylko funkcji minus, multiple, ale również divide, ze względu na to, że nie jest ona nigdzie używana. Super.

Kiedy tree-shaking nie działa?

Tree-shaking polega na statycznym działaniu modułów ES6, a więc nie zadziała albo to działanie będzie utrudnione i mniej efektywne na zaimportowanych plikach, które korzystają z modułów CommonJS, które są dynamiczne, tzn. możemy je zaimportować w trakcie działania aplikacji pod jakimś konkretnym warunkiem. A to sprawia, że webpack czy inny bundler nie jest w stanie zadecydować, które z modułów zostaną użyte zanim nie włączymy aplikacji.

Importy ES6

Importy CommonJS

Z tego też powodu jeśli chcemy, żeby tree-shaking w naszym bundlerze działał poprawnie, musimy się upewnić, że przed procesem tree-shakingu nie ma miejsca proces transpilacji kodu ES6 do kodu ES5 z modułami CommonJS (a to jest dokładnie to, co robi bardzo popularny preset do babela – @babel/preset-env).

Tree-shaking, a biblioteki

Do poprawnego tree-shakingu musimy się też upewnić, że biblioteki, z których korzystamy wykorzystują moduły ES6 i tutaj świetnym przykładem będzie biblioteka lodash, który z nich nie korzysta, na co się natknąłem pracując ostatnio dla Idego w projekcie ScopeOne.

Początkowo importowaliśmy funkcje pomocnicze lodasha w poniższy sposób:

Z czasem okazało mimo korzystania jedynie z funkcji get oraz kilku innych do naszego kodu wynikowego trafiał calutki lodash. Remedium na to zjawisko jest między innymi paczka lodash-es, która jest po prostu kopią biblioteki lodash, ale wyeksportowaną w postaci modułów ES6.

Innym rozwiązaniem byłyby tzw direct imports:

lub użycie babel-plugin-lodash.

Warto dodać, że według https://lodash.com/per-method-packages część współczesnych bundlerów pozwala na obejście się bez wyżej opisanych problemów.

webpack-bundle-analyzer

Jeśli chcesz sprawdzić, czy Twoja aplikacja nie zawiera przypadkiem sporej ilości niepotrzebnego kodu możesz skorzystać z webpack-bundle-analyzer, czyli pluginu do webpacka, który zwizualizuje pliki wynikowe twojej aplikacji wyszczególniając poszczególne zależności w bardzo przystępny dla oka sposób.

Dzięki temu będziesz mógł:

  • sprawdzić co tak naprawdę trafiło do naszego bundle.js,
  • zauważyć, które zależności ważą najwięcej,
  • zauważyć, które zależności trafiły tam przez przypadek i są zbędne,
  • zoptymalizować aplikację poprawiając importy i pozbywając się niepotrzebnego kodu.

Jak widzicie web tree-shaking pozwala w łatwy i szybki sposób zrobić porządek z tym czego już nie chcemy. Zachęcam do wypróbowania i odciążenia swojego kodu!


Zdjęcie główne artykułu pochodzi z unsplash.com.

teleturniej programista100k

Patryk Nawolski. W codziennej pracy uwielbia czysty kod. Zwraca uwagę na modułowość i łatwość konserwacji rozwiązań. Jest fanem animacji przygotowanych dla lepszego UX. Dąży do większej wydajności pracy, automatyzując i optymalizując każde powtarzające się zadanie. Miał okazję pracować nad wieloma niesamowitymi projektami w międzynarodowym środowisku, które pozwoliły mu zdobyć doświadczenie w wielu obszarach tworzenia stron internetowych.

Podobne artykuły

[wpdevart_facebook_comment curent_url="https://geek.justjoin.it/tree-shaking/" order_type="social" width="100%" count_of_comments="8" ]