mirror of
https://github.com/MBombeck/HealthLog.git
synced 2026-11-15 15:02:04 +00:00
build(bundle): gate every page's first load and the distinct client code
The gate summed every emitted chunk once and watched five pages. The sum counts a module once per chunk group it lands in, so it rose whenever a page got lighter by moving code into on-demand chunks, and it needed a raise in most releases while no reader downloaded more; and a heavy import into a page outside the five went unseen. scripts/check-bundle-budget.mjs now measures: - the first load of every page: rootMainFiles plus the page's client-reference chunks, each file counted once by content hash; - p50, p95 and max of those first loads across pages; - the distinct client code: every chunk evaluated in a node:vm sandbox with a stub TURBOPACK array, each module factory counted once by its module id (not its text: each chunk is minified on its own, so copies of one module differ in mangled names), catalogs excluded, gzipped once. The summed aggregate is still printed but no longer gated. The catalog, per-catalog and one-Recharts checks are unchanged. `--write-baselines` rewrites the per-page baselines, `--dir` measures another build directory, `--json` writes the report. bundle-budget.json is re-based from the v1.44.0 build (local arm64): 110 pages, first load p50 336, p95 437, max 451 KB gz; distinct client code 1904 KB gz in 1224 modules; summed aggregate 3875 KB for comparison. Every page has a baseline with the same 20 KB allowance; caps are p95 447, max 461 and distinct code 1930 KB. A page without a baseline fails until one is written in the same change. Proof: importing zod into the weight insights page measured /insights/weight at 427.8 KB gz, 88.8 KB over its 339 KB baseline, and the gate failed; the old gate passed the same build, because the page was not watched and the summed aggregate did not move (3875 KB). The import was removed again.
This commit is contained in:
1 parent
f64b49cf55
commit
45ea61261e
3 files changed
+386
-143
No files matched your search
+117
-10
@@ -1,14 +1,121 @@
|
||||
{
|
||||
"$comment": "Client-bundle budgets, enforced by scripts/check-bundle-budget.mjs (--check) after `next build` in CI. Values are KB gzip and include every emitted lazy route and locale chunk, while route budgets include the shared rootMainFiles baseline. Re-measured at v1.37.2: / 455, /insights 443, /measurements 441, /insights/mood 453, total 3328, baseline 130, lazy catalogs 849. Every per-route ceiling is unchanged. The /insights overview crept a kilobyte over its 445 ceiling when the ECG teaser began importing its overview cap from the classification module, dragging that module's label map and helpers into the eager page; the cap now lives in its own value-only module, and the Health Score's single provenance entry is split out of the full metric-provenance map, so the overview imports the bare number and citation it renders rather than every metric's label map behind them. Both are back under 445 with room to spare. The 42 KB aggregate rise from 3286 (v1.35.0) is all locale-catalog strings: v1.36 and v1.37 added the encounter, mood-context, mood-prognosis, practitioner, workout-batch and account-sharing surfaces, and their copy lands across the six locale catalogs the whole-build sum counts independently (804 to 849 KB). The non-catalog client chunks are flat against v1.35.0, so nothing a person downloads on a given route grew beyond its own ceiling. The aggregate cap therefore moves from 3310 to 3352 (24 KB headroom, matching the previous margin); per-route ceilings, the static-catalog guard and the one-Recharts-chunk guard remain unchanged. v1.37.4's honest-error-state charge then added recoverable read-failure handling to thirteen surfaces (the shared QueryErrorCard and QueryErrorRow primitives plus an isError branch per surface) and rewrote the MCP scope note and the managed-record error copy across the six locales; the measured total rose to 3404 while every per-route ceiling stayed met (/page 457, /insights 445, /measurements 443, /insights/mood 455). The aggregate cap moves from 3352 to 3428, keeping the same margin; nothing a person downloads on a given route grew beyond its ceiling. v1.37.15's async-truth charge then added the refresh settling state with its two-locale-key copy, the index-outcome plain-words line (seven keys across the six catalogs) and the reindex-count wiring; the measured total rose to 3429 while every per-route ceiling stayed met (/page 456, /insights 445, /measurements 442, /insights/mood 455). The aggregate cap moves from 3428 to 3452, keeping the same margin; nothing a person downloads on a given route grew beyond its ceiling. v1.37.27 found /insights sitting a few hundred bytes under 445 on main and a few hundred over it on the release branch — the page had been at its ceiling for three releases and the release only had to breathe on it. The weight it was carrying was not its own: the authenticated shell imported one destination predicate from the `@/lib/record-settings` barrel, and the barrel also re-exports the managed settings-patch schemas, so Zod, the module registry and three validation modules rode into the eager bundle of every authenticated route for a function that reads a URL slug. The shell imports the `classification` leaf now. Measured across all 585 client-rendered routes: none grew by a byte, 100 fell, by 4.7 KB at the median and 8.1 KB at the most; /insights 444 to 437, /measurements 442 to 435, / 456 to 450, /insights/mood 455 to 450. The whole-build sum moved the other way, 3451 to 3476, and that direction is the metric rather than the change: the aggregate counts each emitted chunk once, so a graph that leaves the chunk group every route shares gets counted again wherever it lands — here inside the deferred settings chunks that actually use it. Bytes on disk rose 25 KB; bytes a reader downloads only ever fell. The aggregate cap moves from 3452 to 3500, the same 24 KB headroom as the four re-measurements before it. Per-route ceilings keep their old values rather than tightening to the new floor: the CI runner measures each route about 1.5 KB heavier than a local arm64 build does, and a ceiling set from a local number would fail on a build that had not regressed. The static-catalog guard and the one-Recharts-chunk guard remain unchanged. Raised to 3700 at v1.37.32 for the seventh interface language (Korean): the lazy message catalogs went 6->7 chunks (1026 KB gz measured), pushing the aggregate to 3631 against the old 3500. The raise is entirely the new catalog; no route budget moved, and the four eager route ceilings are unchanged and still passing. Most of the aggregate is the dynamic locale-switch and fallback path that a first paint never loads (see issue #253), so this ceiling guards bytes almost no visitor requests; 3700 leaves ~69 KB for ordinary drift until that double-count is cleaned up. v1.38.14 re-measures the four eager routes and changes what the number means. The ceilings had been re-stated but never re-based since v1.37.4, so /inLine truncated
|
||||
"routeBaselineKbGz": {
|
||||
"/page": 355,
|
||||
"/insights/page": 323,
|
||||
"/measurements/page": 335,
|
||||
"/insights/mood/page": 334,
|
||||
"/settings/[section]/page": 307
|
||||
},
|
||||
"$comment": "Client-bundle budgets, enforced by scripts/check-bundle-budget.mjs --check after `pnpm build` in CI; the script header describes the method. Numbers are KB gzip. routeBaselineKbGz is the measured first load of every page (the shared rootMainFiles plus the page's client-reference chunks, each file counted once by content hash), written with --write-baselines; a page fails when it is more than routeDriftAllowanceKbGz over its baseline, and a page without a baseline fails until one is written in the same change. firstLoadP95KbGz and firstLoadMaxKbGz cap the distribution across pages. uniqueClientKbGz caps the distinct client code: every module counted once by its module id, the lazy message catalogs excluded. maxCatalogKbGz holds each catalog, maxRechartsChunks the one shared chart chunk. The summed-chunk aggregate the gate used up to v1.44.0 (3875 KB there, capped at 3900) is still printed but no longer gated: it counted a module once per chunk group it landed in, so it rose whenever a page moved code into on-demand chunks and needed a raise in most releases while no reader downloaded more. Re-based at v1.45.0 from the v1.44.0 build, measured on a local arm64 machine: 110 pages, first load p50 336, p95 437, max 451 KB; unique client code 1904 KB in 1224 modules. The five pages watched before keep their numbers within a kilobyte (/ 359, /measurements 339, /insights/mood 337, /insights 323, /settings/[section] 311), and the metric pages that no watched route covered before are gated now too (/insights/weight 339, /insights/pulse 339). Caps: p95 447 and max 461 KB (10 KB over the measurement), unique client code 1930 KB (about 25 KB, roughly two releases of new client code). A raise or a re-base is a reviewed change with the measured numbers and the reason written here; earlier re-bases are in the history of this file.",
|
||||
"routeDriftAllowanceKbGz": 20,
|
||||
"totalClientKbGz": 3900,
|
||||
"firstLoadP95KbGz": 447,
|
||||
"firstLoadMaxKbGz": 461,
|
||||
"uniqueClientKbGz": 1930,
|
||||
"maxRechartsChunks": 1,
|
||||
"maxCatalogKbGz": 210
|
||||
"maxCatalogKbGz": 210,
|
||||
"routeBaselineKbGz": {
|
||||
"/_global-error/page": 133,
|
||||
"/_not-found/page": 282,
|
||||
"/about/page": 282,
|
||||
"/achievements/page": 292,
|
||||
"/admin/[section]/page": 451,
|
||||
"/admin/page": 297,
|
||||
"/auth/claim/page": 298,
|
||||
"/auth/login/page": 290,
|
||||
"/auth/register/page": 288,
|
||||
"/c/[token]/page": 284,
|
||||
"/checkups/page": 365,
|
||||
"/checkups/practitioners/page": 289,
|
||||
"/claim/[token]/page": 282,
|
||||
"/coach/conversations/page": 294,
|
||||
"/coach/page": 355,
|
||||
"/coach/plans/page": 288,
|
||||
"/confirm-access/page": 287,
|
||||
"/custom-metrics/[id]/page": 303,
|
||||
"/custom-metrics/[id]/values/page": 311,
|
||||
"/cycle/page": 412,
|
||||
"/documents/page": 378,
|
||||
"/enroll-mfa/page": 305,
|
||||
"/illness/[id]/page": 447,
|
||||
"/illness/page": 421,
|
||||
"/insights/active-energy/page": 336,
|
||||
"/insights/audio-events/page": 337,
|
||||
"/insights/blood-glucose/page": 340,
|
||||
"/insights/blood-pressure/page": 336,
|
||||
"/insights/bmi/page": 331,
|
||||
"/insights/body-fat/page": 336,
|
||||
"/insights/body-temperature/page": 336,
|
||||
"/insights/body-water/page": 336,
|
||||
"/insights/bone-mass/page": 336,
|
||||
"/insights/breathing-disturbances/page": 337,
|
||||
"/insights/cardio-fitness/page": 336,
|
||||
"/insights/cardio-recovery/page": 337,
|
||||
"/insights/catalog/page": 317,
|
||||
"/insights/daylight/page": 336,
|
||||
"/insights/double-support-time/page": 336,
|
||||
"/insights/ecg/[id]/page": 316,
|
||||
"/insights/ecg/page": 316,
|
||||
"/insights/environmental-audio/page": 337,
|
||||
"/insights/falls/page": 336,
|
||||
"/insights/fat-free-mass/page": 336,
|
||||
"/insights/fat-mass/page": 336,
|
||||
"/insights/flights-climbed/page": 336,
|
||||
"/insights/grip-strength/page": 337,
|
||||
"/insights/headphone-audio/page": 336,
|
||||
"/insights/health-score/page": 315,
|
||||
"/insights/hrv/page": 337,
|
||||
"/insights/lean-body-mass/page": 336,
|
||||
"/insights/medications/page": 338,
|
||||
"/insights/mood/page": 337,
|
||||
"/insights/muscle-mass/page": 337,
|
||||
"/insights/nutrients/page": 319,
|
||||
"/insights/oxygen/page": 337,
|
||||
"/insights/page": 323,
|
||||
"/insights/pain/page": 336,
|
||||
"/insights/pulse-wave-velocity/page": 336,
|
||||
"/insights/pulse/page": 339,
|
||||
"/insights/recovery/page": 330,
|
||||
"/insights/respiratory-rate/page": 336,
|
||||
"/insights/resting-pulse/page": 337,
|
||||
"/insights/scores/[metric]/page": 328,
|
||||
"/insights/six-minute-walk/page": 336,
|
||||
"/insights/skin-temperature/page": 338,
|
||||
"/insights/sleep/page": 337,
|
||||
"/insights/sources/page": 321,
|
||||
"/insights/stair-ascent-speed/page": 336,
|
||||
"/insights/stair-descent-speed/page": 336,
|
||||
"/insights/step-length/page": 336,
|
||||
"/insights/steps/page": 337,
|
||||
"/insights/values/[type]/page": 350,
|
||||
"/insights/vascular-age/page": 337,
|
||||
"/insights/visceral-fat/page": 336,
|
||||
"/insights/waist-to-height/page": 336,
|
||||
"/insights/waist/page": 336,
|
||||
"/insights/walking-asymmetry/page": 336,
|
||||
"/insights/walking-distance/page": 336,
|
||||
"/insights/walking-heart-rate/page": 337,
|
||||
"/insights/walking-speed/page": 336,
|
||||
"/insights/walking-steadiness/page": 336,
|
||||
"/insights/weight/page": 339,
|
||||
"/insights/workouts/[id]/page": 437,
|
||||
"/insights/workouts/page": 437,
|
||||
"/insights/wrist-temperature/page": 336,
|
||||
"/invite/[token]/page": 282,
|
||||
"/labs/[biomarkerId]/page": 327,
|
||||
"/labs/[biomarkerId]/values/page": 335,
|
||||
"/labs/page": 423,
|
||||
"/measurements/page": 339,
|
||||
"/medications/[id]/history/page": 283,
|
||||
"/medications/[id]/page": 402,
|
||||
"/medications/new/page": 282,
|
||||
"/medications/page": 355,
|
||||
"/mental-wellbeing/page": 297,
|
||||
"/mood/page": 438,
|
||||
"/notifications/page": 289,
|
||||
"/onboarding/[step]/page": 445,
|
||||
"/onboarding/handover/page": 295,
|
||||
"/onboarding/page": 286,
|
||||
"/page": 359,
|
||||
"/privacy/page": 282,
|
||||
"/profile/page": 285,
|
||||
"/settings/[section]/page": 311,
|
||||
"/settings/layout/[module]/page": 380,
|
||||
"/settings/modules/[module]/page": 374,
|
||||
"/settings/page": 282,
|
||||
"/timeline/page": 331,
|
||||
"/vaccinations/page": 327
|
||||
}
|
||||
}
|
||||
Reference in new issue
Block a user