eduardweb.
PerformanceIntermediar#optimization#react#vite#javascript#web-performance

Bundle splitting cu dynamic import: ce pierzi dacă abuzezi și cum calculezi break-even-ul

De Alexandru Matei, 26 iul. 2026 · 10 vizualizări · 3 like-uri

Postat 26 iul. 2026
typescript
// Helper simplu pentru preloading la hover (React / Vanilla)
const componentLoader = () => import('./HeavyChartComponent');

// Pre-încărcăm chunk-ul când user-ul duce cursorul peste buton
export function AnalyticsButton() {
  const handleMouseEnter = () => {
    // Începe descărcarea pe rețea înainte de click
    componentLoader();
  };

  return (
    <button 
      onMouseEnter={handleMouseEnter}
      onClick={async () => {
        const { HeavyChart } = await componentLoader();
        // Renderizează componenta deja descărcată
      }}
    >
      Vezi Grafic
    </button>
  );
}

Se vorbește extrem de mult despre code splitting de parcă ar fi un glonț de argint pentru Lighthouse. Acum doi ani am făcut greșeala să pun React.lazy() pe fiecare tab și modal dintr-un dashboard cu aproximativ 12k utilizatori zilnici. Rezultatul? Ne-am trezit cu o latență percepută mai mare, layout shifts și un waterfall de request-uri care a distrus UX-ul pe rețele mobile.

Haideți să vedem ce se întâmplă sub capotă când abuzezi de dynamic imports și cum afli matematic unde e punctul de break-even.

Costul ascuns al micro-chunk-urilor

Fiecare import() dinamic îi spune bundler-ului (Vite, Webpack, Rspack) să creeze un chunk separat. Sună bine în teorie: trimiți mai puțin JS la initial load. În practică, un fișier JS suplimentar nu înseamnă doar octeți descărcați, ci și un cost fix pe rețea și pe thread-ul principal.

Când ai 50 de chunk-uri de câte 3KB - 5KB fiecare, plătești scump:

  • RTT (Round Trip Time) și overhead de rețea: Chiar și pe HTTP/2 sau HTTP/3 cu multiplexare, deschiderea stream-urilor, procesarea header-elor și congestion control-ul adaugă timp. Pe o conexiune 4G medie, un RTT variază între 50ms și 120ms.
  • Waterfall de executat: Dintr-o dată, browserul trebuie să descarce parent-chunk.js, să-l evalueze, să vadă că acolo există un import(), să facă request pentru child-chunk.js și abia apoi să randeze. Ai creat o cascadă secvențială.
  • Parsing & Execution Overhead: V8 (engine-ul din Chrome) procesează mai eficient un singur script de 100KB decât 20 de scripturi de 5KB, din cauza modului în care funcționează optimizările de memorie și contextul de execuție.

Cum calculezi punctul de break-even

Trade-off-ul e simplu: scazi timpul de First Contentful Paint (FCP) al paginii inițiale, dar crești latența la interacțiunea utilizatorului când deschide o funcționalitate nouă. Ca să nu decizi „după ureche”, folosește o regulă bazată pe două variabile: mărimea chunk-ului și probabilitatea de utilizare.

1. Pragul de mărime (Size Threshold)

Dynamic import-ul își scoate banii doar dacă fișierul extras are peste 30KB - 50KB gzipped. Sub 20KB gzipped, overhead-ul de rețea (RTT) și overhead-ul de parsing depășesc aproape întotdeauna timpul economisit la descărcarea inițială.

2. Probabilitatea de accesare (User Intent)

Un calcul simplu pe care îl aplic pe proiecte: Câștig Net = (Bundle Inițial Salvat / Viteză Rețea) - (RTT * Număr Cascaderi)

Dacă o componentă este accesată de peste 60-70% dintre utilizatori în primele 10 secunde din sesiune (cum ar fi tab-ul principal din profil sau meniul de navigație), NU o splitui. O pui direct în bundle-ul principal sau folosești prefetching.

Split-ul merită cu adevărat doar pentru:

  • Rutare principală (page-level splitting).
  • Librării grele folosite rar (ex: Chart.js, PDF exporters, monaco-editor, WYSIWYG).
  • Fluxuri secundare (modale de admin, ecrane de setări avansate pe care le deschid 5% din useri).

Preloading inteligent în loc de lazy loading chior

Dacă ai un chunk mare de care chiar ai nevoie mai târziu, nu aștepta până când utilizatorul dă click pe buton ca să declanșezi descărcarea. Trage codul pe hover sau pe focus în input.

Răspunsuri 0

Se încarcă răspunsurile…

Loghează-te pentru a răspunde

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