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

Bundle splitting cu dynamic import: ce pierzi când abuzezi de el

De Cristian Barbu, 21 iun. 2026 · 17 vizualizări · 2 like-uri

Postat 21 iun. 2026
javascript
// vite.config.js
export default {
  build: {
    rollupOptions: {
      output: {
        manualChunks(id) {
          // Groupăm librăriile mici de utilități ca să evităm 20 de micro-chunk-uri
          if (id.includes('node_modules')) {
            if (id.includes('lodash') || id.includes('ramda') || id.includes('date-fns')) {
              return 'utils-vendor';
            }
          }
        }
      }
    }
  }
}

Toți am trecut prin faza în care am descoperit import() și am vrut să punem dynamic import peste tot ca să scoatem scor de 100 în Lighthouse. Realitatea din producție ne lovește însă rapid peste mână. Dacă fragmentezi aplicația în zeci de chunk-uri mici, s-ar putea să o faci de fapt mult mai leneșă pentru utilizatorul final.

Hai să vedem unde e pragul în care splitting-ul devine o problemă de performanță și cum calculezi dacă merită să spargi un modul sau nu.

Mitul HTTP/2 și realitatea din teren

Când a apărut HTTP/2, promisiunea a fost simplă: multiplexarea elimină penalizarea pentru request-uri multiple, deci putem trimite sute de fișiere mici fără probleme. În teorie, sună bine. În practică, browserul tot trebuie să parseze, să compileze și să execute fiecare fișier JS în parte.

Mai mult, pierdem masiv la capitolul compresie. Algoritmii ca Gzip sau Brotli funcționează excelent când au text mult și repetitiv în același fișier. Dacă spargi un bundle de 100KB în 10 chunk-uri de 10KB, dimensiunea totală descărcată va fi semnificativ mai mare decât cea a fișierului unic. Am pățit asta pe un proiect cu 12k useri zilnici: după un split agresiv, deși chunk-ul inițial scăzuse, traficul total de JS pe sesiune crescuse cu aproape 25% din cauza pierderii eficienței de compresie.

Efectul de waterfall (cascadă)

Cea mai mare capcană la dynamic import-urile folosite fără cap este waterfall-ul de request-uri network.

Imaginează-ți următorul scenariu:

  1. Utilizatorul accesează o pagină.
  2. Browserul descarcă main.js.
  3. main.js se execută și decide că are nevoie de ComponentA.js (dynamic import).
  4. Browserul cere ComponentA.js.
  5. ComponentA.js se descarcă, se execută și... surpriză, importă și el dinamic HeavyLibrary.js.

În loc să descarci totul în paralel, ai creat trei rânduri de request-uri consecutive. Pe o conexiune 3G mobilă, asta înseamnă secunde bune de ecran alb sau spinner de loading.

Cum calculezi break-even-ul?

Ca regulă generală, eu folosesc o formulă destul de simplă bazată pe două variabile: dimensiunea codului și probabilitatea de utilizare.

  • Sub 15-20KB (gzipped): Nu merită niciodată dynamic import. Costul unui nou request HTTP (chiar și cu HTTP/2 sau HTTP/3) plus overhead-ul de parsing depășește beneficiul de a nu descărca acei câțiva kiloocteți.
  • Probabilitate de utilizare > 80%: Dacă 8 din 10 utilizatori care intră pe pagină vor interacționa cu acea componentă (de exemplu, un meniu de navigare mobil sau un dropdown principal), las-o în bundle-ul principal. Nu are sens să amâni încărcarea pentru 20% din utilizatori, pedepsindu-i pe ceilalți 80% cu un delay la click.
  • Punctul de break-even: Merită să faci split doar dacă codul are peste 30KB și este folosit de mai puțin de 30% dintre utilizatori (de exemplu: un editor de text complex din zona de admin, grafice grele sau setări avansate).

Cum controlezi asta în build tooling

În loc să lași bundler-ul să creeze fișiere pentru fiecare import individual, poți folosi strategii de grupare în Vite sau Webpack. De exemplu, în Vite, poți grupa librăriile de utilități mici care nu au sens să fie chunk-uri separate.

Voi cum abordați bundle splitting-ul? Mergeți pe structura clasică pe rute sau aveți reguli stricte de dimensiune în echipa voastră?

Răspunsuri 0

Se încarcă răspunsurile…

Loghează-te pentru a răspunde

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