With serverFunctions.components on, data server functions called during hydration never reach the network (frames intercept waits forever)
维护者通常 1 天内回复
还没有人认领这个 Issue。
评估
- 难度
- 4/5
- 预计耗时
- 3-5 天
- 新手友好度
- 15/100
- Issue 类型
- 缺陷
- 描述清晰度
- 基本清楚
- 活跃度
- 活跃
- 技术栈
- javascript, typescript
- 领域
- frontend, full-stack
调研方向
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…".
由索引模型根据 Issue 内容生成。
描述
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.
- 主要语言
- TypeScript
- 星标
- 36.1k
- 派生
- 1.1k
- 平均合并
- 10 小时 42 分钟
- 30 天内合并 PR
- 361
环境准备
- 没有 Dockerfile 或 Docker Compose 文件
- 有 Pull Request 模板
- 阅读贡献指南
从这里开始
- 先读完整个 Issue,再读项目的贡献指南。
- 在 Issue 下留言说明你要接手 —— 这能避免两个人做同样的事。
- Fork 仓库,在一个分支上完成修改。
- 提交 Pull Request,并在描述里引用这个 Issue 编号。
solidjs/solid 的其他 Issue
-
难度 4/5 3-5 天 新手友好度 20/100
维护者通常 1 天内回复
-
难度 4/5 3-5 天 新手友好度 15/100
维护者通常 1 天内回复
-
bug
难度 4/5 3-5 天 新手友好度 25/100
维护者通常 1 天内回复
-
难度 5/5 一周以上 新手友好度 8/100
维护者通常 1 天内回复
-
bug
难度 5/5 一周以上 新手友好度 15/100
维护者通常 1 天内回复
相似的 Issue
-
难度 2/5 1-3 小时 新手友好度 75/100
apollographql/apollo-client#13493 ·
维护者通常 1 天内回复
-
Custom hosts written as trailing-dot FQDNs (`host.local.`) aren't detected as local backends可能已有人在做 @roboomp 今天认领。 未关闭bug prio:p2 providers triaged
难度 2/5 1-3 小时 新手友好度 82/100
can1357/oh-my-pi#15798 · 3 条评论 ·
维护者通常 1 天内回复
-
难度 2/5 1-3 小时 新手友好度 62/100
code-yeongyu/oh-my-openagent#10172 ·
维护者通常 1 天内回复
-
难度 2/5 1-3 小时 新手友好度 70/100
PDFCraftTool/pdfcraft#189 ·
-
Add the Yahoo chart API duplicate last-day row (yfinance#573) to incidents.md (about 1 hour)可能已有人在做 关联的 PR 仍在进行中或已合并。 未关闭data docs good first issue
难度 1/5 1 小时以内 新手友好度 80/100
pacocartones/market-data-sanity-checker#160 ·
维护者通常 1 天内回复