[v2] Suspense-deferral-through-component: non-EB test + extract to build/v2 + deeper cursor-boundary propagation fix
Nobody has claimed this yet.
- Dominant language
- TypeScript
- Stars
- 22.1k
- Forks
- 1.4k
- Avg merge
- 1d 10h
- Merged PRs (30d)
- 52
Description
Context
The addCursorBoundary walk-up in packages/qwik/src/core/use/use-cursor-boundary.ts:38-52 (fix 50c9666e2, landed on the ErrorBoundary PR #8745 branch) makes a suspending child register against the nearest cursor boundary by walking slotParent || parent. It fixes a real bug — a <Suspense> whose deferred child sits behind an intervening stateful component (e.g. an <ErrorBoundary>, which adds dirty component frames) did not show the Suspense fallback on client nav and instead blocked. The fix is Suspense-generic, but it currently only has ErrorBoundary-shaped coverage.
Three related follow-ups:
1. Add a non-EB walk-up test
suspense.e2e.ts / suspense.spec.tsx have no intervening-component client-deferral case (verified untouched vs base). Add a plain-wrapper test: a non-EB stateful component (e.g. useStore + useContextProvider) projecting a suspending child, asserting the Suspense fallback shows during client navigation. The user-facing behavior is already proven by the EB suites; this covers the generic path.
2. Extract the fix to build/v2
It's EB-independent and self-contained (one file + .changeset/suspense-deferral-through-component.md), so it fits the copy-not-move extraction pattern used for #8790 / #8791 / #8772. Blocked on (1) — a standalone PR needs the non-EB test.
3. Deeper follow-up: repair downward cursor-boundary propagation
The registration-site walk is a bounded mitigation on the rare blocking-promise path (sole caller: cursor-walker.ts:206, inside the isPromise(result) branch — not the hot dirty-mark path). The cleaner fix is to repair the downward NEAREST_CURSOR_BOUNDARY inheritance itself, so projected children of a dirty intervening component inherit the boundary — likely expectSlot (vnode-diff.ts ~735, which overwrites the slot boundary to null instead of inheriting the parent's) and/or setNearestCursorBoundary propagation (vnode-dirty.ts). That path runs on every dirty-mark, so it needs benchmarking + the full suspense suite before it can replace the registration-site walk.
None of this blocks #8745 (the shipped behavior is proven by the EB suites).
Contributor guide
First steps
- Read the whole issue, then the project's contributing guide.
- Comment on the issue to say you are picking it up — it saves two people doing the same work.
- Fork the repository and make your change on a branch.
- Open a pull request that references the issue number.
Research direction
Start with packages/qwik/src/core/use/use-cursor-boundary.ts:38-52 and the existing suspense.e2e.ts and suspense.spec.tsx suites; run the relevant Suspense tests to understand the ErrorBoundary coverage. Add the non-ErrorBoundary client-deferral case, then follow the copy pattern for #8790, #8791, and #8772 to extract the fix to build/v2 with .changeset/suspense-deferral-through-component.md. If pursuing the deeper follow-up, inspect cursor-walker.ts:206, vnode-diff.ts around expectSlot, and vnode-dirty.ts, then benchmark and run the full Suspense suite.
Written by the indexing model from the issue text.
Assessment
- Tech stack
- typescript
- Domain
- build-system, frontend, testing
- Issue type
- Bug
- Difficulty
- 4/5
- Estimated time
- 3-5 days
- Activity status
- Quiet
- Clarity
- Mostly clear
- Newbie friendliness
- 35/100