// Exemplu de grupare a componentelor pentru a evita fragmentarea excesivă
// Proastă practică: 3 request-uri separate pentru 3 fișiere mici
const ProfileHeader = React.lazy(() => import('./ProfileHeader'));
const ProfileBio = React.lazy(() => import('./ProfileBio'));
const ProfileSettings = React.lazy(() => import('./ProfileSettings'));
// Practică mai bună: Grupare într-un singur chunk logic de ~40KB
// Folosind magic comments în Webpack pentru a le pune în același bundle
const ProfileModule = React.lazy(() =>
import(/* webpackChunkName: "profile-section" */ './ProfileContainer')
);
// Sau în Vite/Rollup, poți configura manual output.manualChunks în config
// pentru a evita crearea de fișiere de 2-3KB care doar încurcă browser-ul.Dacă pui import() peste tot în ideea că reduci bundle-ul de bază, s-ar putea să faci mai mult rău decât bine. Am văzut destule proiecte unde timpul de interacțiune a crescut cu peste o secundă fix din cauza fragmentării excesive a fișierelor de JavaScript.
Acum vreo doi ani, m-am ocupat de un dashboard complex pentru un client cu vreo 8.000 de useri activi zilnic. Eram în faza de optimizare și am decis să facem bundle splitting agresiv. Am zis că suntem deștepți: am spart totul, de la rute până la fiecare modal și dropdown mai greu, în chunk-uri separate folosind dynamic imports. Rezultatul pe hârtie? Main bundle-ul a scăzut de la 450KB la 90KB. Ne simțeam campioni până am testat pe un profil de rețea 4G mediu.
Surpriza a fost neplăcută. Deși pagina inițială se încărca repede, orice click prin aplicație declanșa un spinner care dura nepermis de mult. Browserul făcea câte 10-15 request-uri simultan pentru a aduce bucățelele de cod necesare. Chiar și cu HTTP/2 și multiplexare, overhead-ul fiecărui request (negociere TLS, latență, headers) a mâncat tot câștigul de mărime.
Capcana waterfall-ului de request-uri
Cea mai mare problemă la abuzul de dynamic imports este efectul de waterfall. Ai un chunk A care, odată încărcat, își dă seama că are nevoie de chunk-ul B, care la rândul lui importă o librărie utilitară din chunk-ul C. În loc să descarci un singur fișier optimizat, forțezi browserul să aștepte după trei rânduri de request-uri consecutive.
Am pățit asta la o integrare cu un editor de text. Am pus editorul în dynamic import, dar și plugin-urile lui erau tot dynamic. Userul stătea și se uita la un dreptunghi alb timp de 2 secunde pentru că fișierele se descărcau unul după altul, nu în paralel. Pe un device mobil mai vechi, procesarea acestor mici bucăți de JS (parse și compile) adaugă și ea un overhead care se simte la nivel de frame-uri pierdute.
Cum calculezi dacă merită (Break-even)
Regula mea de deget, învățată pe pielea mea: dacă un chunk are sub 20-30KB (după gzip), probabil nu merită să fie separat. Costul de a face un request HTTP adițional depășește beneficiul de a nu avea acei 20KB în bundle-ul principal.
Uite cum fac eu calculul acum. Dacă am o componentă de 10KB pe care 80% din useri o vor folosi în primele 30 de secunde, o las în main bundle. Dacă am un modul de 100KB (cum e un generator de PDF-uri) pe care doar 5% din useri îl accesează, ăla e candidatul perfect pentru dynamic import.
Trade-off-ul e simplu: vrei să minimizezi ce descarcă userul la început, dar fără să fragmentezi experiența de navigare ulterioară. La proiectul de care ziceam, am redus numărul de chunk-uri de la 50 la 12, grupând modulele pe feature-uri logice. Am economisit cam 30% la build time și am eliminat complet acele micro-lag-uri la navigare.
Strategia „Shared Chunks”
În loc de React.lazy(() => import('./Component')) pentru absolut orice, prefer să grupez componentele care sunt folosite împreună. De exemplu, toate setările de profil pot sta într-un singur chunk, chiar dacă tehnic sunt 5 pagini diferite.
Un alt pont: folosește webpackChunkName (sau echivalentul în Vite/Rollup) ca să forțezi gruparea mai multor importuri dinamice în același fișier fizic. Asta reduce numărul de request-uri fără să poluezi bundle-ul de start.
În final, bundle splitting-ul e ca sarea în mâncare: dacă pui prea puțină, aplicația e greoaie la start; dacă pui prea multă, devine de neutilizat pe parcurs. Voi ce limită de mărime folosiți înainte să decideți că o componentă merită propriul ei chunk?