With serverFunctions.components on, data server functions called during hydration never reach the network (frames intercept waits forever)
I maintainer di solito rispondono entro 1 giorno
Nessuno ha ancora preso questa issue.
Valutazione
- Difficoltà
- 4/5
- Tempo stimato
- 3-5 giorni
- Idoneità per principianti
- 15/100
- Tipo di issue
- Bug
- Chiarezza
- Abbastanza chiara
- Stato di attività
- Attiva
- Stack tecnologico
- javascript, typescript
- Ambito
- frontend, full-stack
Direzione di ricerca
Start in packages/web/frames/src/client.ts, where the intercept passed to createServerComponentHandler (around line 1683) calls boundaryMayArrive() and awaitBoundary(id), then read the arrivals cache. Also read subFetch in packages/solid/src/client/hydration.ts and the tracing check from #4013. Reproduce by loading examples/room /live with components: true. Done means data server functions called during hydration reach the network and the summary leaves "summarizing…".
Scritto dal modello di indicizzazione a partire dal testo della issue.
Descrizione
In an app with serverFunctions: { components: true }, a data server function (one that returns data, not a component) called during hydration never sends its request. The frames client's intercept parks the call waiting for a <solid-frame> boundary that a data function never has, and in two ways that wait never ends.
examples/room's /live page shows it on next (4937f0a):
- Never connects: there are no
/_server/live/*or/_server/data/summaryrequests at all, and no console errors. - UI stuck: the status pills stay at "connecting", presence shows "0 here" and "Not in the room yet", and the summary stays at "summarizing…".
- Writes go one way: a message posted from one tab reaches the server but never shows in another tab.
- Everywhere: it happens in dev over HTTP/1.1, in dev over HTTPS/HTTP/2, and in the production build, while
_$HY.done === true. - Controls: room's
/page, a live server component, works on the same server. The same/livesource served withcomponents: trueremoved connects, with both tabs in presence and posts crossing.examples/boarddoesn't setcomponents: true, which is why it connects on the same build.
This is related to #3819, which uses the same page as its motivating case, but that issue is about the connection opening late. Here it never opens.
Cause
In packages/web/frames/src/client.ts, the intercept passed to createServerComponentHandler (around line 1683) runs for every server-function call, data functions included. While boundaryMayArrive() is true, meaning _$HY.done is unset or a fragment is pending, it treats a function with no boundary element as "a boundary that may still arrive" and returns awaitBoundary(id). That is a promise cached per function id in arrivals, and the call doesn't go to the network. A data function never gets a boundary, so it can only be released by the reveal hook. Two defects keep that release from ever happening.
1. The cached arrival promise can be a MockPromise that never resolves (confirmed)
- The first call happens inside the hydration trace (
subFetchinpackages/solid/src/client/hydration.ts), which swaps the globalPromiseforMockPromise. - So
new Promise(r => (resolve = r))inawaitBoundarycreates a MockPromise andresolvestays undefined. - In the browser, the
arrivalsentries for presence, transcript, roomCard and archive all hadtypeof resolve === "undefined", created exactly whenPromise !== native. - The takeover calls after the root pass hit the same cached dead entry and hang.
- If a reveal ever tries to release them, it throws
TypeError: arrival.resolve is not a function. That throw was reproduced.
This is the same class of bug as #4013 (a lazy() loader promise made under hydration tracing). That fix added a tracing check, and frames doesn't consult it.
2. Waiters registered after the page's last reveal are never released (confirmed)
The summary source hangs even though its arrival was created with a real Promise:
- Waiters are released only from a reveal notification, and only if
hy.done && !hy.fr.pending()holds at that moment. - Timeline: reveals at about 520 ms and 720 ms, then the last one (the 4 s Archive panel) at about 4015 ms, with
donestill unset andpending()false. _$HY.done = trueis set about 5 ms later, from asetTimeoutindrainHydrationCallbacks. So the last reveal kept the waiters, and no reveal comes after it.- Calls made by hydration-end recomputes (summary uses
ssrSource: "client") register in that gap and wait forever. - Firing a synthetic reveal after
done(with the dead MockPromise entries dropped first) immediately sentGET /_server/data/summary, and the summary started streaming.
A fresh call after hydration goes straight to the network, because boundaryMayArrive() is false once done is set. Only calls made in the hydration window are lost, and any components: true app that calls data server functions during hydration should hit this.
Possible fixes (untested)
- Don't defer non-component functions in the intercept: a data function can never have a boundary.
- Don't create or cache arrival promises while hydration tracing is on, as #4013's fix does for lazy().
- Release outstanding waiters at hydration end (
onHydrationEnd) as well as on reveals.
Regression?
Unknown. The intercept, awaitBoundary and boundaryMayArrive code predates the held-swap policy note (#2964) in the comments, and an older build (around 06c7717dd) behaves the same.
- Lingua principale
- TypeScript
- Stelle
- 36.1k
- Fork
- 1.1k
- Merge medio
- 10h 42m
- PR unite (30g)
- 361
Preparare l'ambiente
- Nessun Dockerfile né file Docker Compose
- Ha un modello di pull request
- Leggi la guida per i contributori
Come iniziare
- Leggi tutta la issue e poi la guida ai contributi del progetto.
- Commenta sulla issue per dire che te ne occupi tu — evita che due persone facciano lo stesso lavoro.
- Fai un fork del repository e lavora su un branch.
- Apri una pull request che faccia riferimento al numero della issue.
Altre issue di solidjs/solid
-
Difficoltà 4/5 3-5 giorni Idoneità per principianti 20/100
I maintainer di solito rispondono entro 1 giorno
-
Difficoltà 4/5 3-5 giorni Idoneità per principianti 15/100
I maintainer di solito rispondono entro 1 giorno
-
bug
Difficoltà 4/5 3-5 giorni Idoneità per principianti 25/100
I maintainer di solito rispondono entro 1 giorno
-
Difficoltà 5/5 Più di una settimana Idoneità per principianti 8/100
I maintainer di solito rispondono entro 1 giorno
-
bug
Difficoltà 5/5 Più di una settimana Idoneità per principianti 15/100
solidjs/solid#4023 · 1 commento ·
I maintainer di solito rispondono entro 1 giorno
Tutte le issue di solidjs/solid
Issue simili
-
afk-ok area:data-quality importer size:S
Difficoltà 2/5 1-3 ore Idoneità per principianti 74/100
enorm-labs/event-junkie#3301 ·
I maintainer di solito rispondono entro 1 giorno
-
Difficoltà 2/5 1-3 ore Idoneità per principianti 62/100
one-zero-eight/apply-bot#39 ·
-
Difficoltà 2/5 1-3 ore Idoneità per principianti 72/100
bigbluebutton/bbb-ui-components-react#108 ·
I maintainer di solito rispondono entro 2 giorni
-
area: app type: bug
Difficoltà 2/5 1-3 ore Idoneità per principianti 70/100
ExpidetGames/code-reviewer#308 ·
I maintainer di solito rispondono entro 1 giorno
-
Difficoltà 2/5 1-3 ore Idoneità per principianti 82/100
I maintainer di solito rispondono entro 1 giorno