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

Bundle splitting cu dynamic import: unde tragi linia înainte să strici totul

De Vlad Stancu, 30 apr. 2026 · 1 vizualizări · 2 like-uri

Postat acum 2 zile
javascript
// Exemplu de splitting util: doar pentru librării masive
async function loadHeavyCharts() {
  const { default: ECharts } = await import('echarts');
  const chart = ECharts.init(document.getElementById('main'));
  // logică chart
}

// ABUZ: Nu face asta pentru 10 rânduri de cod
const MySmallComponent = React.lazy(() => import('./SmallComponent'));

Am văzut prea mulți dev-i care pun React.lazy sau import() pe fiecare componentă mai mare de 50 de linii, crezând că fac o mare optimizare. Adevărul e că dacă abuzezi de bundle splitting, s-ar putea să livrezi o experiență mai proastă decât dacă ai avea un singur fișier de 500KB. Dacă browserul trebuie să facă 40 de cereri HTTP în loc de 3, ai pierdut startul.

La un proiect de acum doi ani, un dashboard administrativ destul de stufos, am vrut să fiu "profesor" și am spart totul în bucățele. Rezultatul? Aveam vreo 80 de request-uri la load-ul inițial. Chiar și pe HTTP/2, latența aia cumulată de la fiecare negociere TLS și overhead-ul de headere ne-a omorât LCP-ul (Largest Contentful Paint). Am pierdut vreo 1.2 secunde pe mobile doar așteptând să vină "bucățelele".

Capcana micro-chunk-urilor

Problema e simplă: browser-ul nu descarcă totul în paralel instantaneu. Există limite de conexiuni și, mai important, există procesarea. Fiecare fișier JS descărcat trebuie parsat și executat separat. Dacă ai 10 fișiere de câte 2KB, overhead-ul rețelei și timpul de "boot" pentru fiecare script în parte e mult mai mare decât dacă ai avea un singur fișier de 20KB.

Am făcut un test pe un site cu aproximativ 12k useri zilnici. Am observat că pentru orice chunk sub 15-20KB (minified + gzipped), costul cererii HTTP depășea beneficiul economisirii de bandwidth. Practic, userul stătea mai mult să aștepte confirmarea de la server decât să tragă datele efective. E un trade-off sincer: câștigi la dimensiunea totală pe care o vede Lighthouse, dar pierzi la interactivitate reală pentru că browser-ul e ocupat să jongleze cu zeci de fișiere.

Cum calculezi break-even-ul?

Nu există o cifră magică universală, dar regula mea de bază e asta: dacă biblioteca sau componenta pe care vrei să o scoți din bundle-ul principal nu are măcar 30KB, las-o acolo. Excepția e dacă e o componentă care se încarcă strict la o acțiune rară a userului, cum ar fi un editor de text complex sau un modul de export PDF care trage după el 500KB de biblioteci.

Pentru un proiect mediu, am economisit cam 25% la timpul de încărcare (TBT) doar prin unirea unor bucăți mici înapoi în bundle-uri logice. E mult mai eficient să ai 3-4 chunk-uri mari (vendor, common-ui, route-main) decât 50 de fărâme de cod.

Strategia care chiar funcționează

În loc să spargi totul atomizat, mergi pe "Route-based splitting" prima dată. E cel mai sigur pariu. Apoi, uită-te în Webpack Bundle Analyzer sau Vite Bundle Visualizer. Vezi ce librării grele ai (moment.js, lodash, echarts). Dacă o librărie e folosită într-un singur loc, scoate-o cu dynamic import.

Dacă ai un modal de "Terms and Conditions" care are 2KB de JS, nu-i da dynamic import. Serios, nu merită request-ul suplimentar. Pune-l în bundle-ul paginii respective. Dynamic import-ul e o unealtă de precizie, nu un ciocan cu care să bați în orice componentă.

Voi cum procedați? Vă uitați la numărul de request-uri din Network tab sau vă interesează doar să fie bundle-ul principal sub un anumit prag de KB cu orice preț?

Răspunsuri 0

Se încarcă răspunsurile…

Loghează-te pentru a răspunde

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