eduardweb.
PerformanceIntermediar#performance#react#javascript#webpack

Dynamic import-ul nu e moca: cum calculezi când merită să spargi bundle-ul

De Liliana Ghiță, 5 iul. 2026 · 13 vizualizări · 2 like-uri

Postat 5 iul. 2026
typescript
import { useState } from 'react';

export function LazyChart() { 
  const [ChartComponent, setChartComponent] = useState<any>(null);

  const preloadComponent = () => {
    if (!ChartComponent) {
      // Începe descărcarea doar la hover sau focus
      import('./HeavyChart').then((module) => {
        setChartComponent(() => module.default);
      });
    }
  };

  return (
    <div onMouseEnter={preloadComponent} onFocus={preloadComponent}>
      {ChartComponent ? (
        <ChartComponent />
      ) : (
        <button onClick={preloadComponent}>Afișează Grafic</button>
      )}
    </div>
  );
}

Am văzut prea des recomandarea asta oarbă: „pune dynamic import peste tot și o să ai un Lighthouse score de 100”. Am mușcat și eu gălușca asta acum vreo trei ani pe un proiect de e-commerce cu vreo 15.000 de useri zilnici. Am spart tot ce se putea sparge în micro-chunk-uri. Rezultatul? Pagina se încărca mai greu pe mobil, iar userii aveau o experiență de navigare sacadată.

Unde apare problema când ai prea multe bucățele

Când folosești import() din ES6, browserul trebuie să facă un request HTTP separat pentru fiecare chunk. Dacă ai spart o pagină în 20 de fișiere de câte 2-3 KB, ai făcut o mare greșeală.

Da, ai redus bundle-ul inițial cu 50 KB. Dar ai introdus 20 de conexiuni TCP suplimentare (sau chiar și pe HTTP/2, ai overhead de handshaking, parsare și latență de rețea). Pe o conexiune 3G mobilă sau chiar pe un 4G mai obosit dintr-un mall, latența de peste 150ms pentru fiecare request o să facă interfața să pară complet blocată. Userul dă click pe un tab, așteaptă jumătate de secundă să se descarce chunk-ul de 2 KB, apoi se randează. E o experiență groaznică.

Cum calculezi dacă merită (Break-even-ul)

Eu folosesc o regulă empirică simplă, testată pe câteva zeci de proiecte în ultimii ani. Nu sparg în chunk separat nimic dacă acel modul are sub 20 KB (gzipped).

De ce? Pentru că sub această dimensiune, timpul de descărcare al fișierului este neglijabil față de timpul necesar pentru a iniția conexiunea și a parcurge rețeaua.

Matematica din spate arată cam așa:

  • Costul fix: Latența de rețea (RTT) + negociere TLS + overhead HTTP header. Pe mobil, asta înseamnă între 80ms și 300ms.
  • Costul variabil: Timpul efectiv de transfer al datelor. Pentru 10 KB, la o viteză medie de 10 Mbps, transferul durează sub 1ms.

Dacă pui dynamic import pe o componentă de 5 KB, plătești 200ms de latență ca să economisești 0.5ms la încărcarea inițială. Este o afacere extrem de proastă.

Soluția de mijloc: Prefetch inteligent

Dacă totuși ai o componentă mare (cum ar fi un editor de text sau un grafic complex de 150 KB) care nu e vizibilă imediat, folosește dynamic import, dar cu prefetching. Îi spui browserului să descarce codul când are timp liber, după ce pagina principală s-a încărcat deja. Sau, și mai bine, încarcă codul doar când utilizatorul dă semne că vrea să interacționeze cu acea zonă.

Uite un exemplu simplu de prefetching la hover pe butonul care deschide componenta grea. Economisești timp prețios înainte ca utilizatorul să apuce să dea click.

Trade-off-ul sincer

Dynamic import-ul e genial pentru rute mari (pagini separate) și pentru librării masive pe care nu le folosești imediat (gen PDF generators, chart-uri complexe). E absolut dezastruos pentru componente mici de UI, cum ar fi dropdown-uri, modale simple de confirmare sau tooltips. Pe acestea din urmă lasă-le în bundle-ul principal.

Voi cum procedați? Aveți o limită clară de mărime de la care decideți să spargeți un bundle, sau mergeți doar pe intuiție?

Răspunsuri 0

Se încarcă răspunsurile…

Loghează-te pentru a răspunde

Doar membrii comunității pot lăsa comentarii.