export default {
build: {
rollupOptions: {
output: {
manualChunks(id) {
if (id.includes('node_modules/chart.js') || id.includes('node_modules/d3')) {
return 'vendor-charts';
}
}
}
}
}
};Am văzut prea des recomandarea „pune dynamic import la orice componentă mai mare” ca rețetă universală de performanță. E o capcană în care am căzut și eu acum vreo trei ani pe un proiect cu 15.000 de utilizatori activi zilnic. În realitate, dacă abuzezi de bundle splitting, distrugi experiența utilizatorului din cauza latenței de rețea și a fragmentării excesive.
Hai să vedem de ce regula de aur nu e „split everything”, ci cum să găsești punctul în care optimizarea chiar își merită costul de implementare.
Costul ascuns al fragmentării (Micro-chunking)
Când rulezi un audit de Lighthouse, scorul tău crește dacă ai un bundle inițial mic. Sună ideal, nu? Dar Lighthouse rulează într-un mediu controlat, adesea fără latență reală de rețea mobilă (sau cu una simulată destul de prost).
Am pățit pe un proiect de e-commerce ca echipa să spargă fiecare modal, dropdown și tab în dynamic imports separate. Rezultatul? Pagina principală descărca doar 80KB de JS inițial. Super! Însă, când utilizatorul dădea click pe „Adaugă în coș”, browserul trebuia să facă un request nou pentru chunk-ul de modal, apoi alt request pentru animația de succes, apoi altul pentru scriptul de tracking.
Pe o conexiune 3G sau 4G congestionată, acele 3 extra request-uri de câte 5KB adăugau o întârziere de aproape 1.2 secunde între click și feedback-ul vizual. Utilizatorul dădea click de trei ori crezând că site-ul e blocat. Am rezolvat problema comasând acele micro-chunk-uri înapoi în bundle-ul principal, crescând dimensiunea inițială cu doar 15KB, dar eliminând latența complet.
Cum calculezi pragul de rentabilitate (Break-even)
Ca să nu mergi pe ghicite, folosește o regulă simplă bazată pe probabilitatea de utilizare. Nu merită să faci dynamic import pentru o componentă dacă probabilitatea ca utilizatorul să o acceseze în prima sesiune este mai mare de 40-50%.
Iată logica pe care o aplic eu:
- Frecvența de acces: Dacă ai un tab de „Setări Cont” unde intră doar 5% dintre utilizatori, dynamic import este obligatoriu. Economisești 95% din bandwidth pentru majoritatea vizitatorilor.
- Dimensiunea prag: Un chunk separat ar trebui să aibă cel puțin 20-30KB după compresie (gzip/brotli). Dacă faci split pentru o componentă de 3KB, overhead-ul de conexiune HTTP (chiar și pe HTTP/2) depășește timpul de descărcare al acelor 3KB în bundle-ul principal.
- Latența vs. Lățimea de bandă: Pe mobil, latența (RTT - Round Trip Time) este inamicul numărul unu, nu lățimea de bandă. Este mult mai rapid să descarci un singur fișier de 200KB decât 10 fișiere de 20KB.
Cum controlezi asta în config
Dacă folosești Vite sau Webpack, nu lăsa bundlerul să facă split complet haotic. Poți grupa manual librăriile mari sau componentele similare în chunk-uri logice folosind configurarea de build. De exemplu, în loc de 5 chunk-uri pentru 5 grafice diferite, le poți grupa pe toate într-un singur chunk numit charts pe care îl încarci asincron doar când e nevoie.
La final, trade-off-ul e simplu: bundle splitting-ul agresiv dă bine în rapoartele de SEO și Lighthouse, dar distruge fluiditatea aplicației dacă utilizatorul navighează intens. Găsește echilibrul și nu te sfii să lași componentele medii în bundle-ul principal.
Voi cum abordați asta? Mergeți pe configurarea default din Next.js/Nuxt sau măsurați manual dimensiunile cu bundle analyzer?