Powrót do strony głównej

Rozdmuchiwanie zależności npm: 3 przyczyny i rozwiązania

Artykuł omawia trzy przyczyny rozrastania się zależności npm: wsparcie środowisk legacy, architektura atomowa i przestarzałe ponyfille. Opisano problemy duplikacji, ryzyka łańcucha dostaw i rekomendacje dotyczące cleanup. Materiał skierowany do programistów middle/senior.

Trzy przyczyny „rozdmuchiwania” zależności npm w JS
Advertisement 728x90

Dlaczego drzewa zależności npm rozrastają się: trzy kluczowe przyczyny

Drzewa zależności w projektach JavaScript często puchną z powodu przestarzałych pakietów, które dublują natywne możliwości platformy. To prowadzi do zbędnych kosztów ładowania, rozwiązywania wersji i luk w łańcuchu dostaw. Przyjrzyjmy się trzem typowym scenariuszom wyjaśniającym tę sytuację oraz sposobom ich naprawy.

Obsługa legacy-środowisk i specyfika realm

Wiele pakietów, takich jak is-string czy hasown, istnieje dla kompatybilności z archaicznymi środowiskami wykonawczymi, jak ES3 (IE6/7, wczesny Node.js). Implementują brakujące metody: Array.prototype.forEach, Array.prototype.reduce, Object.keys, Object.defineProperty.

Dodatkowe motywacje:

Google AdInline article slot
  • Ochrona przestrzeni globalnej: Node importuje primordials (np. Map), aby uniknąć awarii spowodowanych nadpisywaniem. Pakiety takie jak math-intrinsics ponownie eksportują Math.* w podobnym celu.
  • Kompatybilność realm: instanceof nie działa między iframe a rodzicem (różne konstruktory RegExp). Alternatywą jest Object.prototype.toString.call(val) === '[object RegExp]', jak w chai lub is-string dla new String(val).
const shebangRegex = /^#!(.*)/;
export default shebangRegex;

Dla większości middle/senior-developerów to przesada: współczesny Node (nie starszy niż 10 lat) i przeglądarki nie wymagają takich hacków. Zalecenie: sprawdzaj browserslist i usuwaj niepotrzebne polyfille.

Architektura atomowa: od teorii do problemów

Filozofia 'atomowych' pakietów zakłada podział na minimalne bloki do ponownego użycia. Przykład — graf zależności execa z pakietami takimi jak shebang-regex (5 linii kodu).

Typowe atomowe narzędzia:

Google AdInline article slot
  • arrify: Array.isArray(val) ? val : [val]
  • slash: normalizacja ukośników w ścieżkach
  • cli-boxes: JSON z granicami elementów UI
  • path-key: env['PATH'] || env['Path']
  • onetime: jednorazowe wywołanie funkcji
  • is-wsl: process.platform === 'linux' && /microsoft/.test(os.release())
  • is-windows: process.platform === 'win32'

W teorii to upraszcza budowanie CLI. W praktyce:

  • Jednorazowość: shebang-regex jest używany tylko przez shebang-command (ten sam autor); cli-boxes — tylko przez boxen/ink.
  • Duplikaty w hoisting: W nuxt duplikują się is-docker, is-stream, is-wsl (po 2 wersje). Wbudowany kod duplikuje się za darmo, bez npm-overhead.
  • Ryzyka łańcucha dostaw: Więcej pakietów — więcej luk. Kompromitacja jednego maintainera (jak w zeszłym roku) dotknęła setki zależności.

Rozwiązanie: inlining prostych funkcji, tree-shaking, pnpm ze strict hoisting.

Ponyfille, które przetrwały swoją epokę

Ponyfille (ponyfill) — to polyfille bez mutacji globali, importowane bezpośrednio. Przydatne dla bibliotek: @fastly/performance-observer-polyfill pozwala używać PerformanceObserver bez zmiany środowiska.

Google AdInline article slot

Problem: nie są usuwane po pojawieniu się natywnego wsparcia.

Przykłady przestarzałych ponyfilli (z cotygodniowymi pobraniami):

  • globalthis — dla globalThis (wsparcie od 2019, 49M downloads/week)
  • indexof — dla Array.prototype.indexOf (od 2010, 2.3M/week)
  • object.entries — dla Object.entries (od 2017, 35M/week)

W eslint-plugin-react połowa grafu to legacy-polyfille. Dla bibliotek: polegaj na consumer-side polyfillach (core-js). Sprawdzaj caniuse.com przed dodaniem.

Co jest ważne

  • Optymalizacja legacy: 90% pakietów nie potrzebuje ES3/ES5 polyfilli; używaj typeof zamiast is-string.
  • Atomowość szkodzi: Wbudowuj 5-liniowe funkcje, redukując duplikaty i powierzchnię ataku.
  • Audyt ponyfilli: Usuwaj pakiety dla funkcji wspieranych >5 lat w target runtime.
  • Narzędzia: npm ls --depth=0, depcheck, npm-check-updates do analizy.
  • Inicjatywa e18e: Skupienie na czyszczeniu przestarzałych deps dla wydajności.

Praktyczne kroki do czyszczenia

  • Uruchom npm dedupe i npm prune.
  • Dodaj overrides w package.json do wymuszonego hoistingu.
  • Używaj esbuild/vite z tree-shaking.
  • Monitoruj rozmiar bundla przez webpack-bundle-analyzer.

To zmniejszy rozmiar bundla o 20-50% bez utraty funkcjonalności.

— Editorial Team

Advertisement 728x90

Czytaj dalej