Jak wykryć nieużywane biblioteki JS
Wiele aplikacji webowych rośnie wraz z dodawaniem nowych funkcji, bibliotek i szybkich rozwiązań z internetu. Po pewnym czasie część z tych zależności przestaje być używana, ale nadal jest ładowana do przeglądarki lub trzymana w projekcie. W efekcie rośnie rozmiar bundle, pogarsza się performance i wydłużają się czasy ładowania przez dodatkowe zapytania HTTP. Ten artykuł pokazuje praktyczne metody wykrywania i weryfikowania nieużywanech bibliotek w projektach JS, narzędzia które warto znać oraz kroki, jak bezpiecznie je usunąć.
Dlaczego warto wykrywać i usuwać nieużywane biblioteki
Usuwanie zbędnych zależności to nie tylko kwestia estetyki projektu. Konsekwencje ekonomiczne i techniczne są realne:
- Wydłużony czas ładowania strony i gorsze wyniki w narzędziach takich jak Lighthouse — negatywny wpływ na SEO i performance.
- Większy bundle oznacza więcej pamięci i wolniejsze parsowanie JS po stronie klienta.
- Potencjalne luki bezpieczeństwa — nieaktualizowane pakiety stają się wektorem podatności.
- Zwiększone koszty utrzymania: trudniej robić refaktoryzacje i aktualizacje, gdy repozytorium zawiera niepotrzebne zależności.
- Zwiększona złożoność dependency tree — trudności z debugowaniem i konfliktami wersji.
Dzięki regularnej kontroli zależności można zmniejszyć ryzyko i poprawić doświadczenie użytkownika końcowego.
Metody i narzędzia do wykrywania nieużywanych bibliotek
Istnieje kilka podejść do identyfikacji nieużywanych pakietów — od analiz statycznych, przez analizę bundla, po monitorowanie runtime. Każde ma zalety i ograniczenia. Poniżej opisane są najważniejsze techniki oraz narzędzia, które warto wprowadzić do workflow.
Analiza runtime w przeglądarce
- Coverage w Chrome DevTools: otwórz DevTools → More tools → Coverage. Wykonaj odświeżenie i sprawdź, które pliki JS mają niski procent wykorzystania. To szybki sposób, aby zidentyfikować kod, który jest pobierany, ale nie wykonywany.
- Lighthouse: testuje stronę pod kątem wydajności i raportuje „Unused JavaScript”. Zwróć uwagę na pliki i fragmenty kodu wskazane jako nieużywane.
- Network + Performance: sprawdź, które pliki są ładowane przy starcie i ile czasu zajmuje ich pobranie i wykonanie.
Analiza bundla
Jeżeli używasz bundlera (webpack, Rollup, Parcel), analiza wynikowego bundle pozwala zobaczyć, które pakiety zajmują najwięcej miejsca i które moduły są ładowane.
- webpack-bundle-analyzer — tworzy interaktywną mapę graficzną rozmiaru pakietów. Pozwoli szybko zlokalizować duże biblioteki.
- source-map-explorer — analizuje plik JS wraz z mapą źródłową i pokazuje rozkład rozmiaru według modułów.
- Rollup i narzędzia do statycznej analizy generują raporty, które pomagają zidentyfikować niezoptymalizowane moduły.
Analiza zależności w kodzie (statyczna)
- depcheck — popularne narzędzie do wykrywania nieużywanych zależności w package.json. Mimo przydatności potrafi dawać fałszywe alarmy przy dynamicznych importach.
- eslint z regułami dotyczącymi nieużywanych importów (np. no-unused-vars, import/no-extraneous-dependencies) — pomocne przy znajdywaniu nieużywanych modułów w kodzie źródłowym.
- npm-check / npm-check-updates — narzędzia do przeglądu zależności, ich stanu i przydatności.
Analiza produkcyjna i telemetryczna
Analizy w środowisku produkcyjnym pokazują, co rzeczywiście trafia do użytkowników:
- Logi CDN i analizy ruchu — które pliki są pobierane przez użytkowników (czy np. większość użytkowników nie pobiera pewnych chunków).
- Monitoring wydajności (RUM — Real User Monitoring) — metryki ładowania i wykonania skryptów u rzeczywistych użytkowników.
- Mapy source map i narzędzia do profilowania (np. Sentry, New Relic) — wyłapywanie długich zrzutów stosu, fragmentów kodu wpływających na długi czas działania.
Praktyczny proces wykrywania — krok po kroku
Poniżej znajduje się proponowany cykl, który można wdrożyć w zespole, aby systematycznie wychwytywać nieużywane biblioteki i minimalizować ryzyko błędnych usunięć.
- Krok 1 — inwentaryzacja: wygeneruj listę zależności z package.json i zidentyfikuj te, które ostatnio zostały dodane lub niezmieniane od dłuższego czasu. Użyj npm ls / yarn list dla drzewa zależności.
- Krok 2 — statyczna analiza: uruchom depcheck i eslint, aby zidentyfikować potencjalne nieużywane pakiety. Zanotuj ostrzeżenia i przygotuj listę do weryfikacji manualnej.
- Krok 3 — analiza bundla: stwórz produkcyjny build i przeanalizuj wynik za pomocą source-map-explorer lub webpack-bundle-analyzer. Zwróć uwagę na duże paczki i moduły, które mogą być ładowane niepotrzebnie.
- Krok 4 — runtime verification: użyj Coverage w Chrome oraz Lighthouse, żeby potwierdzić, które pliki są faktycznie ignorowane przy użytkowaniu. Sprawdź przypadki edge-case: dynamiczne importy, feature flags, lazy loading.
- Krok 5 — eksperyment w oddzielnym branchu: usuń podejrzane zależności lokalnie, uruchom testy oraz build. Ręcznie przetestuj krytyczne ścieżki aplikacji i uruchom automatyczne testy e2e.
- Krok 6 — wdrożenie kontrolowane: po pozytywnej weryfikacji, wdróż zmiany stopniowo (canary, staged rollout) i monitoruj telemetrykę (Bugsnag/Sentry, RUM).
Automatyzacja i integracja w CI/CD
Aby nie dopuścić do ponownego narastania nieużywanych zależności, warto zautomatyzować kontrole w pipeline CI. Oto sugestie jak to zrobić:
- Uruchamiaj depcheck i eslint jako job w CI; oznacz jako ostrzeżenie lub błąd w zależności od reguł zespołu.
- Generuj raporty webpack-bundle-analyzer w formie statycznych plików HTML i przesyłaj je jako artefakt builda — pozwala to reviewować zmiany w bundle między kolejnymi PR-ami.
- Wprowadź threshold size checks: jeśli build zwiększy się powyżej określonego progu, pipeline powinien zgłosić błąd lub ostrzeżenie.
- Integracja z review — dodawaj checklistę do pull requestów (np. „Nowa zależność? Dlaczego?”), wymagaj uzasadnienia i ewaluacji rozmiaru.
Jak bezpiecznie usuwać i zastępować biblioteki
Usuwanie zależności może być prostsze lub bardziej ryzykowne w zależności od sposobu jej użycia. Oto praktyczne wskazówki, aby przeprowadzić to bezboleśnie:
- Sprawdź wszystkie importy i require — użyj wyszukiwania w repozytorium. Upewnij się, że nie ma dynamicznych odwołań typu require(someVar) lub eval, które uniemożliwią statyczne wykrycie użycia.
- Uważaj na biblioteki z sideEffects — nawet gdy nie ma jawnych importów, pliki mogą wykonywać kod przy ładowaniu. W package.json sprawdź pole sideEffects.
- Zastąp duże biblioteki lżejszymi modułami albo natywnymi API. Przykłady: zamiast lodash.get użyj optional chaining (?.), zamiast moment.js użyj date-fns lub Temporal / Intl.
- W przypadku bibliotek używanych tylko w niektórych ścieżkach, rozważ lazy loading (dynamic import) i code splitting, aby nie ładować ich na start.
- Jeśli pojawiły się fałszywe fałszywe alarmy: oznacz pliki jako używane lub dostosuj reguły depcheck/ESLint. Dokumentuj wyjątki, żeby nie gubić kontekstu.
Typowe pułapki i jak ich unikać
Poniżej lista częstych problemów, które mogą prowadzić do błędnego usunięcia zależności lub do błędnych wyników analizy:
- Dynamiczne importy i require — narzędzia statyczne mogą nie wykryć użycia. Ręczna weryfikacja jest konieczna.
- Side effects — biblioteki, które modyfikują global state lub prototypy, mogą być ładowane tylko dla efektu ubocznego.
- Pliki ładowane przez zewnętrzne runtime’y — przykładowo pluginy do bundlera, build-time scripts — mogą być pominięte przez proste skrypty sprawdzające.
- Posługuj się source maps przy analizie bundla — bez nich analiza rozmiaru będzie mniej precyzyjna.
- Fałszywe pozytywy w depcheck — sprawdź listę ręcznie zanim usuniesz zależność.
Przykładowe narzędzia i polecenia
Poniżej krótkie wskazówki jak uruchomić najważniejsze narzędzia:
- depcheck: npx depcheck — raport nieużywanych dependencies i devDependencies.
- webpack-bundle-analyzer: po buildzie uruchom npx webpack-bundle-analyzer dist/stats.json lub zintegruj plugin w konfiguracji webpacka.
- source-map-explorer: npx source-map-explorer dist/main.js dist/main.js.map.
- Chrome Coverage: DevTools → Coverage → Start instrumenting and reload.
- Lighthouse: DevTools → Lighthouse lub użyj npx lighthouse https://example.com.
- npm-check: npx npm-check — interaktywny przegląd pakietów, pomocny do ręcznego odinstalowania.
Dobre praktyki przy zarządzaniu zależnościami
Wprowadzenie kilku zasad organizacyjnych zmniejszy prawdopodobieństwo, że projekt znowu zapełni się niepotrzebnymi bibliotekami:
- Zasada „każda nowa zależność wymaga uzasadnienia” — prośba o dodanie pakietu powinna zawierać analizę rozmiaru i alternatywy.
- Regularne przeglądy pakietów (quarterly dependency audits) — audytuje się nie tylko nieużywane, ale i podatne pakiety.
- Preferowanie natywnych rozwiązań i lekkich mikro-bibliotek zamiast monolitycznych pakietów.
- Utrzymanie testów end-to-end i integracyjnych, które pomagają wykryć regresje po usunięciu zależności.
- Oznaczanie wyjątków i dokumentowanie powodów pozostawienia nienaruszonych pakietów (np. compatibility, legacy code).
Przykładowe scenariusze i rozwiązania
Kilka typowych przypadków z praktyki i rekomendowane podejścia:
- Problem: Aplikacja ładuje moment.js globalnie, ale używa tylko formatowania dat w jednym miejscu.
- Rozwiązanie: Zastąp moment.js lżejszym date-fns lub użyj Intl.DateTimeFormat, albo ładować moment tylko w lazy-chunk dla dedykowanej strony.
- Problem: W package.json jest wiele devDependencies nieużywanych po refaktoryzacji.
- Rozwiązanie: Użyj depcheck, a następnie ręcznie przetestuj i odinstaluj pakiety. Zadbaj o aktualizację skryptów w package.json.
- Problem: Library z globalnymi side effects jest rozpoznawana jako nieużywana.
- Rozwiązanie: Potwierdź zachowanie biblioteki, a jeśli jest potrzebna wyłącznie dla efektów ubocznych, pozostaw ją i udokumentuj powód. W przeciwnym wypadku refaktoryzuj kod tak, aby nie polegał na side effects.
Podsumowanie kroków do natychmiastowego zastosowania
Jeżeli chcesz zacząć dziś: uruchom depcheck, zrób production build i sprawdź go narzędziem typu webpack-bundle-analyzer, oraz przeprowadź Coverage w Chrome. Opracuj listę podejrzanych zależności, usuń je w oddzielnym branchu, uruchom testy i wdrożenie etapowe z RUM. Wprowadź również automatyczną kontrolę w CI, żeby wykrycia były regularne i widoczne dla zespołu.


