Skip to content

fix(router): align PPR lane comments, JSDoc and capture warnings with ssr:false - #871

Merged
ivogt merged 1 commit into
mainfrom
docs/ppr-lane-rule-warnings
Sep 23, 2026
Merged

ivogt merged 1 commit into
mainfrom
docs/ppr-lane-rule-warnings

Conversation

@ivogt

@ivogt ivogt commented Sep 23, 2026

Copy link
Copy Markdown
Collaborator

Problem

Since #813/#820, only loader(Def, { ssr: false }) bakes into a PPR shell at capture. Every other loader is live: masked at capture, fresh per request, and it needs loading() or an inline <Suspense> above its reader. The dev-time PPR diagnostics were never updated, so a consumer following them was led in the wrong direction:

  • Bake-cost warning: "for a segment loader, add a loading() boundary to its entry (live lane)". loading() no longer changes the lane, so the loader keeps baking.
  • Identity-guard refusal and the cookies()/headers() capture error: they suggested moving the read into a nested promise. That still trips the guard, because the promise body runs at capture.
  • No-usable-shell, rejected-loader and redirect/notFound refusals: they described lanes by loading().
  • Stale explanations: about 48 comments, JSDoc blocks, skills, docs and site pages restated the old rule. docs/internal/feature-map.md also carried an unresolved merge-conflict block from feat(ppr): capture scheduling telemetry, bake-cost attribution, inert-store guard #803.
  • Test coverage: the /shell-cache/guard e2e fixture registered its cookies()-reading loader without ssr: false. After feat(router)!: loader ssr:false replaces stream:"navigation" #820 that loader is masked at capture, so the test stopped exercising the identity guard. It passed only through the no-boundary MISS.

Before / after

The bake-cost warning (src/rsc/shell-capture.ts):

before: … for a segment loader, add a loading() boundary to its entry (live lane, masked at capture). See the /ppr skill …
after:  … for a loader(Def, { ssr: false }), drop ssr: false to move it to the live lane. Lane rule: only loader(Def, { ssr: false }) executes at capture and bakes its non-promise data; every other loader is live (masked at capture, fresh per request) and needs loading() or an inline <Suspense> above its reader. See the /ppr skill, "The loader lane rule" …

The identity refusal now says: drop ssr: false and read under loading() or an inline <Suspense> (a nested promise does not help: its body still runs at capture); in a handler, read in a live loader and consume it with useLoader.

Changes

  • One source of truth for the rule:
    • The full rule lives in the resolveLoaderData JSDoc (router/segment-resolution/loader-cache.ts) and in the /ppr skill section "The loader lane rule".
    • About 30 other copies are now a one-line pointer: source comments, skills, package docs and site pages.
    • Design docs keep "Superseded" notes rather than rewrites.
  • Shared hint: PPR_LANE_HINT in src/rsc/shell-capture-constants.ts, a leaf module, so server/cookie-store.ts imports it without a cycle.
  • Messages: the lane-related warnings and errors are rewritten to about three sentences plus the hint. Refusal pointers no longer reference a repo-only design-doc path.
  • Tag stores: the tag-invalidation warnings now list VercelCacheStore as tag-capable.
  • JSDoc examples fixed:
    • server errorBoundary receives only { error };
    • the generated routes file has a named NamedRoutes export;
    • rsc-router/* becomes @rangojs/router/*;
    • the Workers entry forwards env/ctx;
    • createLoader takes one type parameter;
    • the not-found fallback text;
    • cloudflare() needs childEnvironments;
    • inline Prerender is unsupported;
    • the order of cache condition/key relative to middleware;
    • scopedReverse types only local names.
  • Docs cleanup: docs/internal/feature-map.md has the feat(ppr): capture scheduling telemetry, bake-cost attribution, inert-store guard #803 conflict block resolved (one PPR bullet and one PPR/SWR: stale shell snapshots are rejected on partial navigation, rerunning baked handlers and handles #773 bullet, facts checked against src).
  • Tests:
    • e2e/semantic-matrix.test.ts: PPR3 comment corrected. No assertion changes.
    • /shell-cache/guard fixture: loader(ShellIdentityLoader, { ssr: false }), so the identity guard fires again. The test still expects MISS, now for the documented reason.
    • src/rsc/__tests__/shell-capture.test.ts: assertions follow the new message text and pin "The loader lane rule".

No routing or behaviour logic changes. The text of seven diagnostics changes.

Test plan

  • oxfmt, oxlint --deny-warnings, check:skills, check:docs-api, check:doc-links, check:skills-catalog, check:e2e-bucketing
  • pnpm run typecheck (not run locally)
  • pnpm run test:unit:all: shell-capture.test.ts message assertions (not run locally)
  • pnpm --filter @rangojs/router exec playwright test semantic-matrix (the diff touches segment-resolution/ comments)
  • e2e shell-cache "bake-lane loader reading cookies(): capture refused, stays MISS", dev and production. This now exercises the guard again.

Notes

  • Merge first. PRs for LoaderOptions, response-route/middleware reverse and debugManifest touch some of the same docs; they will be rebased onto this one.
  • The /shell-cache/guard change affects only the fixture's registration. The worker-side refusal warning stays pinned by the unit tests.

@pkg-pr-new

pkg-pr-new Bot commented Sep 23, 2026 •

Copy link
Copy Markdown

Open in StackBlitz

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

commit: 9126a95

… ssr:false

Only loader(Def, { ssr: false }) bakes at PPR capture since #813/#820. Update the capture diagnostics (bake cost, no usable shell, identity refusal, rejected loader, redirect/notFound refusal) and the cookies()/headers() capture error, which still advised loading() or nested promises. Share one PPR_LANE_HINT. Make resolveLoaderData the canonical statement of the lane rule and point other comments and docs at it. Fix stale JSDoc examples, resolve the #803 conflict leftover in feature-map.md, and register the /shell-cache/guard fixture loader with ssr: false so the identity guard is exercised again.
@ivogt
ivogt force-pushed the docs/ppr-lane-rule-warnings branch from c99fdb3 to 9126a95 Compare September 23, 2026 11:19
@ivogt
ivogt merged commit f29d80a into main Sep 23, 2026
43 checks passed
@ivogt
ivogt deleted the docs/ppr-lane-rule-warnings branch September 23, 2026 11:28
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