the BUNDLED CITY
ALTITUDE 2⅞ — inside the wire: what the bundler kept · one production bundle: 14 package groups in 18 chunks, 126,866 gz, footprint from source kept and height from wire share — apps/sample-app-lit-vanilla · counted at origin/main @ 3f55e419 (2026-10-30)
STRUCTURE SCHEDULE — source bytes the bundler kept · gzipped wire share · modules · note
| # | package group | kept | wire | modules | note |
|---|---|---|---|---|---|
| 1 | @uirouter/core | 174.4 KB | 26.0 KB | 64 | the state machine: transition · url · state services |
| 2 | lit | 33.8 KB | 8.7 KB | 20 | one lit major, no second copy |
| 3 | lit-ui-router | 41.7 KB | 7.9 KB | 18 | the subject — directives and ui-view |
| 4 | router plugins | 20.8 KB | 4.2 KB | 5 | dsr · sticky-states · nav-location |
| 5 | runtime helpers | 5.3 KB | 1.2 KB | 4 | oxc · vite · tslib — the bundler tax |
| 6 | @uirouter/visualizer | 116.8 KB | 24.2 KB | 1 | ships prebundled, opaque |
| 7 | marked | 58.1 KB | 10.9 KB | 1 | one file, whole — lazy chunk |
| 8 | dompurify | 63.9 KB | 12.0 KB | 1 | one file, whole — lazy chunk |
| 9 | @api-viewer | 24.5 KB | 4.6 KB | 12 | docs · tabs · common |
| 10 | lit-dialog | 2.8 KB | 617 b | 1 | the demo dialog, on the shared lit |
| 11 | sample-app-shared | 60.9 KB | 13.0 KB | 41 | the demo the four sample apps share |
| 12 | lodash-es | 63.3 KB | 7.5 KB | 135 | _baseClone graph — isEqual's family |
| 13 | app own src | 11.2 KB | 2.4 KB | 8 | the vanilla shell and its views |
| 14 | sample-app-routes | 2.3 KB | 528 b | 5 | the route table the sample apps and the docs site share |
TOTAL — 14 groups in 18 chunks · 696,117 kept → 390,306 emitted → 126,866 gz · apps/sample-app-lit-vanilla · counted at origin/main @ 3f55e419 (2026-10-30)
GENERAL NOTES
Method: a generateBundle census on a real production vite build of apps/, run inside a materialized, installed archive of the measured ref rather than the working tree — apps/sample-app-lit-vanilla · counted at origin/main @ 3f55e419 (2026-10-30). Every rendered module is attributed to its package by an explicit grouping table whose misses land in a loud other row (this print: none), and every footprint, height, schedule row and door price is read from the checked-in plates at build time — a group the drawing places that the plate does not carry is a build error, not a stale constant. Footprint is post-tree-shake source kept; height is generateBundle: module renderedLength scaled by its chunk gz/rendered ratio — the honest wire share. Beside it, the repo's own codecov bundle-analysis probe (tools/, the <pkg>-<label>-esm series CI uploads) prices each exported entry at the same ref, read here from www/. This closes the survey as a quartet: the source (7), what npm delivers (8), what the wire carries (9) — and here, who occupies those bytes. Sheet 11 is this sheet's split view: the same probe cut by published package, every entry priced alone. Whole bundle: 696,117 kept → 390,306 emitted → 126,866 gz in 18 chunks.
Reconciliation with sheet 9. The two sheets do not meet at an identity, and the reason is a rule: on sheet 9 a chunk counts where it is first claimed, so ui-router-visualizer.esm sits inside app: vanilla rather than beside it. Straight from the two plates: sheet 9's vanilla district is 132,598 gz over 19 files; this bundle is 126,866 gz over 18 chunks; the residual is 5,732 gz over 1 file. That file is the one emitted asset in the app's output that is not a chunk — the api-viewer custom-elements manifest, JSON a module census structurally cannot see, since it walks bundle entries of type chunk. The app's stylesheet is not in the gap: sheet 9's pattern table files .css under site css before the app districts are reached. So 126,866 + 5,732 = 132,598, and the named residual is a manifest, not a rounding error.
The library is a skin over the machine. The biggest building in the bundle is not the router package — it is @uirouter/ at 26.0 KB gz, 21.0% of the wire, 64 modules. lit-ui-router itself is the small accent building: 7.9 KB, 6.4%, 18 modules. The two independent measurements reconcile: the codecov door prices the bare . entry at 9,801 gz with deps external, and this app's census pulls 8,057 of it — the 18% difference is what the app's own imports leave on the shelf.
The chrome outweighs the machine. marked, dompurify and @api-viewer total 27.6 KB gz — more than the routing machine they document — and the prebundled @uirouter/ adds 24.2 KB on its own, opaque to tree-shaking because it arrives already bundled. None of it is on the eager path: the panel renders behind a feature flag and rides a lazy api-docs chunk. This census counts who occupies the bundle, not when they arrive; sheet 9 draws the critical path. One lit major serves all of it — 8.7 KB gz across 20 modules, no second copy riding in with the docs-viewer stack, because a scoped pnpm override (^3.3.3, a floor, not a pin) holds @api-viewer/ and lit-dialog to it.
The app's own district is the small one. lodash-es is 7.5 KB gz from 135 modules and 63.3 KB of kept source — isEqual's _base* family, the largest module count in the bundle and its own chunk, which is what four imports truly cost once tree-shaking has done its work. Beside it, the app's own source is 2.4 KB and sample-app-routes — the route table the sample apps and the docs site import — is 2,346 bytes kept, 528 on the wire, one module: the smallest building on the map.
The runtime tax is near-zero. All bundler machinery — oxc decorator helpers, vite's preload helper and polyfill, a stray tslib — totals 5.3 KB kept, 1.2 KB gz, 0.8% of the kept source, in 4 modules. No duplicated-helper problem.
KEY
| package group — height = gz wire share | |
| lit-ui-router — the subject | |
| ships prebundled — opaque to tree-shaking | |
| district (role in the bundle) |