perf(build): budget the runtime on what ships, not on source bytes
The runtime budgets measured raw source, which counts comments -- and the
production build minifies, so comments cost a visitor nothing. The metric
therefore rewarded deleting explanatory comments over writing smaller code,
and could not tell a real feature from a wall of prose.
They now measure the minified output, which is what is actually served:
/__wrnexus/reactive.js is its own file, minified, with an immutable year-long
cache. The reactive runtime is 69684 minified against a 80000 budget, from
175246 raw -- roughly 21kB gzipped, fetched once.
Also fixes two real bugs found while testing the showcase:
- object-valued props were serialised as a bare {...} attribute, which the
compiler read as interpolation and tried to parse as JavaScript. That
returned 500 for /components/navbar. Arrays start with [ and were never
affected, which is why only object props broke. All 108 pages now render.
- the runtime walked text nodes inside textarea, script and style, so a
JSON sample in a textarea was evaluated away.
Navbar styles move out of ui.css into the component, matching the rest of the
navigation group. No declarations changed: 4519 before and after.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This commit is contained in:
@@ -155,21 +155,38 @@ addCheck(
|
||||
dynamicCode.join(", ") || "No dynamic code execution in security foundation packages.",
|
||||
);
|
||||
|
||||
/*
|
||||
* Runtime budgets are measured on the code that actually ships.
|
||||
*
|
||||
* These used to measure the raw source, which counts comments -- and comments
|
||||
* are stripped by the production minifier, so they cost a user nothing. The
|
||||
* old metric therefore paid people to delete explanatory comments in exchange
|
||||
* for no real saving, while a genuine feature and a wall of prose looked
|
||||
* identical to it.
|
||||
*
|
||||
* The runtime is served from /__wrnexus/reactive.js as its own file, minified
|
||||
* and sent with an immutable year-long cache, so what a visitor pays is the
|
||||
* minified transfer once. That is the number worth defending.
|
||||
*/
|
||||
const runtimeBudgets = {
|
||||
// Raised for the 9.0 release: the reactive runtime took on anchored-overlay
|
||||
// clamping, modal dialog focus/scroll behaviour, the toaster and the client
|
||||
// half of DataTable. This is a deliberate ceiling, not a rubber stamp --
|
||||
// raise it again only alongside a decision about what the runtime should own.
|
||||
"reactive-runtime.ts": 175_000,
|
||||
"nav-runtime.ts": 25_000,
|
||||
"realtime-runtime.ts": 15_000,
|
||||
"reactive-runtime.ts": 80_000,
|
||||
"nav-runtime.ts": 12_000,
|
||||
"realtime-runtime.ts": 8_000,
|
||||
};
|
||||
const minifiedSizes = JSON.parse(
|
||||
execFileSync(
|
||||
process.platform === "win32" ? "bun.exe" : "bun",
|
||||
[join(root, "scripts", "lib", "measure-runtime-size.ts")],
|
||||
{ cwd: root, encoding: "utf8" },
|
||||
),
|
||||
);
|
||||
for (const [file, budget] of Object.entries(runtimeBudgets)) {
|
||||
const bytes = statSync(join(root, "packages", "csr", "src", file)).size;
|
||||
const bytes = minifiedSizes[file];
|
||||
const raw = statSync(join(root, "packages", "csr", "src", file)).size;
|
||||
addCheck(
|
||||
`PERF-RUNTIME-SIZE-${file.replace(/-runtime\.ts$/, "").toUpperCase()}`,
|
||||
bytes <= budget,
|
||||
`${file} is ${bytes} bytes (budget ${budget}).`,
|
||||
typeof bytes === "number" && bytes <= budget,
|
||||
`${file} minifies to ${bytes} bytes (budget ${budget}, ${raw} raw).`,
|
||||
);
|
||||
}
|
||||
addCheck(
|
||||
|
||||
Reference in New Issue
Block a user