Repository navigation
Conversation
@qwik.dev/core
@qwik.dev/router
@qwik.dev/utils
eslint-plugin-qwik
create-qwik
@qwik.dev/optimizer
@qwik.dev/devtools
@qwik.dev/mcp
commit: |
🦋 Changeset detectedLatest commit: f560272 The changes in this PR will be included in the next version bump. This PR includes changesets to release 8 packages
Not sure what this means? Click here to learn what changesets are. Click here if you're a maintainer who wants to add another changeset to this PR |
|
hey the #9170 fixes part of this PR, so you need to make a new changes on top of them. I will merge my changes asap |
5569595 to
4b011dd
Compare
| // The qO() swap reveals the content, so the client must resume in the content state. | ||
| function resumeInContentState(state: Signal<PendingState>): void { | ||
| state.untrackedValue = 'content'; | ||
| } |
There was a problem hiding this comment.
this looks like a workaround, let me think why the state is incorrect
|
So basically the problem is we dont change from fallback to content on client. Your fix is doing a little workaround and set the state 'content' on server, which is incorrect for the flow. It should be changed on the client after swap. I dont have ready solution here, but maybe you can find something |
4b011dd to
95ac0f4
Compare
|
I just gave it your comment and asked it to investigate and it came up with something else: Reworked: the server now leaves the state alone and serializes 'fallback' as before. The client moves it to 'content' once it sees the swap: on resume for boundaries qO() already swapped (the usual case, since qO() runs before the container exists), and from qProcessOOOS for swaps that land after resume. The state is found through the content host's vnode (parent is Pending, state is its first hook), and Catch's late-fallback q:rp hosts are skipped. Happy to change how the boundary-to-state link is found if you'd prefer something else. |
Varixo
left a comment
There was a problem hiding this comment.
The new solution looks weird. Imo its still wrong in the flow. It should be somewhere connected to the real content swap, not treat it as done on resume
| // Pending's `state` signal is the first hook it registers. | ||
| const PENDING_STATE_SEQ_INDEX = 0; |
There was a problem hiding this comment.
it is very dangerous to do that, we need to remember about it and update if anything related changes
|
I guess I don't know enough about the core part of qwik so won't be able to deliver this outside of Claude. Hopefully the reproduction and tests are helpful if someone else could look into it |
…er out-of-order streaming The server serializes the boundary in its 'fallback' state, and qO() only swaps the DOM, so the resumed state stayed 'fallback'. Any later Pending re-render recomputed its styles from it and showed the fallback again. The client now moves the state to 'content' once the swap is seen: on resume for boundaries qO() already swapped, and from qProcessOOOS for swaps that land after resume. Fixes QwikDev#9166 Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…tent Locating a Pending host and reading its render function and hook state while the container state is still being processed caches those props from unfinished state. On a larger page that left a component host whose render function was not a QRL, and every render then threw componentQRL.resolve is not a function in a loop. Mark the swapped content once the container data is ready, both at resume and for segments streamed in later. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
95ac0f4 to
f560272
Compare
|
after your other fix, Claude had to rework it's solution which I've just pushed. It's probably still not pretty but I pushed it anyway as it works for me locally and passes the tests |
|
Closing in favour of #9280 |
Fixes #9166
Problem
With out-of-order streaming (the default for
<Pending>), the server sets the boundary'sstatesignal to'fallback'so the shell renders the fallback. That value is serialized into the root state, but on the clientqO()only swaps the DOM, so the resumedstatestays'fallback'after the content is shown.Any later re-render of
Pendingrebuilds its style signals from that stale state and the fallback reappears. In the issue, the owner's re-render passes a freshfallback$QRL, which the diff treats as a changed prop and so re-rendersPending.Fix
The client moves the boundary's
stateto'content'once it sees the swap. The server still serializes'fallback', which is true for the shell.qO()runs before the container exists): on resume, after segment state is processed, each[q:rp]content host that no longer holds its placeholder template has its Pending state set to'content'.qProcessOOOSqueues the same step after that segment's state patches.The state is found through the content host's vnode: its parent is the Pending component, and
stateis its first hook. Catch's late-fallbackq:rphosts are skipped. OnlyuntrackedValuechanges, becauseqO()has already done the DOM work.Tests
pending.spec.tsx: the issue's scenario, the delayed-fallback variant, and a swap that lands after the container resumed; each fails without its part of the fixpending.e2e.ts: owner re-render fixture across SSR / CSR / pure CSRNot in this PR
Components receiving an equivalent
$callback prop re-render whenever their owner re-renders after resume, because the deserialized QRL and the fresh one compare unequal. That's a broader diff change and is left for a separate issue.🤖 Generated with Claude Code