diff --git a/packages/vinext/src/entries/app-rsc-entry.ts b/packages/vinext/src/entries/app-rsc-entry.ts index 2e6aa8340..40cc00a93 100644 --- a/packages/vinext/src/entries/app-rsc-entry.ts +++ b/packages/vinext/src/entries/app-rsc-entry.ts @@ -68,6 +68,7 @@ const appPageRenderPath = resolveEntryPath("../server/app-page-render.js", impor const appPageResponsePath = resolveEntryPath("../server/app-page-response.js", import.meta.url); const cspPath = resolveEntryPath("../server/csp.js", import.meta.url); const appPageRequestPath = resolveEntryPath("../server/app-page-request.js", import.meta.url); +const flightHintsPath = resolveEntryPath("../server/flight-hints.js", import.meta.url); const appRouteHandlerResponsePath = resolveEntryPath( "../server/app-route-handler-response.js", import.meta.url, @@ -330,35 +331,14 @@ import { createTemporaryReferenceSet, } from "@vitejs/plugin-rsc/rsc"; import { AsyncLocalStorage } from "node:async_hooks"; +import { createFlightHintFixTransform as __createFlightHintFixTransform } from ${JSON.stringify(flightHintsPath)}; // React Flight emits HL hints with "stylesheet" for CSS, but the HTML spec // requires "style" for . Fix at the source so every // consumer (SSR embed, client-side navigation, server actions) gets clean data. -// -// Flight lines are newline-delimited, so we buffer partial lines across chunks -// to guarantee the regex never sees a split hint. function renderToReadableStream(model, options) { - const _hlFixRe = /(\\d*:HL\\[.*?),"stylesheet"(\\]|,)/g; const stream = _renderToReadableStream(model, options); - const decoder = new TextDecoder(); - const encoder = new TextEncoder(); - let carry = ""; - return stream.pipeThrough(new TransformStream({ - transform(chunk, controller) { - const text = carry + decoder.decode(chunk, { stream: true }); - const lastNl = text.lastIndexOf("\\n"); - if (lastNl === -1) { - carry = text; - return; - } - carry = text.slice(lastNl + 1); - controller.enqueue(encoder.encode(text.slice(0, lastNl + 1).replace(_hlFixRe, '$1,"style"$2'))); - }, - flush(controller) { - const text = carry + decoder.decode(); - if (text) controller.enqueue(encoder.encode(text.replace(_hlFixRe, '$1,"style"$2'))); - } - })); + return stream.pipeThrough(__createFlightHintFixTransform()); } import { createElement } from "react"; import { setNavigationContext as _setNavigationContextOrig, getNavigationContext as _getNavigationContext } from "next/navigation"; diff --git a/packages/vinext/src/server/app-router-entry.ts b/packages/vinext/src/server/app-router-entry.ts index 3010a37f7..0abd22aa9 100644 --- a/packages/vinext/src/server/app-router-entry.ts +++ b/packages/vinext/src/server/app-router-entry.ts @@ -15,7 +15,7 @@ // @ts-expect-error — virtual module resolved by vinext import rscHandler from "virtual:vinext-rsc-entry"; import { runWithExecutionContext, type ExecutionContextLike } from "../shims/request-context.js"; -import { resolveStaticAssetSignal } from "./worker-utils.js"; +import { applyLocalDevStreamingHeaders, resolveStaticAssetSignal } from "./worker-utils.js"; type WorkerAssetEnv = { ASSETS?: { @@ -70,7 +70,7 @@ export default { }); if (assetResponse) return assetResponse; } - return result; + return applyLocalDevStreamingHeaders(result, request); } if (result === null || result === undefined) { diff --git a/packages/vinext/src/server/app-ssr-stream.ts b/packages/vinext/src/server/app-ssr-stream.ts index 170bdf9d5..2b481dd8c 100644 --- a/packages/vinext/src/server/app-ssr-stream.ts +++ b/packages/vinext/src/server/app-ssr-stream.ts @@ -1,3 +1,4 @@ +import { fixFlightHints } from "./flight-hints.js"; import { createInlineScriptTag, safeJsonStringify } from "./html.js"; export type RscEmbedTransform = { @@ -5,14 +6,7 @@ export type RscEmbedTransform = { finalize(): Promise; }; -/** - * Fix invalid preload "as" values in RSC Flight hint lines before they reach - * the client. React Flight emits HL hints with as="stylesheet" for CSS, but - * the HTML spec requires as="style" for . - */ -export function fixFlightHints(text: string): string { - return text.replace(/(\d*:HL\[.*?),"stylesheet"(\]|,)/g, '$1,"style"$2'); -} +export { fixFlightHints }; /** * Create a helper that progressively embeds RSC chunks as inline