The problem with the obvious test
You fix an SSR page-weight regression (a crawler flagged >1 MB of HTML) and want a CI guard so it cannot come back. The obvious assertion is the one the crawler makes:
expect(html.length).toBeLessThan(1_000_000);Against a dev server this is worse than useless. Measured on the same page, same commit:
| environment | HTML bytes |
|---|---|
| prod (before fix) | 1,988,886 |
| prod (after fix) | ~210,000 |
| dev server (after fix) | 2,857,289 |
The fixed page in dev is larger than the broken page in prod. Vite's dev server injects the HMR client, unminified inline module scripts, and /@fs/ import graph preamble; locally that was ~2.6 MB of pure dev overhead. Any threshold that passes in dev is far too loose to catch the real bug, and any threshold tight enough to catch it fails every local run.
Building a production bundle just to run the assertion is the usual escape hatch, and it makes the test slow enough that people stop running it.
What to assert instead
Budget the inlined API-response bytes, not the rendered HTML. In SvelteKit those are the data-sveltekit-fetched script tags; the equivalents are the RSC flight payload in Next.js App Router and __NUXT__ in Nuxt.
These bytes are API responses. The bundler never touches them, so they are identical in dev and prod, which makes a dev-server assertion meaningful and exact:
const blocks = [...html.matchAll(
/<script type="application\/json" data-sveltekit-fetched data-url="([^"]+)"[^>]*>(.*?)<\/script>/gs
)].map((m) => ({ url: m[1], bytes: m[2].length }));
// 1. Named guard: the specific collection endpoint that caused the regression.
expect(blocks.filter((b) => /\/v\/[^/]+\/viewables\b/.test(b.url)).map((b) => b.url)).toEqual([]);
// 2. Backstop: any other bulk fetch added to this route's load chain.
const total = blocks.reduce((s, b) => s + b.bytes, 0);
expect(total, `over budget:\n${blocks.map((b) => `${b.bytes} ${b.url}`).join("\n")}`)
.toBeLessThan(400_000);Two assertions, deliberately: the named one documents the incident and fails with an obvious message; the total is what catches the next variant of the bug. Put the breakdown in the failure message — a bare byte count tells the next person nothing about which fetch grew.
Verify the guard fails on the real bug
A page-weight guard that has never gone red is decoration. Revert the single fixed file out of the previous commit and run it:
git checkout HEAD~1 -- path/to/+layout.ts && npx playwright test -g "bulk collection"
# Error: view page must not inline the /v/{username}/viewables listing
# + "http://localhost:8081/v/heyfinfam/viewables",
git checkout HEAD -- path/to/+layout.tsGotcha while doing this: git stash push -- <path> on an already-committed file is a silent no-op that still prints success, and the following git stash show stash@{0} then errors with "not a valid reference". If you stash to build a before/after, confirm the file actually changed before trusting the measurement — I nearly recorded a "before" number that was really the "after".
Why this class of bug needs a guard at all
It is invisible through every normal channel. It does not break rendering, it produces no error, review sees a one-line load addition, and gzip hides it from wire-size monitoring: the 1.96 MB page compressed to 311 KB. Only a crawler measuring uncompressed HTML notices, months later, as a domain-health score drop.
Applies to
SvelteKit 2 (@sveltejs/kit@2.69.1 verified, Playwright). The dev-overhead inversion applies to any Vite-based dev server; the payload-budget technique applies to any framework that serializes loader data into the document.