Expose per-render failure state for buffered SSR consumers
メンテナーはふだん 1 日以内に返信
まだ誰も着手していません。
評価
- 難易度
- 4/5
- 見積もり時間
- 3〜5日
- 初心者へのやさしさ
- 18/100
- issue の種類
- 機能追加
- 明瞭さ
- おおむね明確
- 活発さ
- 活発
- 技術スタック
- javascript, typescript
- 領域
- web-dev
調査の方向性
Start from renderToStream() and the configureServerErrors onError path that the reproduction exercises, since the requested flag must be set where render containment happens rather than where errors are reported. The reproduction script in the issue is the first thing to run; it shows the current calls and hasFailure output for reused errors and escaping server-function failures. Done means each renderToStream() result exposes a read-only, monotonic failure flag that stays true for all three cases without changing hook invocation counts or sanitization.
索引モデルが issue の本文から書いたものです。
説明
Use case
A buffered SSR consumer needs to know whether its HTML contains a render failure before publishing it as a successful document. Our concrete use case is serving Markdown from the same rendered page HTML, without browser hydration.
Awaiting renderToStream() intentionally resolves with the HTML produced, including a render where a Loading fragment rejected. onCompleteAll also runs for that case. The documented onError hook reports/maps each error object once, so it cannot act as a per-render integrity signal:
- Reusing one Error in two requests only notifies the first request.
- A server-function error first reported as
kind: 'server-function'is not reported again askind: 'render'when it escapes into Loading.
The distinction matters because a server-function failure caught by application code may still produce valid content. Marking every server-function failure would reject those valid renders.
Reproduction
Verified against solid-js and @solidjs/web 2.0.0-rc.15. Run this as an ES module in Node with those packages installed:
import {configureServerErrors,createRequestEvent,renderToStream,ssr,markSafeError} from '@solidjs/web';
import {provideRequestEvent} from '@solidjs/web/storage';
import {configureServerFunctionsServer,registerServerReference,createServerReference} from '@solidjs/web/server-functions/server';
import {createComponent,createMemo,Loading} from 'solid-js';
const calls=[];
configureServerErrors({onError(error,context){calls.push({kind:context.kind,handling:context.handling,url:context.event?.request.url}); if(context.kind==='render'&&context.event) context.event.locals.hasSsrRenderFailure=true; return markSafeError(new Error('Public failure'));}});
configureServerFunctionsServer({wrapInvocation:async run=>{try{return await run()}catch{return (()=>{throw markSafeError(new Error('Public failure'));})()}}});
async function render(id, run){
const event=createRequestEvent(new Request(`https://example.test/${id}`));
const before=calls.length; let didCompleteAll=false;
const html=await provideRequestEvent(event,()=>renderToStream(()=>ssr(['<main>', '</main>'],createComponent(Loading,{fallback:'pending',get children(){const data=createMemo(run);return ssr(['<p>','</p>'],createMemo(()=>data()))}})), {onCompleteAll(){didCompleteAll=true}}));
return {id,didCompleteAll,hasFailure:event.locals.hasSsrRenderFailure??false,hasResolved:html.includes('resolved'),calls:calls.slice(before)};
}
const shared=new Error('PRIVATE_shared');
const results=[];
results.push(await render('reuse-first',async()=>{throw shared}));
results.push(await render('reuse-second',async()=>{throw shared}));
const sf=createServerReference(registerServerReference('probe-failure',async()=>{throw new Error('PRIVATE_sf')}));
results.push(await render('server-function',()=>sf()));
console.log(JSON.stringify(results,null,2));
Observed output:
[
{
"id": "reuse-first",
"didCompleteAll": true,
"hasFailure": true,
"hasResolved": false,
"calls": [
{
"kind": "render",
"handling": "client",
"url": "https://example.test/reuse-first"
}
]
},
{
"id": "reuse-second",
"didCompleteAll": true,
"hasFailure": false,
"hasResolved": false,
"calls": []
},
{
"id": "server-function",
"didCompleteAll": true,
"hasFailure": false,
"hasResolved": false,
"calls": [
{
"kind": "server-function",
"handling": "thrown",
"url": "https://example.test/server-function"
}
]
}
]
All three renders complete with the resolved fragment missing. The second and third renders have no render-hook notification. The existing hook behavior matches its once-per-error-object contract; invoking a mapper again is not the requested solution.
Proposed direction
Expose a read-only, monotonic failure flag on each renderToStream() result. Set it at render containment/failure sites independently of error-reporting deduplication, without retaining or exposing error payloads. Consumers can await the render, check this flag and the request lifecycle, and reject incomplete documents.
A contribution is being prepared against next, with coverage for repeated errors across requests, server-function failures that escape versus those caught by application code, contained fallbacks, serialization, concurrent renders and normal streaming. Existing sanitization and hook invocation counts should remain unchanged.
- 主要言語
- TypeScript
- スター
- 36.1k
- フォーク
- 1.1k
- 平均マージ
- 12時間 10分
- マージ済み PR(30日)
- 338
環境構築
- Dockerfile・Docker Compose ファイルなし
- プルリクエストのテンプレートあり
- コントリビューションガイドを読む
はじめの一歩
- issue を最後まで読み、次にプロジェクトのコントリビューションガイドを読みます。
- 着手することを issue にコメントします — 二人が同じ作業をするのを防げます。
- リポジトリをフォークし、ブランチを切って変更します。
- issue 番号を参照したプルリクエストを送ります。
solidjs/solid のほかの issue
-
`lazy()`: remounting an already-loaded component renders empty (or the Suspense fallback) since 1.9.14対応中かも @itisrmk が 1 日前に担当しました。 オープン
難易度 2/5 1〜3時間 初心者へのやさしさ 62/100
メンテナーはふだん 1 日以内に返信
-
難易度 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 日以内に返信
似ている issue
-
bug priority: P2
難易度 2/5 1〜3時間 初心者へのやさしさ 78/100
メンテナーはふだん 1 日以内に返信
-
wayfinder:task
難易度 2/5 1〜3時間 初心者へのやさしさ 65/100
メンテナーはふだん 1 日以内に返信
-
bug customer-reported data-plane question Service Attention Storage
難易度 2/5 1〜3時間 初心者へのやさしさ 69/100
Azure/azure-rest-api-specs#47397 · コメント 2 件 ·
メンテナーはふだん 1 日以内に返信
-
Claude thinking budget can shrink capped Haiku responses to 2,048 tokens対応中かも @DavyMassoneto が今日担当しました。 オープン
難易度 2/5 1〜3時間 初心者へのやさしさ 78/100
diegosouzapw/OmniRoute#17109 ·
メンテナーはふだん 1 日以内に返信
-
難易度 2/5 1〜3時間 初心者へのやさしさ 76/100
paperclipai/paperclip#16785 ·
メンテナーはふだん 1 日以内に返信