Performance
Splitting the JavaScript bundle: what actually changes
Our build produces 48 chunks at 172 kB gzipped, and 43 chunks stay under 15 kB. How to split, what it buys and when it goes too far.
Key points
- Splitting the bundle removes from the first paint the code needed later.
- Our build with Vite 5.4.21 produces 48 chunks, 511 kB raw and 172 kB gzipped.
- 43 of 48 chunks stay under 15 kB: route-level splitting works.
- Under 5 kB per chunk the request costs more than the code it saves.
Splitting the bundle means loading only the first screen's code on startup and fetching the rest when it is needed: in our build that is 48 chunks and 172 kB gzipped in total.
The three cuts that matter
| Cut | What it separates | Gain | Cost |
|---|---|---|---|
| Route | One page per file | A lighter first paint | One round trip on navigation |
| Vendor | Stable dependencies | A long cache across deploys | The vendor chunk stays large |
| Feature | Heavy code used after a click | Nothing at load time | A loading state to manage |
The route cut is the one that moves the numbers: the entry stays small and every page pays for its own code. The vendor cut is about caching, not about the first paint.
Measuring the real chunks
node -e "const fs=require('fs'),z=require('zlib'),d='client/dist/assets';const f=fs.readdirSync(d).filter(x=>x.endsWith('.js'));let g=0;for(const x of f)g+=z.gzipSync(fs.readFileSync(d+'/'+x)).length;console.log(f.length,'chunk',Math.round(g/1024),'kB gzip')"
The command needs Node and a build that already ran. It answers one question only: how many bytes of JavaScript the first page downloads, not how many the whole project holds.
When it goes too far
- Under 5 kB per chunk the request costs more than the code it saves.
- One chunk per component multiplies requests and pushes the problem onto the network.
- Keep route prefetching selective: precaching everything cancels the cut.
The limitation to name
An extra chunk is not free: it costs a request, a header and a parse. HTTP/2 lowers the cost per request, but parse and compile stay on the main thread and mobile users feel them. The number to watch is not the sum of the chunks but the graph the first screen actually loads.
Where to continue
The EneUI catalogue indexes 111,985 components, 1,556 blocks and the record CPU architecture: a chart with hundreds of nodes belongs in its own chunk, not in the entry. For the single import that grows the bundle read one import that grows the bundle, for library weight the weight of a UI library, and for the measured comparison React libraries 2026.
Frequently asked questions
Are code splitting and bundle splitting the same?
In practice yes: both divide the output into several files. Code splitting describes the cut in the source, bundle splitting the output of the bundler.
Do I need a bundler to split a bundle?
Not strictly, but it helps: Vite, Rollup and webpack handle chunk boundaries and hashed names. By hand you are left with dynamic import().
Below what size does splitting stop paying?
Under 5 kB per chunk: the request costs more than the code it avoids, especially on mobile networks.
Does route splitting slow navigation down?
The first navigation pays one round trip. Prefetch the most likely chunk instead of precaching every chunk.
How do I measure the real weight?
With gzip over the dist files and the sum of the chunks the first page really loads. The project total is not the number the user sees.