Repository navigation
P 12 Code Splitting
Context: The workbench loaded CodeMirror (the SQL editor) and the chart panel as part of its initial script, so every visit downloaded and parsed them before the first paint, even before anyone typed a query or opened a chart. ECharts was already loaded on demand. Measured on main, the initial JavaScript of /app/ was 306.7 KB gzipped, over the 250 KB budget in Performance & Benchmarks.
Hypothesis: Loading the editor and the chart panel on demand takes them out of the initial script, which brings the initial JavaScript under budget and lets the app shell paint sooner. Engine start-up shouldn't change, since the engine is loaded separately.
-
Lazy panels: the SQL editor and the chart panel are loaded with
React.lazy. While they load, their fallbacks hold the panels' space, so nothing shifts. -
Chunks: CodeMirror is now its own
SqlEditor-*chunk (123.3 KB gzipped) and isn't modulepreloaded. The chart panel (3.2 KB) and ECharts (177.6 KB) are separate chunks. - Early text: text sent to the editor before it has loaded, such as a template or history entry picked straight away, is kept and applied when the editor mounts. Before this change it would have been dropped. A unit test covers it.
-
Analysis:
BLINKQL_ANALYZE=1 pnpm buildwrites a treemap of every chunk, with gzipped sizes, tobench/bundle/stats.html(git-ignored), usingrollup-plugin-visualizer.
Method:
-
Initial JavaScript: every
<script type="module">andmodulepreloadindist/app/index.html, compressed with gzip -9, excluding WebAssembly and the engine's worker. -
Scenarios:
time-to-app-shell(navigation start until theblinkql:app-shellmark) andtime-to-engine-ready, each cold and warm. -
Builds:
mainat3639160as the baseline and the branch ate064147, both clean, served byvite preview. -
Same session:
mainwas run straight before the branch, about a minute apart, so laptop drift affects both equally. - Iterations: 3 warm-up and 10 measured iterations per scenario and mode.
- Environment: the reference laptop from P-01 (Intel Core i5-8250U, 24 GB, Windows 11 Pro 10.0.26300). Chromium 156.
Times are in milliseconds, given as median / p95.
| Before | After | Change | |
|---|---|---|---|
| Initial JS (gzipped) | 306.7 KB | 185.3 KB | −39.6% |
| Metric | Before | After | Change (median) |
|---|---|---|---|
timeToAppShell, cold |
360.0 / 386.6 | 326.4 / 370.1 | −9.3% |
timeToAppShell, warm |
345.2 / 362.9 | 319.7 / 344.3 | −7.4% |
timeToEngineReady, cold |
1,609.3 / 1,672.6 | 1,600.3 / 2,281.4 | unchanged |
timeToEngineReady, warm |
1,598.2 / 1,697.3 | 1,601.4 / 1,748.0 | unchanged |
- The initial JavaScript budget is now met. The initial script fell from 306.7 KB to 185.3 KB gzipped, 64.7 KB under the 250 KB budget. Almost all of the saving is CodeMirror, which no longer loads before the first paint.
- The app shell paints sooner. The median time to the app shell fell by 9.3% cold and 7.4% warm, and the p95s fell too. Less script to download and parse comes before the first render.
- Engine start-up is unchanged. The medians are within a few milliseconds in both modes, as expected: the engine and its worker were never in the split chunks. The cold p95 on the branch (2,281.4 ms) comes from two slow iterations (2,255 and 2,303 ms) out of ten; the other eight were between 1,575 and 1,680 ms, and the median didn't move.
- The hypothesis held. Splitting out the editor and chart panel brought the bundle under budget and shortened the time to first paint, without slowing anything that was measured.
Trade-offs:
- The editor appears a moment later. On a cold load the editor's chunk is fetched after the first paint, so the editor shows up shortly after the rest of the panel. The fallback holds its space, so the layout doesn't shift.
-
More moving parts. Text sent before the editor mounts has to be queued and applied later, which the eager editor never needed. Tests that need the editor now wait for it (
findSqlEditor()); no assertion was weakened.
Limitations:
- One machine, Chromium only. Ten measured iterations per scenario on the reference laptop.
- Time until the editor is usable wasn't measured. The benchmarks cover the app shell and the engine, not the moment the editor's chunk has loaded and mounted.
Evidence:
- Raw results:
2026-10-26T12-59-19Z-3639160.json(main, before) and2026-10-26T13-00-37Z-e064147.json(branch, after). - To reproduce: run
pnpm benchon each commit. To inspect the chunks, runBLINKQL_ANALYZE=1 pnpm buildand openbench/bundle/stats.html.
Conclusion: Keep. Loading the editor and chart panel on demand cuts the initial JavaScript by 39.6% to 185.3 KB gzipped, which meets the 250 KB budget, and the app shell paints 7 to 9% sooner. Engine start-up is unchanged. The cost is a short delay before the editor appears on a cold load.
⚡ Blinkql: queries in the blink of an eye · MIT licensed · Live app · Issues · Discussions
Project
Engineering
- Tech Stack
- Architecture
- Performance & Benchmarks
- Decision Records (ADRs)
- Privacy & Security
- Browser Support & Limitations
Design
Community