eduardweb.
PerformanceIntermediar#performance#react#javascript#web-perf

Mitul dynamic-import: Când bundle splitting-ul îți încetinește site-ul și cum calculezi pragul de rentabilitate

De Maria Vasilescu, 26 mai 2026 · 4 vizualizări · 2 like-uri

Postat 26 mai 2026
typescript
import { useState } from 'react';

export function ExportButton() {
  const [isExporting, setIsExporting] = useState(false);

  // Începem descărcarea chunk-ului când utilizatorul doar pune mouse-ul pe buton
  const prefetchParser = () => {
    import('./heavyPdfParser').then(() => {
      console.log('Chunk pre-încărcat cu succes!');
    });
  };

  const handleExport = async () => {
    setIsExporting(true);
    const { exportToPdf } = await import('./heavyPdfParser');
    await exportToPdf();
    setIsExporting(false);
  };

  return (
    <button 
      onMouseEnter={prefetchParser} 
      onClick={handleExport}
      disabled={isExporting}
    >
      {isExporting ? 'Se exportă...' : 'Exportă PDF'}
    </button>
  );
}

Am văzut prea des greșeala asta în ultima vreme: un dev citește despre split-chunking, pune React.lazy sau dynamic import() peste tot și se declară mulțumit de scorul din Lighthouse. Dar în producție, pe un telefon mediu, aplicația începe să se miște sacadat, iar utilizatorii simt că „se agață” la fiecare click. Split-chunking-ul nu e gratuit, iar abuzul te costă mai mult decât un bundle inițial ceva mai mare.

Costul ascuns pe care Lighthouse nu ți-l arată

Când spargi codul în 30 de bucățele mici, muți efortul din faza de download inițial în faza de runtime. Da, primul ecran se încarcă cu 200ms mai rapid, dar ai creat o problemă de latență de rețea numită waterfall.

Am avut cazul unui e-commerce cu vreo 45.000 de sesiuni zilnice unde echipa a decis să facă dynamic import pentru fiecare tab din pagina de produs și pentru fiecare modal de confirmare. Am câștigat vreo 150KB la bundle-ul principal. Sună bine pe hârtie, nu? În realitate, când un utilizator de pe 4G dădea click pe „Review-uri”, trebuia să aștepte aproape o secundă ca browserul să facă request-ul HTTP, să primească chunk-ul de 8KB, să-l parseze și abia apoi să randeze tab-ul. Pe un dispozitiv mobil ieftin, latența de rețea combinată cu timpul de execuție a distrus complet UX-ul.

Fiecare request HTTP suplimentar are un cost fix de overhead (negociere conexiune, TLS, prioritizare în browser). Pe HTTP/2 lucrurile stau mai bine, dar dacă rețeaua e instabilă, pierderile de pachete pot bloca toate request-urile din coadă.

Cum calculezi break-even-ul: Regula de aur

Ca să nu mai mergem pe ghicite, am stabilit o regulă empirică în echipă, bazată pe datele din Analytics și teste de performanță. Calculăm rentabilitatea unui dynamic import folosind doi factori: dimensiunea codului (gzipped) și probabilitatea de interacțiune (engagement rate).

Formula e simplă: dacă un modul are sub 20KB gzipped și este accesat de peste 30% dintre utilizatori în timpul unei sesiuni obișnuite, nu merită să fie încărcat dinamic. Trebuie lăsat în bundle-ul principal.

De ce? Pentru că timpul necesar pentru a descărca acei 20KB suplimentari la încărcarea inițială (când conexiunea este deja deschisă și activă) este neglijabil (sub 10-20ms pe 4G). În schimb, să deschizi un request nou mai târziu te va costa garantat între 150ms și 800ms de latență (RTT + parsing). Pierzi la UX ca să câștigi un scor pur teoretic în tool-urile de analiză.

Cum optimizăm fără să fragmentăm excesiv

În loc să spargem totul orbește, grupăm resursele. Dacă ai 5 modale mici în aceeași pagină, le pui într-un singur chunk numit modals.[hash].js.

De asemenea, folosim prefetching inteligent. Dacă ești aproape sigur că utilizatorul va da click pe un element, instruiește browserul să descarce chunk-ul în background, când rețeaua e liberă.

În exemplul de mai jos, în loc să așteptăm click-ul utilizatorului pentru a încărca modulul de export PDF, declanșăm importul dinamic la mouseenter pe buton. Astfel, câștigăm acele câteva sute de milisecunde critice înainte ca userul să apese efectiv pe ecran.

Trade-off-ul e destul de clar aici: dynamic-import e excelent pentru rute mari (pagini complet diferite) și librării grele folosite rar (cum ar fi un chart complex sau un editor text bogat). Pentru componente mici de UI, este o rețetă sigură pentru o experiență de utilizare fragmentată.

Voi cum procedați la proiectele voastre? Aveți o limită de KB sub care refuzați să spargeți codul, sau lăsați totul pe seama configurărilor default din Webpack/Vite?

Răspunsuri 0

Se încarcă răspunsurile…

Loghează-te pentru a răspunde

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