Monolithic bundle
Read + editor on the initial path
The feature set stays the same. Only delivery changes: one large file, two chunks preloaded together, or a read chunk now and an editor chunk after intent.
Read the full write-up: Bundle for Perceived Performance, Not Just Size ↗
Raw minified JavaScript is shown below. Gzip sizes are included in each build card for reference.
All frames use separate cold-cache run IDs and the same network profile.
Read + editor on the initial path
Read and editor chunks start together
Editor starts after intent
Run six cold trials for each build. Trials run one at a time, then the dashboard reports the median read time and edit wait.
Ready
The browser cannot evaluate the app until the read UI, CodeMirror, language modes, and editor feature data have all arrived.
Both chunks start together. The smaller read chunk can finish and render while the editor continues downloading and compiling.
Only the read chunk starts. This minimizes startup contention, but the first edit pays the editor download cost.
The goal is a fair, reproducible comparison, not a cherry-picked demo. Here is exactly what is real, what is simulated, and how to verify it yourself.
All three builds are ordinary Vite production bundles of the
same React app: minified, code-split with
React.lazy(), no fake loading timers. The build
script fails if the monolith drifts outside 800-1000KB, if the
split's initial chunk drifts outside 30-40% of total JS, or if
the three builds' feature sets drift by more than 5KB. That
keeps the comparison about delivery order, not about one build
secretly doing less work.
A small Node HTTP server enforces a fixed RTT latency, then
trickles the response in ticks capped to a per-profile
byte-budget: Office Wi-Fi (10Mbps, 30ms),
Fast 4G (4Mbps, 80ms), and
Slow 4G (1.6Mbps, 160ms). This is server-side
shaping applied to real bytes, not a client-side
setTimeout.
Each run gets a fresh UUID run ID baked into its URL, and every
response is sent with Cache-Control: no-store. The
browser cannot reuse a previous run's cached bytes, so the cold
race, the six-trial benchmark, and the manual profiling links
below all start from zero every time.
Every build card has a Throttled link, which opens that build alone under the server-side shaping above, and a Raw link, which serves the same cold build at full local speed with zero server delay. Use Raw when you want to apply Chrome or Firefox DevTools' own network and CPU throttling presets, or to record a Performance trace of parse and compile time without any artificial network delay in the way.
The Read ready metric comes from a
performance.mark() the app fires on a
requestAnimationFrame after React commits the read
view. It is a stable, reproducible application milestone, but
it is not the same thing as the browser's Largest Contentful
Paint. Treat LCP, visible in each build's own DevTools trace, as
the defensible paint-time number when the exact painted frame
matters.
In the cold race, all three builds run at once and share the same simulated aggregate bandwidth, the same way three tabs on one Wi-Fi network would. That contention is intentional: it is why the lazy build, which sends the least at startup, can finish its read chunk sooner than the eager build even though both start downloading together.
Do not stack both throttling layers at once. Opening a Throttled link while DevTools network throttling is also enabled will apply both delays and produce numbers that do not correspond to any real network. Use Throttled links with DevTools throttling off, and Raw links when you want DevTools in control.
For the full measured write-up, including Chromium and Firefox traces and the reconstructed download/parse/compile timeline, see Bundle for Perceived Performance, Not Just Size ↗.