From 531b335b667074a782468cb623d6c69674f02a0f Mon Sep 17 00:00:00 2001 From: Romuald Brillout Date: Tue, 12 May 2026 11:36:49 +0200 Subject: [PATCH 1/9] wip --- packages/vike-react/tsconfig.json | 1 + 1 file changed, 1 insertion(+) diff --git a/packages/vike-react/tsconfig.json b/packages/vike-react/tsconfig.json index 008abe91..21e86607 100644 --- a/packages/vike-react/tsconfig.json +++ b/packages/vike-react/tsconfig.json @@ -10,6 +10,7 @@ "noUncheckedIndexedAccess": true, "noUnusedLocals": true, "noUnusedParameters": true, + "exactOptionalPropertyTypes": true, // Resolution "esModuleInterop": true, "moduleResolution": "Node16", From 8ca54a2f63e7bffee0d97517a000645412627198 Mon Sep 17 00:00:00 2001 From: Romuald Brillout Date: Tue, 12 May 2026 11:42:04 +0200 Subject: [PATCH 2/9] wip --- .../src/integration/onRenderClient.tsx | 4 +- .../src/integration/onRenderHtml.tsx | 40 ++++++++++++------- 2 files changed, 27 insertions(+), 17 deletions(-) diff --git a/packages/vike-react/src/integration/onRenderClient.tsx b/packages/vike-react/src/integration/onRenderClient.tsx index f58d17c7..53fe8a44 100644 --- a/packages/vike-react/src/integration/onRenderClient.tsx +++ b/packages/vike-react/src/integration/onRenderClient.tsx @@ -105,8 +105,8 @@ type OnUncaughtErrorArgs = Parameters default +stream.enable is true // +stream.require is false => default +stream.enable is false streamSetting.enable === false - ? true + ? { disable: true } : /* Don't override disabling when bot is detected. false, */ - undefined, - ...renderToStreamOptions, - }) + {} + ), + } + const pageHtmlStream = await renderToStream(pageContext.page, renderOptions) pageContext.pageHtmlStream = pageHtmlStream } } From df47f2cdad89e0f1c2dc92ac718cd9e59ffa49eb Mon Sep 17 00:00:00 2001 From: Romuald Brillout Date: Fri, 15 May 2026 15:17:33 +0200 Subject: [PATCH 3/9] [AI] refactor renderToStream options for readability --- .../src/integration/onRenderHtml.tsx | 47 ++++++------------- 1 file changed, 15 insertions(+), 32 deletions(-) diff --git a/packages/vike-react/src/integration/onRenderHtml.tsx b/packages/vike-react/src/integration/onRenderHtml.tsx index a58e7608..cdd8b37f 100644 --- a/packages/vike-react/src/integration/onRenderHtml.tsx +++ b/packages/vike-react/src/integration/onRenderHtml.tsx @@ -80,38 +80,21 @@ async function renderPageToHtml(pageContext: PageContextServer) { const pageHtmlString = renderToString(pageContext.page, renderToStringOptions) pageContext.pageHtmlString = pageHtmlString } else { - const renderOptions: RenderToStreamOptions = { - ...renderToStreamOptions, - ...(!streamSetting.type - ? {} - : { - webStream: streamSetting.type === 'web', - }), - ...(( - pageContext.headers?.['user-agent'] || - // TO-DO/eventually: remove old way of acccessing the User Agent header. - // @ts-ignore - pageContext.userAgent - ) - ? { - userAgent: - pageContext.headers?.['user-agent'] || - // TO-DO/eventually: remove old way of acccessing the User Agent header. - // @ts-ignore - pageContext.userAgent, - } - : {}), - ...( - // +stream.require is true => default +stream.enable is true - // +stream.require is false => default +stream.enable is false - streamSetting.enable === false - ? { disable: true } - : /* Don't override disabling when bot is detected. - false, - */ - {} - ), - } + const userAgent = + pageContext.headers?.['user-agent'] || + // TO-DO/eventually: remove old way of acccessing the User Agent header. + // @ts-ignore + pageContext.userAgent + // Properties are set conditionally (instead of being assigned `undefined`) to satisfy `exactOptionalPropertyTypes`. + const renderOptions: RenderToStreamOptions = {} + // When streamSetting.type is null: let react-streaming decide the stream type + if (streamSetting.type) renderOptions.webStream = streamSetting.type === 'web' + if (userAgent) renderOptions.userAgent = userAgent + // +stream.require is true => default +stream.enable is true + // +stream.require is false => default +stream.enable is false + // Don't override disabling when a bot is detected. + if (streamSetting.enable === false) renderOptions.disable = true + Object.assign(renderOptions, renderToStreamOptions) const pageHtmlStream = await renderToStream(pageContext.page, renderOptions) pageContext.pageHtmlStream = pageHtmlStream } From a41208eee82eb08a413210a039215bfb5937cfc1 Mon Sep 17 00:00:00 2001 From: Romuald Brillout Date: Fri, 15 May 2026 15:34:21 +0200 Subject: [PATCH 4/9] minor refactor --- .../vike-react/src/integration/onRenderClient.tsx | 2 +- packages/vike-react/src/integration/onRenderHtml.tsx | 11 +++++------ 2 files changed, 6 insertions(+), 7 deletions(-) diff --git a/packages/vike-react/src/integration/onRenderClient.tsx b/packages/vike-react/src/integration/onRenderClient.tsx index 53fe8a44..55a81137 100644 --- a/packages/vike-react/src/integration/onRenderClient.tsx +++ b/packages/vike-react/src/integration/onRenderClient.tsx @@ -102,10 +102,10 @@ function onUncaughtErrorGlobal( } type OnUncaughtError = RootOptions['onUncaughtError'] type OnUncaughtErrorArgs = Parameters> +type OnUncaughtErrorInfo = OnUncaughtErrorArgs[1] // Inject componentStack to the error's stack trace // - Server counterpart: https://github.com/brillout/react-streaming/blob/e0a6210957e65dad2c92877ad075ebac4713d8fa/src/server/renderToStream/common.ts#L93 -type OnUncaughtErrorInfo = OnUncaughtErrorArgs[1] function getErrorWithComponentStack(errorOriginal: unknown, errorInfo?: OnUncaughtErrorInfo) { if (!errorInfo?.componentStack || !isObject(errorOriginal)) return errorOriginal const errorStackLines = String(errorOriginal.stack).split('\n') diff --git a/packages/vike-react/src/integration/onRenderHtml.tsx b/packages/vike-react/src/integration/onRenderHtml.tsx index cdd8b37f..39890113 100644 --- a/packages/vike-react/src/integration/onRenderHtml.tsx +++ b/packages/vike-react/src/integration/onRenderHtml.tsx @@ -86,16 +86,15 @@ async function renderPageToHtml(pageContext: PageContextServer) { // @ts-ignore pageContext.userAgent // Properties are set conditionally (instead of being assigned `undefined`) to satisfy `exactOptionalPropertyTypes`. - const renderOptions: RenderToStreamOptions = {} + const options: RenderToStreamOptions = {} // When streamSetting.type is null: let react-streaming decide the stream type - if (streamSetting.type) renderOptions.webStream = streamSetting.type === 'web' - if (userAgent) renderOptions.userAgent = userAgent + if (streamSetting.type) options.webStream = streamSetting.type === 'web' + if (userAgent) options.userAgent = userAgent // +stream.require is true => default +stream.enable is true // +stream.require is false => default +stream.enable is false // Don't override disabling when a bot is detected. - if (streamSetting.enable === false) renderOptions.disable = true - Object.assign(renderOptions, renderToStreamOptions) - const pageHtmlStream = await renderToStream(pageContext.page, renderOptions) + if (streamSetting.enable === false) options.disable = true + const pageHtmlStream = await renderToStream(pageContext.page, { ...options, ...renderToStreamOptions }) pageContext.pageHtmlStream = pageHtmlStream } } From 2446f197a3514fcee661e68764552e184111379e Mon Sep 17 00:00:00 2001 From: Romuald Brillout Date: Fri, 15 May 2026 18:16:09 +0200 Subject: [PATCH 5/9] minor refactor --- packages/vike-react/src/integration/onRenderHtml.tsx | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/packages/vike-react/src/integration/onRenderHtml.tsx b/packages/vike-react/src/integration/onRenderHtml.tsx index 39890113..5b29ce81 100644 --- a/packages/vike-react/src/integration/onRenderHtml.tsx +++ b/packages/vike-react/src/integration/onRenderHtml.tsx @@ -80,15 +80,15 @@ async function renderPageToHtml(pageContext: PageContextServer) { const pageHtmlString = renderToString(pageContext.page, renderToStringOptions) pageContext.pageHtmlString = pageHtmlString } else { + // Properties are set conditionally (instead of being assigned `undefined`) to satisfy `exactOptionalPropertyTypes`. + const options: RenderToStreamOptions = {} + // When streamSetting.type is null: let react-streaming decide the stream type + if (streamSetting.type) options.webStream = streamSetting.type === 'web' const userAgent = pageContext.headers?.['user-agent'] || // TO-DO/eventually: remove old way of acccessing the User Agent header. // @ts-ignore pageContext.userAgent - // Properties are set conditionally (instead of being assigned `undefined`) to satisfy `exactOptionalPropertyTypes`. - const options: RenderToStreamOptions = {} - // When streamSetting.type is null: let react-streaming decide the stream type - if (streamSetting.type) options.webStream = streamSetting.type === 'web' if (userAgent) options.userAgent = userAgent // +stream.require is true => default +stream.enable is true // +stream.require is false => default +stream.enable is false From 9ca94c518df27a277767adceb511855eac77fcc0 Mon Sep 17 00:00:00 2001 From: Romuald Brillout Date: Fri, 15 May 2026 18:16:44 +0200 Subject: [PATCH 6/9] add TODO/ai --- packages/vike-react/src/integration/onRenderHtml.tsx | 1 + 1 file changed, 1 insertion(+) diff --git a/packages/vike-react/src/integration/onRenderHtml.tsx b/packages/vike-react/src/integration/onRenderHtml.tsx index 5b29ce81..f2d9b99f 100644 --- a/packages/vike-react/src/integration/onRenderHtml.tsx +++ b/packages/vike-react/src/integration/onRenderHtml.tsx @@ -80,6 +80,7 @@ async function renderPageToHtml(pageContext: PageContextServer) { const pageHtmlString = renderToString(pageContext.page, renderToStringOptions) pageContext.pageHtmlString = pageHtmlString } else { + // TODO/ai move code in new function getRenderToStreamOptions() // Properties are set conditionally (instead of being assigned `undefined`) to satisfy `exactOptionalPropertyTypes`. const options: RenderToStreamOptions = {} // When streamSetting.type is null: let react-streaming decide the stream type From a3a5a83dacb911ed863779381e6e29bb090d9cb7 Mon Sep 17 00:00:00 2001 From: Romuald Brillout Date: Fri, 15 May 2026 18:25:46 +0200 Subject: [PATCH 7/9] ai --- .../src/integration/onRenderHtml.tsx | 41 +++++++++++-------- 1 file changed, 25 insertions(+), 16 deletions(-) diff --git a/packages/vike-react/src/integration/onRenderHtml.tsx b/packages/vike-react/src/integration/onRenderHtml.tsx index f2d9b99f..736e473e 100644 --- a/packages/vike-react/src/integration/onRenderHtml.tsx +++ b/packages/vike-react/src/integration/onRenderHtml.tsx @@ -80,22 +80,10 @@ async function renderPageToHtml(pageContext: PageContextServer) { const pageHtmlString = renderToString(pageContext.page, renderToStringOptions) pageContext.pageHtmlString = pageHtmlString } else { - // TODO/ai move code in new function getRenderToStreamOptions() - // Properties are set conditionally (instead of being assigned `undefined`) to satisfy `exactOptionalPropertyTypes`. - const options: RenderToStreamOptions = {} - // When streamSetting.type is null: let react-streaming decide the stream type - if (streamSetting.type) options.webStream = streamSetting.type === 'web' - const userAgent = - pageContext.headers?.['user-agent'] || - // TO-DO/eventually: remove old way of acccessing the User Agent header. - // @ts-ignore - pageContext.userAgent - if (userAgent) options.userAgent = userAgent - // +stream.require is true => default +stream.enable is true - // +stream.require is false => default +stream.enable is false - // Don't override disabling when a bot is detected. - if (streamSetting.enable === false) options.disable = true - const pageHtmlStream = await renderToStream(pageContext.page, { ...options, ...renderToStreamOptions }) + const pageHtmlStream = await renderToStream( + pageContext.page, + getRenderToStreamOptions(pageContext, streamSetting, renderToStreamOptions), + ) pageContext.pageHtmlStream = pageHtmlStream } } @@ -228,6 +216,27 @@ type StreamSetting = { enable: boolean | null require: boolean } +function getRenderToStreamOptions( + pageContext: PageContextServer, + streamSetting: StreamSetting, + renderToStreamOptions: RenderToStreamOptions | undefined, +): RenderToStreamOptions { + // Properties are set conditionally (instead of being assigned `undefined`) to satisfy `exactOptionalPropertyTypes`. + const options: RenderToStreamOptions = {} + // When streamSetting.type is null: let react-streaming decide the stream type + if (streamSetting.type) options.webStream = streamSetting.type === 'web' + const userAgent = + pageContext.headers?.['user-agent'] || + // TO-DO/eventually: remove old way of acccessing the User Agent header. + // @ts-ignore + pageContext.userAgent + if (userAgent) options.userAgent = userAgent + // +stream.require is true => default +stream.enable is true + // +stream.require is false => default +stream.enable is false + // Don't override disabling when a bot is detected. + if (streamSetting.enable === false) options.disable = true + return { ...options, ...renderToStreamOptions } +} function resolveStreamSetting(pageContext: PageContextServer): StreamSetting { const { stream, From 910216f3c7931bb81e2831f11c9f4460545090a8 Mon Sep 17 00:00:00 2001 From: Romuald Brillout Date: Fri, 15 May 2026 18:26:15 +0200 Subject: [PATCH 8/9] comment --- packages/vike-react/src/integration/onRenderHtml.tsx | 1 - 1 file changed, 1 deletion(-) diff --git a/packages/vike-react/src/integration/onRenderHtml.tsx b/packages/vike-react/src/integration/onRenderHtml.tsx index 736e473e..08b86276 100644 --- a/packages/vike-react/src/integration/onRenderHtml.tsx +++ b/packages/vike-react/src/integration/onRenderHtml.tsx @@ -221,7 +221,6 @@ function getRenderToStreamOptions( streamSetting: StreamSetting, renderToStreamOptions: RenderToStreamOptions | undefined, ): RenderToStreamOptions { - // Properties are set conditionally (instead of being assigned `undefined`) to satisfy `exactOptionalPropertyTypes`. const options: RenderToStreamOptions = {} // When streamSetting.type is null: let react-streaming decide the stream type if (streamSetting.type) options.webStream = streamSetting.type === 'web' From ca6321a92b6aad1c5bf7f7e855f6162f271452f6 Mon Sep 17 00:00:00 2001 From: Romuald Brillout Date: Fri, 15 May 2026 18:30:21 +0200 Subject: [PATCH 9/9] minor refactor --- .../src/integration/onRenderHtml.tsx | 29 +++++++++++++------ 1 file changed, 20 insertions(+), 9 deletions(-) diff --git a/packages/vike-react/src/integration/onRenderHtml.tsx b/packages/vike-react/src/integration/onRenderHtml.tsx index 08b86276..2651bc7e 100644 --- a/packages/vike-react/src/integration/onRenderHtml.tsx +++ b/packages/vike-react/src/integration/onRenderHtml.tsx @@ -211,31 +211,42 @@ async function getHtmlInjections(pageContext: PageContextServer) { return { bodyHtmlBegin, bodyHtmlEnd, headHtmlBegin, headHtmlEnd } } -type StreamSetting = { - type: 'node' | 'web' | null - enable: boolean | null - require: boolean -} function getRenderToStreamOptions( pageContext: PageContextServer, streamSetting: StreamSetting, renderToStreamOptions: RenderToStreamOptions | undefined, ): RenderToStreamOptions { const options: RenderToStreamOptions = {} - // When streamSetting.type is null: let react-streaming decide the stream type - if (streamSetting.type) options.webStream = streamSetting.type === 'web' + + if (streamSetting.type) { + options.webStream = streamSetting.type === 'web' + } else { + // Let react-streaming decide the stream type + } + const userAgent = pageContext.headers?.['user-agent'] || // TO-DO/eventually: remove old way of acccessing the User Agent header. // @ts-ignore pageContext.userAgent if (userAgent) options.userAgent = userAgent + // +stream.require is true => default +stream.enable is true // +stream.require is false => default +stream.enable is false - // Don't override disabling when a bot is detected. - if (streamSetting.enable === false) options.disable = true + if (streamSetting.enable === false) { + options.disable = true + } else { + // Let react-streaming disable streaming when it detects a bot + } + return { ...options, ...renderToStreamOptions } } + +type StreamSetting = { + type: 'node' | 'web' | null + enable: boolean | null + require: boolean +} function resolveStreamSetting(pageContext: PageContextServer): StreamSetting { const { stream,