the report
The steps, in order
1 — Retire the sunset surface−1,100 KB first load
The integrated feedback platform had been sunset as a product, but its code — the
pdfmake PDF generator (the largest single block in the baseline map), a duplicate
charting library (apexcharts), report-download plumbing, and eventually the entire
feedback page with its entities and widgets — still shipped to every merchant. All of it
was deleted: four dependencies and roughly 330 files, with old feedback bookmarks redirecting to
the home dashboard. This alone took the bundle from 5,329 to 4,229 KB and, by shrinking the
build’s memory footprint, ended the out-of-memory crashes that had been blocking releases.
2 — Split the two design systems−860 KB first load
The app contains two complete UIs — classic (UX2) and modern (UX3) — and every
merchant was downloading both. The bootstrap was rebuilt: the UX preference is cached
client-side, checked before anything loads, and revalidated in the background; each tree got its
own starter chunk and its own API setup. The bundle became four macro-chunks (second map), and a
merchant’s first load stopped paying for a design system they never see. This split also
fixed a silent monitoring bug: UX2 crash reports had no release version attached, so Rollbar
could never match them to source maps.
3 — Vectorize the “vector” images−904 KB total JS
Several decorative SVGs were photographs base64-embedded inside an SVG wrapper —
including a 424 KB logo and a 758 KB shopping-cart illustration — and because
they sat inside the icon sprite, they shipped as JavaScript to every merchant. Each was re-traced
into a true vector (path outlines plus fitted gradients), typically 3–8 KB: a
>98% reduction per image with no visible difference at any size.
4 — Load pages on demand48 → 933 assets
All ~250 routes across both trees were converted to dynamic imports, so the router fetches a
page’s code the first time a merchant opens it. This is the change that turned the third
map into a constellation: the download cost of a page moved from “everyone, always”
to “only visitors, once per release that touches it.” A stale-chunk guard reloads the
app once, transparently, if a tab left open across a deploy requests a chunk that no longer
exists.
5 — Deduplicate and defer what remained−400 KB total JS
With the map finally legible, the remaining lumps were addressed individually: 219 icons that
existed identically in both trees now ship once; the 550 KB emoji dataset that appeared
three times ships once; chart.js registration moved out of the boot path into the
28 chart components that need it; the confetti/particle engine and the AI-chat panel load only
at their moment of use; the date-picker and multi-select libraries left the boot shell. Total
JavaScript across all chunks fell from 3,400 to 2,999 KB gzip.
6 — Make the build trustworthy600+ warnings → 0
The pipeline itself was part of the problem: builds took 3m 19s, crashed intermittently
on memory, and emitted over 600 warnings — 623 circular-import warnings that could reorder
module execution, plus deprecated style-compiler APIs — which meant real problems scrolled
past unseen. Every circular import was resolved (a codemod fixed the barrel-file pattern causing
them), the style pipeline moved to the modern compiler API with byte-identical output, memory
was measured and right-sized, and source maps are now generated hidden, uploaded to the error
monitor with a release version, and stripped from the deployed artifact. Builds finish in
1m 5s with completely clean output — a future warning will actually mean something.