With serverFunctions.components on, data server functions called during hydration never reach the network (frames intercept waits forever)
メンテナーはふだん 1 日以内に返信
まだ誰も着手していません。
評価
- 難易度
- 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
- 平均マージ
- 11時間 32分
- マージ済み PR(30日)
- 356
環境構築
- Dockerfile・Docker Compose ファイルなし
- プルリクエストのテンプレートあり
- コントリビューションガイドを読む
はじめの一歩
- issue を最後まで読み、次にプロジェクトのコントリビューションガイドを読みます。
- 着手することを issue にコメントします — 二人が同じ作業をするのを防げます。
- リポジトリをフォークし、ブランチを切って変更します。
- issue 番号を参照したプルリクエストを送ります。
solidjs/solid のほかの issue
-
難易度 4/5 3〜5日 初心者へのやさしさ 22/100
メンテナーはふだん 1 日以内に返信
-
難易度 5/5 1週間以上 初心者へのやさしさ 14/100
メンテナーはふだん 1 日以内に返信
-
難易度 4/5 3〜5日 初心者へのやさしさ 35/100
メンテナーはふだん 1 日以内に返信
-
難易度 4/5 3〜5日 初心者へのやさしさ 18/100
メンテナーはふだん 1 日以内に返信
-
難易度 4/5 3〜5日 初心者へのやさしさ 22/100
メンテナーはふだん 1 日以内に返信
似ている issue
-
documentation good first issue
難易度 2/5 半日 初心者へのやさしさ 72/100
sujithputta02/Esapay#13 ·
-
難易度 2/5 1〜3時間 初心者へのやさしさ 65/100
ehmpathy/rhachet-roles-bhuild#468 ·
メンテナーはふだん 1 日以内に返信
-
Share dialog: the address book's contact count reads "1 contacts" (no singular form in any language)対応中かも @chibenwa が今日担当しました。 オープンai-driven-qa bug claude Cosmetic
難易度 2/5 1〜3時間 初心者へのやさしさ 72/100
linagora/twake-contacts-frontend#271 · コメント 1 件 ·
メンテナーはふだん 1 日以内に返信
-
factory-active task-identify-harness-labels-done task-identify-issue-type-done
難易度 1/5 1時間未満 初心者へのやさしさ 70/100
メンテナーはふだん 1 日以内に返信
-
難易度 2/5 1〜3時間 初心者へのやさしさ 72/100
Koenkk/zigbee2mqtt#33402 ·
メンテナーはふだん 1 日以内に返信