Skip to content

test: bundle-hygiene guards — Text-module channel, multi-router chunks, prerender/shell/static discipline - #754

Merged
ivogt merged 1 commit into
mainfrom
chore/bundle-hygiene-guards
Jul 10, 2026
Merged

ivogt merged 1 commit into
mainfrom
chore/bundle-hygiene-guards

Conversation

@ivogt

@ivogt ivogt commented Jul 10, 2026

Copy link
Copy Markdown
Collaborator

Problem statement

The post-#751 route-data audit found that three bundle-hygiene invariants hold in every current build but have zero automated enforcement — each is a regression class that would keep every functional test green while silently costing cold-start time or duplicating route data:

  1. The Cloudflare Text-module channel was unguarded end-to-end. It carries the largest generated artifact (up to multi-MB tries) on the one preset where cold isolates make the cost real, and the refactor(vite): lazy per-router chunk carries only derived match data + rule #1 bundle guard #751 guard cannot see it (no inline JSON.parse literal to detect). A regression that staged duplicate .txt files, re-inlined the trie as a literal alongside the Text module (paying the compile cost the channel exists to remove, twice the bytes), or leaked the payload into the client would pass CI.
  2. Multi-router chunk independence had no build guard. The single-router guard asserts "exactly one data chunk" — an assertion that is wrong for N routers. Nothing inspected a multi-router dist, and multi-router is where the refactor(vite): lazy per-router chunk carries only derived match data + rule #1 bundle guard #751 disease compounds by router count.
  3. Prerender/shell/static artifacts had no discipline guard. __pr-*/__ps-*/__st-* payload chunks (204 KB of baked Flight in test-app) are lazy, RSC-only read-through data per the prerender design; __static-manifest.js is the single eagerly-imported generated artifact (its global must exist before static-store.ts evaluates — workerd ALS constraint) and must stay a thunk-only lookup table. All unenforced.

No runtime or consumer-visible changes — this PR is guards only.

What each guard pins

Guard Location Asserts
Text-module hygiene tests/cloudflare-basic/e2e/manifest-text-module.test.ts (new test in the existing production-only suite, which already builds with RANGO_MANIFEST_TEXT=1) exactly one staged manifest-*.txt (single-router app); no rsc chunk carries a ≥4 KB JSON.parse literal (dual-channel regression); neither the .txt name nor its payload bytes reach the client bundle
Multi-router independence examples/cloudflare-multi-router/e2e/bundle-guard.test.ts (new) parses the registerRouterManifestLoader("<id>", () => import("<chunk>")) wiring out of the built RSC entry — the exact routerId→chunk mapping the runtime uses, no size heuristics — then asserts 4 loaders, unique ids, unique chunk files, pairwise-distinct content, dynamic-import-only references, clean client bundle
Prerender/shell/static discipline packages/rangojs-router/e2e/build-test-app.setup.ts (extends the #751 guard) __pr-*/__ps-*/__st-* exist in RSC output only, never client/ssr, never statically imported (their manifests too); __static-manifest.js exists, is eagerly imported by the entry (load-order requirement pinned in both directions), carries no payload markers ("segments"/"encoded"/"handles"), and stays under a 32 KB ceiling that doubles as the audit's O(#Static handlers) eager-growth tripwire

Code-change summary

  • build-test-app.setup.ts — guards refactored to a single-pass shape: readJsFiles() reads each RSC chunk once and every guard filters over the list (the per-basename form re-read the same 73 files ~3,300 times; measured noise in time, but the single pass is simpler); staticImportRefs(files, base) extracted as the shared forbidden-shape matcher.
  • manifest-text-module.test.ts — one new test plus a local walkFiles helper; existing tests untouched.
  • bundle-guard.test.ts — new file; production-only describe (build-artifact guard, mirrors the manifest-text-module precedent; dev registers no loaders so there is no dev artifact to inspect). Router count 4 is hardcoded with an update-me comment.
  • The dir-walk/regex machinery is deliberately per-file: @shared/e2e is wired into only two of the three apps, and coupling an example app to the shared test package for a 12-line walker isn't worth it (reviewed and rejected in the simplify pass).

Test plan

  • All three guards green against real builds: build-test-app setup (fresh test-app build), manifest-text-module --project=production (3 passed, RANGO_MANIFEST_TEXT=1 build), bundle-guard (multi-router build fixture)
  • Detectors red-proven against planted regressions: payload chunk copied into dist/ssr → caught; payload marker in __static-manifest.js → caught; planted ≥4 KB inline JSON.parse literal in cloudflare-basic rsc → caught; duplicated chunk content → caught (plus the static-import matcher's red-proof from refactor(vite): lazy per-router chunk carries only derived match data + rule #1 bundle guard #751 carries over verbatim)
  • pnpm run typecheck, pnpm run test:unit:all, pnpm run lint, pnpm run format, pnpm check:e2e-bucketing, pnpm check:e2e-parity
  • Production-only describes clear the bucketing/parity checks (build-artifact guards have no dev counterpart by nature — same category as the pre-existing manifest-text-module suite)

Notes

…nks, prerender/shell/static discipline

Closes the guard gaps the route-data audit found. Everything asserted here
is currently true in real builds but had no automated enforcement:

- cloudflare-basic manifest-text-module.test.ts: the workerd Text-module
  channel (the largest generated artifact, on the preset where cold-start
  matters most) now pins exactly one staged .txt per router, no dual
  channel (route data must not ALSO ship as an inline JSON.parse literal),
  and no leak of the module or its payload bytes into the client bundle.
- examples/cloudflare-multi-router e2e/bundle-guard.test.ts (new): parses
  the registerRouterManifestLoader wiring out of the built RSC entry (the
  exact routerId -> chunk mapping the runtime uses) and asserts one lazy
  chunk per router, pairwise-distinct content, dynamic-import-only
  references, and a clean client bundle. Multi-router is where the #751
  regression class compounds and nothing inspected its dist before.
- build-test-app.setup.ts: prerender/shell/static artifact discipline —
  __pr-*/__ps-*/__st-* payload chunks are RSC-only and never statically
  imported; __static-manifest.js (the one eagerly-imported generated
  artifact, required before static-store.ts evaluates) stays a thunk-only
  lookup table with a size tripwire for O(#Static handlers) eager growth.

All detectors red-proven against planted regressions (payload copied into
ssr, payload marker in the static manifest, planted inline dual-channel
literal, duplicated chunk content). Guards are production-only by nature
(build artifacts; dev has no dist), following the manifest-text-module
precedent.
@pkg-pr-new

pkg-pr-new Bot commented Jul 10, 2026

Copy link
Copy Markdown

Open in StackBlitz

npm i https://pkg.pr.new/@rangojs/router@754

commit: 76fbe14

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant