vinext 0.0.31 → 0.0.33

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (99) hide show
  1. package/README.md +10 -7
  2. package/dist/build/report.d.ts +1 -1
  3. package/dist/build/report.js +334 -0
  4. package/dist/build/report.js.map +1 -1
  5. package/dist/build/run-prerender.js +2 -2
  6. package/dist/build/run-prerender.js.map +1 -1
  7. package/dist/check.js +93 -3
  8. package/dist/check.js.map +1 -1
  9. package/dist/cli.js +3 -1
  10. package/dist/cli.js.map +1 -1
  11. package/dist/config/next-config.d.ts +2 -0
  12. package/dist/config/next-config.js +9 -3
  13. package/dist/config/next-config.js.map +1 -1
  14. package/dist/entries/app-browser-entry.js +3 -330
  15. package/dist/entries/app-browser-entry.js.map +1 -1
  16. package/dist/entries/app-rsc-entry.js +286 -644
  17. package/dist/entries/app-rsc-entry.js.map +1 -1
  18. package/dist/entries/app-ssr-entry.js +4 -460
  19. package/dist/entries/app-ssr-entry.js.map +1 -1
  20. package/dist/entries/pages-server-entry.js +2 -1
  21. package/dist/entries/pages-server-entry.js.map +1 -1
  22. package/dist/entries/runtime-entry-module.d.ts +13 -0
  23. package/dist/entries/runtime-entry-module.js +27 -0
  24. package/dist/entries/runtime-entry-module.js.map +1 -0
  25. package/dist/index.d.ts +12 -0
  26. package/dist/index.js +16 -35
  27. package/dist/index.js.map +1 -1
  28. package/dist/plugins/optimize-imports.d.ts +38 -0
  29. package/dist/plugins/optimize-imports.js +557 -0
  30. package/dist/plugins/optimize-imports.js.map +1 -0
  31. package/dist/routing/pages-router.js +1 -1
  32. package/dist/routing/pages-router.js.map +1 -1
  33. package/dist/server/api-handler.d.ts +2 -2
  34. package/dist/server/api-handler.js +3 -4
  35. package/dist/server/api-handler.js.map +1 -1
  36. package/dist/server/app-browser-entry.d.ts +1 -0
  37. package/dist/server/app-browser-entry.js +161 -0
  38. package/dist/server/app-browser-entry.js.map +1 -0
  39. package/dist/server/app-browser-stream.d.ts +33 -0
  40. package/dist/server/app-browser-stream.js +54 -0
  41. package/dist/server/app-browser-stream.js.map +1 -0
  42. package/dist/server/app-page-cache.d.ts +61 -0
  43. package/dist/server/app-page-cache.js +133 -0
  44. package/dist/server/app-page-cache.js.map +1 -0
  45. package/dist/server/app-page-response.d.ts +51 -0
  46. package/dist/server/app-page-response.js +90 -0
  47. package/dist/server/app-page-response.js.map +1 -0
  48. package/dist/server/app-route-handler-cache.d.ts +42 -0
  49. package/dist/server/app-route-handler-cache.js +69 -0
  50. package/dist/server/app-route-handler-cache.js.map +1 -0
  51. package/dist/server/app-route-handler-execution.d.ts +64 -0
  52. package/dist/server/app-route-handler-execution.js +100 -0
  53. package/dist/server/app-route-handler-execution.js.map +1 -0
  54. package/dist/server/app-route-handler-policy.d.ts +51 -0
  55. package/dist/server/app-route-handler-policy.js +57 -0
  56. package/dist/server/app-route-handler-policy.js.map +1 -0
  57. package/dist/server/app-route-handler-response.d.ts +26 -0
  58. package/dist/server/app-route-handler-response.js +61 -0
  59. package/dist/server/app-route-handler-response.js.map +1 -0
  60. package/dist/server/app-route-handler-runtime.d.ts +27 -0
  61. package/dist/server/app-route-handler-runtime.js +99 -0
  62. package/dist/server/app-route-handler-runtime.js.map +1 -0
  63. package/dist/server/app-ssr-entry.d.ts +19 -0
  64. package/dist/server/app-ssr-entry.js +105 -0
  65. package/dist/server/app-ssr-entry.js.map +1 -0
  66. package/dist/server/app-ssr-stream.d.ts +30 -0
  67. package/dist/server/app-ssr-stream.js +116 -0
  68. package/dist/server/app-ssr-stream.js.map +1 -0
  69. package/dist/server/dev-server.d.ts +3 -2
  70. package/dist/server/dev-server.js +29 -30
  71. package/dist/server/dev-server.js.map +1 -1
  72. package/dist/server/instrumentation.d.ts +11 -39
  73. package/dist/server/instrumentation.js +14 -15
  74. package/dist/server/instrumentation.js.map +1 -1
  75. package/dist/server/middleware.d.ts +3 -2
  76. package/dist/server/middleware.js +12 -29
  77. package/dist/server/middleware.js.map +1 -1
  78. package/dist/server/prod-server.js +3 -2
  79. package/dist/server/prod-server.js.map +1 -1
  80. package/dist/shims/compat-router.d.ts +3 -1
  81. package/dist/shims/compat-router.js.map +1 -1
  82. package/dist/shims/error-boundary.d.ts +1 -1
  83. package/dist/shims/fetch-cache.js +2 -0
  84. package/dist/shims/fetch-cache.js.map +1 -1
  85. package/dist/shims/head.d.ts +2 -1
  86. package/dist/shims/head.js +27 -5
  87. package/dist/shims/head.js.map +1 -1
  88. package/dist/shims/internal/router-context.d.ts +2 -1
  89. package/dist/shims/internal/router-context.js.map +1 -1
  90. package/dist/shims/metadata.js +3 -3
  91. package/dist/shims/metadata.js.map +1 -1
  92. package/dist/shims/request-state-types.d.ts +2 -2
  93. package/dist/shims/router.d.ts +1 -1
  94. package/dist/shims/router.js.map +1 -1
  95. package/dist/shims/server.d.ts +41 -3
  96. package/dist/shims/server.js +90 -7
  97. package/dist/shims/server.js.map +1 -1
  98. package/dist/shims/unified-request-context.d.ts +1 -1
  99. package/package.json +1 -1
@@ -0,0 +1 @@
1
+ {"version":3,"file":"app-ssr-entry.js","names":["createReactElement"],"sources":["../../src/server/app-ssr-entry.ts"],"sourcesContent":["/// <reference types=\"@vitejs/plugin-rsc/types\" />\n\nimport type { ReactNode } from \"react\";\nimport { Fragment, createElement as createReactElement } from \"react\";\nimport { createFromReadableStream } from \"@vitejs/plugin-rsc/ssr\";\nimport { renderToReadableStream, renderToStaticMarkup } from \"react-dom/server.edge\";\nimport * as clientReferences from \"virtual:vite-rsc/client-references\";\nimport type { NavigationContext } from \"../shims/navigation.js\";\nimport {\n ServerInsertedHTMLContext,\n clearServerInsertedHTML,\n flushServerInsertedHTML,\n setNavigationContext,\n useServerInsertedHTML,\n} from \"../shims/navigation.js\";\nimport { runWithNavigationContext } from \"../shims/navigation-state.js\";\nimport { safeJsonStringify } from \"./html.js\";\nimport { createRscEmbedTransform, createTickBufferedTransform } from \"./app-ssr-stream.js\";\n\nexport interface FontPreload {\n href: string;\n type: string;\n}\n\nexport interface FontData {\n links?: string[];\n styles?: string[];\n preloads?: FontPreload[];\n}\n\ntype ClientRequire = (id: string) => Promise<unknown>;\n\nlet clientRefsPreloaded = false;\n\nfunction getClientReferenceRequire(): ClientRequire | undefined {\n return (\n globalThis as typeof globalThis & {\n __vite_rsc_client_require__?: ClientRequire;\n }\n ).__vite_rsc_client_require__;\n}\n\nasync function preloadClientReferences(): Promise<void> {\n if (clientRefsPreloaded) return;\n\n const refs = (clientReferences as { default?: Record<string, unknown> }).default;\n const clientRequire = getClientReferenceRequire();\n if (!refs || !clientRequire) return;\n\n await Promise.all(\n Object.keys(refs).map((id) =>\n clientRequire(id).catch((error) => {\n if (process.env.NODE_ENV !== \"production\") {\n console.warn(\"[vinext] failed to preload client ref:\", id, error);\n }\n }),\n ),\n );\n\n clientRefsPreloaded = true;\n}\n\nfunction escapeHtmlAttr(value: string): string {\n return value.replace(/&/g, \"&amp;\").replace(/\"/g, \"&quot;\");\n}\n\nfunction ssrErrorDigest(input: string): string {\n let hash = 5381;\n for (let i = input.length - 1; i >= 0; i--) {\n hash = (hash * 33) ^ input.charCodeAt(i);\n }\n return (hash >>> 0).toString();\n}\n\nfunction getErrorMessage(error: unknown): string {\n if (error instanceof Error) return error.message;\n if (typeof error === \"string\") return error;\n return Object.prototype.toString.call(error);\n}\n\nfunction renderInsertedHtml(insertedElements: readonly unknown[]): string {\n let insertedHTML = \"\";\n\n for (const element of insertedElements) {\n try {\n insertedHTML += renderToStaticMarkup(\n createReactElement(Fragment, null, element as ReactNode),\n );\n } catch {\n // Ignore individual callback failures so the rest of the page can render.\n }\n }\n\n return insertedHTML;\n}\n\nfunction renderFontHtml(fontData?: FontData): string {\n if (!fontData) return \"\";\n\n let fontHTML = \"\";\n\n for (const url of fontData.links ?? []) {\n fontHTML += `<link rel=\"stylesheet\" href=\"${escapeHtmlAttr(url)}\" />\\n`;\n }\n\n for (const preload of fontData.preloads ?? []) {\n fontHTML += `<link rel=\"preload\" href=\"${escapeHtmlAttr(preload.href)}\" as=\"font\" type=\"${escapeHtmlAttr(preload.type)}\" crossorigin />\\n`;\n }\n\n if (fontData.styles && fontData.styles.length > 0) {\n fontHTML += `<style data-vinext-fonts>${fontData.styles.join(\"\\n\")}</style>\\n`;\n }\n\n return fontHTML;\n}\n\nfunction extractModulePreloadHtml(bootstrapScriptContent?: string): string {\n if (!bootstrapScriptContent) return \"\";\n\n const match = bootstrapScriptContent.match(/import\\(\"([^\"]+)\"\\)/);\n if (!match?.[1]) return \"\";\n\n return `<link rel=\"modulepreload\" href=\"${escapeHtmlAttr(match[1])}\" />\\n`;\n}\n\nfunction buildHeadInjectionHtml(\n navContext: NavigationContext | null,\n bootstrapScriptContent: string | undefined,\n insertedHTML: string,\n fontHTML: string,\n): string {\n const paramsScript =\n \"<script>self.__VINEXT_RSC_PARAMS__=\" +\n safeJsonStringify(navContext?.params ?? {}) +\n \"</script>\";\n const navPayload = {\n pathname: navContext?.pathname ?? \"/\",\n searchParams: navContext?.searchParams ? [...navContext.searchParams.entries()] : [],\n };\n const navScript =\n \"<script>self.__VINEXT_RSC_NAV__=\" + safeJsonStringify(navPayload) + \"</script>\";\n\n return (\n paramsScript +\n navScript +\n extractModulePreloadHtml(bootstrapScriptContent) +\n insertedHTML +\n fontHTML\n );\n}\n\nexport async function handleSsr(\n rscStream: ReadableStream<Uint8Array>,\n navContext: NavigationContext | null,\n fontData?: FontData,\n): Promise<ReadableStream<Uint8Array>> {\n return runWithNavigationContext(async () => {\n await preloadClientReferences();\n\n if (navContext) {\n setNavigationContext(navContext);\n }\n\n clearServerInsertedHTML();\n\n try {\n const [ssrStream, embedStream] = rscStream.tee();\n const rscEmbed = createRscEmbedTransform(embedStream);\n\n let flightRoot: Promise<unknown> | null = null;\n\n function VinextFlightRoot(): ReactNode {\n if (!flightRoot) {\n flightRoot = createFromReadableStream(ssrStream);\n }\n return flightRoot as unknown as ReactNode;\n }\n\n const root = createReactElement(VinextFlightRoot);\n const ssrRoot = ServerInsertedHTMLContext\n ? createReactElement(\n ServerInsertedHTMLContext.Provider,\n { value: useServerInsertedHTML },\n root,\n )\n : root;\n\n const bootstrapScriptContent = await import.meta.viteRsc.loadBootstrapScriptContent(\"index\");\n\n const htmlStream = await renderToReadableStream(ssrRoot, {\n bootstrapScriptContent,\n onError(error) {\n if (error && typeof error === \"object\" && \"digest\" in error) {\n return String(error.digest);\n }\n\n if (process.env.NODE_ENV === \"production\" && error) {\n const message = getErrorMessage(error);\n const stack = error instanceof Error ? (error.stack ?? \"\") : \"\";\n return ssrErrorDigest(message + stack);\n }\n\n return undefined;\n },\n });\n\n const insertedHTML = renderInsertedHtml(flushServerInsertedHTML());\n const fontHTML = renderFontHtml(fontData);\n const injectHTML = buildHeadInjectionHtml(\n navContext,\n bootstrapScriptContent,\n insertedHTML,\n fontHTML,\n );\n\n return htmlStream.pipeThrough(createTickBufferedTransform(rscEmbed, injectHTML));\n } finally {\n setNavigationContext(null);\n clearServerInsertedHTML();\n }\n }) as Promise<ReadableStream<Uint8Array>>;\n}\n\nexport default {\n async fetch(request: Request): Promise<Response> {\n const url = new URL(request.url);\n if (url.pathname.startsWith(\"//\")) {\n return new Response(\"404 Not Found\", { status: 404 });\n }\n\n const rscModule = await import.meta.viteRsc.loadModule<{\n default(request: Request): Promise<Response | string | null | undefined>;\n }>(\"rsc\", \"index\");\n const result = await rscModule.default(request);\n\n if (result instanceof Response) {\n return result;\n }\n\n if (result == null) {\n return new Response(\"Not Found\", { status: 404 });\n }\n\n return new Response(String(result), { status: 200 });\n },\n};\n"],"mappings":"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"}
@@ -0,0 +1,30 @@
1
+ //#region src/server/app-ssr-stream.d.ts
2
+ interface RscEmbedTransform {
3
+ flush(): string;
4
+ finalize(): Promise<string>;
5
+ }
6
+ /**
7
+ * Fix invalid preload "as" values in RSC Flight hint lines before they reach
8
+ * the client. React Flight emits HL hints with as="stylesheet" for CSS, but
9
+ * the HTML spec requires as="style" for <link rel="preload">.
10
+ */
11
+ declare function fixFlightHints(text: string): string;
12
+ /**
13
+ * Create a helper that progressively embeds RSC chunks as inline <script> tags.
14
+ * The browser entry turns the embedded text chunks back into Uint8Array data.
15
+ */
16
+ declare function createRscEmbedTransform(embedStream: ReadableStream<Uint8Array>): RscEmbedTransform;
17
+ /**
18
+ * Fix invalid preload "as" values in server-rendered HTML.
19
+ * React Fizz emits <link rel="preload" as="stylesheet"> for CSS, but the
20
+ * HTML spec requires as="style" for <link rel="preload">.
21
+ */
22
+ declare function fixPreloadAs(html: string): string;
23
+ /**
24
+ * Create the tick-buffered HTML transform that injects RSC scripts between
25
+ * React Fizz flush cycles without corrupting split HTML chunks.
26
+ */
27
+ declare function createTickBufferedTransform(rscEmbed: RscEmbedTransform, injectHTML?: string): TransformStream<Uint8Array, Uint8Array>;
28
+ //#endregion
29
+ export { RscEmbedTransform, createRscEmbedTransform, createTickBufferedTransform, fixFlightHints, fixPreloadAs };
30
+ //# sourceMappingURL=app-ssr-stream.d.ts.map
@@ -0,0 +1,116 @@
1
+ import { safeJsonStringify } from "./html.js";
2
+ //#region src/server/app-ssr-stream.ts
3
+ /**
4
+ * Fix invalid preload "as" values in RSC Flight hint lines before they reach
5
+ * the client. React Flight emits HL hints with as="stylesheet" for CSS, but
6
+ * the HTML spec requires as="style" for <link rel="preload">.
7
+ */
8
+ function fixFlightHints(text) {
9
+ return text.replace(/(\d+:HL\[.*?),"stylesheet"(\]|,)/g, "$1,\"style\"$2");
10
+ }
11
+ /**
12
+ * Create a helper that progressively embeds RSC chunks as inline <script> tags.
13
+ * The browser entry turns the embedded text chunks back into Uint8Array data.
14
+ */
15
+ function createRscEmbedTransform(embedStream) {
16
+ const reader = embedStream.getReader();
17
+ const decoder = new TextDecoder();
18
+ let pendingChunks = [];
19
+ let reading = false;
20
+ async function pumpReader() {
21
+ if (reading) return;
22
+ reading = true;
23
+ try {
24
+ while (true) {
25
+ const result = await reader.read();
26
+ if (result.done) break;
27
+ const text = decoder.decode(result.value, { stream: true });
28
+ pendingChunks.push(fixFlightHints(text));
29
+ }
30
+ } catch (error) {
31
+ if (process.env.NODE_ENV !== "production") console.warn("[vinext] RSC embed stream read error:", error);
32
+ } finally {
33
+ reading = false;
34
+ }
35
+ }
36
+ const pumpPromise = pumpReader();
37
+ return {
38
+ flush() {
39
+ if (pendingChunks.length === 0) return "";
40
+ const chunks = pendingChunks;
41
+ pendingChunks = [];
42
+ let scripts = "";
43
+ for (const chunk of chunks) scripts += "<script>self.__VINEXT_RSC_CHUNKS__=self.__VINEXT_RSC_CHUNKS__||[];self.__VINEXT_RSC_CHUNKS__.push(" + safeJsonStringify(chunk) + ")<\/script>";
44
+ return scripts;
45
+ },
46
+ async finalize() {
47
+ await pumpPromise;
48
+ let scripts = this.flush();
49
+ scripts += "<script>self.__VINEXT_RSC_DONE__=true<\/script>";
50
+ return scripts;
51
+ }
52
+ };
53
+ }
54
+ /**
55
+ * Fix invalid preload "as" values in server-rendered HTML.
56
+ * React Fizz emits <link rel="preload" as="stylesheet"> for CSS, but the
57
+ * HTML spec requires as="style" for <link rel="preload">.
58
+ */
59
+ function fixPreloadAs(html) {
60
+ return html.replace(/<link(?=[^>]*\srel="preload")[^>]*>/g, (tag) => {
61
+ return tag.replace(" as=\"stylesheet\"", " as=\"style\"");
62
+ });
63
+ }
64
+ /**
65
+ * Create the tick-buffered HTML transform that injects RSC scripts between
66
+ * React Fizz flush cycles without corrupting split HTML chunks.
67
+ */
68
+ function createTickBufferedTransform(rscEmbed, injectHTML = "") {
69
+ const decoder = new TextDecoder();
70
+ const encoder = new TextEncoder();
71
+ let injected = false;
72
+ let buffered = [];
73
+ let timeoutId = null;
74
+ const flushBuffered = (controller) => {
75
+ for (const chunk of buffered) {
76
+ if (!injected) {
77
+ const headEnd = chunk.indexOf("</head>");
78
+ if (headEnd !== -1) {
79
+ const before = chunk.slice(0, headEnd);
80
+ const after = chunk.slice(headEnd);
81
+ controller.enqueue(encoder.encode(before + injectHTML + after));
82
+ injected = true;
83
+ continue;
84
+ }
85
+ }
86
+ controller.enqueue(encoder.encode(chunk));
87
+ }
88
+ buffered = [];
89
+ };
90
+ return new TransformStream({
91
+ transform(chunk, controller) {
92
+ buffered.push(fixPreloadAs(decoder.decode(chunk, { stream: true })));
93
+ if (timeoutId !== null) return;
94
+ timeoutId = setTimeout(() => {
95
+ flushBuffered(controller);
96
+ const rscScripts = rscEmbed.flush();
97
+ if (rscScripts) controller.enqueue(encoder.encode(rscScripts));
98
+ timeoutId = null;
99
+ }, 0);
100
+ },
101
+ async flush(controller) {
102
+ if (timeoutId !== null) {
103
+ clearTimeout(timeoutId);
104
+ timeoutId = null;
105
+ }
106
+ flushBuffered(controller);
107
+ if (!injected && injectHTML) controller.enqueue(encoder.encode(injectHTML));
108
+ const finalScripts = await rscEmbed.finalize();
109
+ if (finalScripts) controller.enqueue(encoder.encode(finalScripts));
110
+ }
111
+ });
112
+ }
113
+ //#endregion
114
+ export { createRscEmbedTransform, createTickBufferedTransform, fixFlightHints, fixPreloadAs };
115
+
116
+ //# sourceMappingURL=app-ssr-stream.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"app-ssr-stream.js","names":[],"sources":["../../src/server/app-ssr-stream.ts"],"sourcesContent":["import { safeJsonStringify } from \"./html.js\";\n\nexport interface RscEmbedTransform {\n flush(): string;\n finalize(): Promise<string>;\n}\n\n/**\n * Fix invalid preload \"as\" values in RSC Flight hint lines before they reach\n * the client. React Flight emits HL hints with as=\"stylesheet\" for CSS, but\n * the HTML spec requires as=\"style\" for <link rel=\"preload\">.\n */\nexport function fixFlightHints(text: string): string {\n return text.replace(/(\\d+:HL\\[.*?),\"stylesheet\"(\\]|,)/g, '$1,\"style\"$2');\n}\n\n/**\n * Create a helper that progressively embeds RSC chunks as inline <script> tags.\n * The browser entry turns the embedded text chunks back into Uint8Array data.\n */\nexport function createRscEmbedTransform(\n embedStream: ReadableStream<Uint8Array>,\n): RscEmbedTransform {\n const reader = embedStream.getReader();\n const decoder = new TextDecoder();\n let pendingChunks: string[] = [];\n let reading = false;\n\n async function pumpReader(): Promise<void> {\n if (reading) return;\n reading = true;\n try {\n while (true) {\n const result = await reader.read();\n if (result.done) break;\n const text = decoder.decode(result.value, { stream: true });\n // The RSC entry already fixes HL hints at the source. Keep this second\n // pass as defense in depth for any embed stream that bypasses that\n // wrapper; the rewrite is idempotent, so double-application is safe.\n pendingChunks.push(fixFlightHints(text));\n }\n } catch (error) {\n if (process.env.NODE_ENV !== \"production\") {\n console.warn(\"[vinext] RSC embed stream read error:\", error);\n }\n } finally {\n reading = false;\n }\n }\n\n const pumpPromise = pumpReader();\n\n return {\n flush(): string {\n if (pendingChunks.length === 0) return \"\";\n\n const chunks = pendingChunks;\n pendingChunks = [];\n\n let scripts = \"\";\n for (const chunk of chunks) {\n scripts +=\n \"<script>self.__VINEXT_RSC_CHUNKS__=self.__VINEXT_RSC_CHUNKS__||[];self.__VINEXT_RSC_CHUNKS__.push(\" +\n safeJsonStringify(chunk) +\n \")</script>\";\n }\n return scripts;\n },\n\n async finalize(): Promise<string> {\n await pumpPromise;\n let scripts = this.flush();\n scripts += \"<script>self.__VINEXT_RSC_DONE__=true</script>\";\n return scripts;\n },\n };\n}\n\n/**\n * Fix invalid preload \"as\" values in server-rendered HTML.\n * React Fizz emits <link rel=\"preload\" as=\"stylesheet\"> for CSS, but the\n * HTML spec requires as=\"style\" for <link rel=\"preload\">.\n */\nexport function fixPreloadAs(html: string): string {\n return html.replace(/<link(?=[^>]*\\srel=\"preload\")[^>]*>/g, (tag) => {\n return tag.replace(' as=\"stylesheet\"', ' as=\"style\"');\n });\n}\n\n/**\n * Create the tick-buffered HTML transform that injects RSC scripts between\n * React Fizz flush cycles without corrupting split HTML chunks.\n */\nexport function createTickBufferedTransform(\n rscEmbed: RscEmbedTransform,\n injectHTML = \"\",\n): TransformStream<Uint8Array, Uint8Array> {\n const decoder = new TextDecoder();\n const encoder = new TextEncoder();\n let injected = false;\n let buffered: string[] = [];\n let timeoutId: ReturnType<typeof setTimeout> | null = null;\n\n const flushBuffered = (controller: TransformStreamDefaultController<Uint8Array>): void => {\n for (const chunk of buffered) {\n if (!injected) {\n const headEnd = chunk.indexOf(\"</head>\");\n if (headEnd !== -1) {\n const before = chunk.slice(0, headEnd);\n const after = chunk.slice(headEnd);\n controller.enqueue(encoder.encode(before + injectHTML + after));\n injected = true;\n continue;\n }\n }\n controller.enqueue(encoder.encode(chunk));\n }\n buffered = [];\n };\n\n return new TransformStream<Uint8Array, Uint8Array>({\n transform(chunk, controller) {\n buffered.push(fixPreloadAs(decoder.decode(chunk, { stream: true })));\n\n if (timeoutId !== null) return;\n\n timeoutId = setTimeout(() => {\n flushBuffered(controller);\n\n const rscScripts = rscEmbed.flush();\n if (rscScripts) {\n controller.enqueue(encoder.encode(rscScripts));\n }\n\n timeoutId = null;\n }, 0);\n },\n\n async flush(controller) {\n if (timeoutId !== null) {\n clearTimeout(timeoutId);\n timeoutId = null;\n }\n\n flushBuffered(controller);\n\n if (!injected && injectHTML) {\n controller.enqueue(encoder.encode(injectHTML));\n }\n\n const finalScripts = await rscEmbed.finalize();\n if (finalScripts) {\n controller.enqueue(encoder.encode(finalScripts));\n }\n },\n });\n}\n"],"mappings":";;;;;;;AAYA,SAAgB,eAAe,MAAsB;AACnD,QAAO,KAAK,QAAQ,qCAAqC,iBAAe;;;;;;AAO1E,SAAgB,wBACd,aACmB;CACnB,MAAM,SAAS,YAAY,WAAW;CACtC,MAAM,UAAU,IAAI,aAAa;CACjC,IAAI,gBAA0B,EAAE;CAChC,IAAI,UAAU;CAEd,eAAe,aAA4B;AACzC,MAAI,QAAS;AACb,YAAU;AACV,MAAI;AACF,UAAO,MAAM;IACX,MAAM,SAAS,MAAM,OAAO,MAAM;AAClC,QAAI,OAAO,KAAM;IACjB,MAAM,OAAO,QAAQ,OAAO,OAAO,OAAO,EAAE,QAAQ,MAAM,CAAC;AAI3D,kBAAc,KAAK,eAAe,KAAK,CAAC;;WAEnC,OAAO;AACd,OAAI,QAAQ,IAAI,aAAa,aAC3B,SAAQ,KAAK,yCAAyC,MAAM;YAEtD;AACR,aAAU;;;CAId,MAAM,cAAc,YAAY;AAEhC,QAAO;EACL,QAAgB;AACd,OAAI,cAAc,WAAW,EAAG,QAAO;GAEvC,MAAM,SAAS;AACf,mBAAgB,EAAE;GAElB,IAAI,UAAU;AACd,QAAK,MAAM,SAAS,OAClB,YACE,uGACA,kBAAkB,MAAM,GACxB;AAEJ,UAAO;;EAGT,MAAM,WAA4B;AAChC,SAAM;GACN,IAAI,UAAU,KAAK,OAAO;AAC1B,cAAW;AACX,UAAO;;EAEV;;;;;;;AAQH,SAAgB,aAAa,MAAsB;AACjD,QAAO,KAAK,QAAQ,yCAAyC,QAAQ;AACnE,SAAO,IAAI,QAAQ,sBAAoB,gBAAc;GACrD;;;;;;AAOJ,SAAgB,4BACd,UACA,aAAa,IAC4B;CACzC,MAAM,UAAU,IAAI,aAAa;CACjC,MAAM,UAAU,IAAI,aAAa;CACjC,IAAI,WAAW;CACf,IAAI,WAAqB,EAAE;CAC3B,IAAI,YAAkD;CAEtD,MAAM,iBAAiB,eAAmE;AACxF,OAAK,MAAM,SAAS,UAAU;AAC5B,OAAI,CAAC,UAAU;IACb,MAAM,UAAU,MAAM,QAAQ,UAAU;AACxC,QAAI,YAAY,IAAI;KAClB,MAAM,SAAS,MAAM,MAAM,GAAG,QAAQ;KACtC,MAAM,QAAQ,MAAM,MAAM,QAAQ;AAClC,gBAAW,QAAQ,QAAQ,OAAO,SAAS,aAAa,MAAM,CAAC;AAC/D,gBAAW;AACX;;;AAGJ,cAAW,QAAQ,QAAQ,OAAO,MAAM,CAAC;;AAE3C,aAAW,EAAE;;AAGf,QAAO,IAAI,gBAAwC;EACjD,UAAU,OAAO,YAAY;AAC3B,YAAS,KAAK,aAAa,QAAQ,OAAO,OAAO,EAAE,QAAQ,MAAM,CAAC,CAAC,CAAC;AAEpE,OAAI,cAAc,KAAM;AAExB,eAAY,iBAAiB;AAC3B,kBAAc,WAAW;IAEzB,MAAM,aAAa,SAAS,OAAO;AACnC,QAAI,WACF,YAAW,QAAQ,QAAQ,OAAO,WAAW,CAAC;AAGhD,gBAAY;MACX,EAAE;;EAGP,MAAM,MAAM,YAAY;AACtB,OAAI,cAAc,MAAM;AACtB,iBAAa,UAAU;AACvB,gBAAY;;AAGd,iBAAc,WAAW;AAEzB,OAAI,CAAC,YAAY,WACf,YAAW,QAAQ,QAAQ,OAAO,WAAW,CAAC;GAGhD,MAAM,eAAe,MAAM,SAAS,UAAU;AAC9C,OAAI,aACF,YAAW,QAAQ,QAAQ,OAAO,aAAa,CAAC;;EAGrD,CAAC"}
@@ -1,6 +1,7 @@
1
1
  import { ValidFileMatcher } from "../routing/file-matcher.js";
2
2
  import { Route } from "../routing/pages-router.js";
3
3
  import { NextI18nConfig } from "../config/next-config.js";
4
+ import { ModuleImporter } from "./instrumentation.js";
4
5
  import { ViteDevServer } from "vite";
5
6
  import { IncomingMessage, ServerResponse } from "node:http";
6
7
 
@@ -30,12 +31,12 @@ declare function parseCookieLocale(req: IncomingMessage, i18nConfig: NextI18nCon
30
31
  *
31
32
  * For each request:
32
33
  * 1. Match the URL against discovered routes
33
- * 2. Load the page module via Vite's SSR module loader
34
+ * 2. Load the page module via the ModuleRunner
34
35
  * 3. Call getServerSideProps/getStaticProps if present
35
36
  * 4. Render the component to HTML
36
37
  * 5. Wrap in _document shell and send response
37
38
  */
38
- declare function createSSRHandler(server: ViteDevServer, routes: Route[], pagesDir: string, i18nConfig?: NextI18nConfig | null, fileMatcher?: ValidFileMatcher, basePath?: string, trailingSlash?: boolean): (req: IncomingMessage, res: ServerResponse, url: string, /** Status code override — propagated from middleware rewrite status. */
39
+ declare function createSSRHandler(server: ViteDevServer, runner: ModuleImporter, routes: Route[], pagesDir: string, i18nConfig?: NextI18nConfig | null, fileMatcher?: ValidFileMatcher, basePath?: string, trailingSlash?: boolean): (req: IncomingMessage, res: ServerResponse, url: string, /** Status code override — propagated from middleware rewrite status. */
39
40
 
40
41
  statusCode?: number) => Promise<void>;
41
42
  //#endregion
@@ -2,6 +2,7 @@ import { createValidFileMatcher } from "../routing/file-matcher.js";
2
2
  import { patternToNextFormat } from "../routing/route-validation.js";
3
3
  import { matchRoute } from "../routing/pages-router.js";
4
4
  import { createRequestContext, runWithRequestContext } from "../shims/unified-request-context.js";
5
+ import { importModule, reportRequestError } from "./instrumentation.js";
5
6
  import { _runWithCacheState } from "../shims/cache.js";
6
7
  import { buildPagesCacheValue, getRevalidateDuration, isrCacheKey, isrGet, isrSet, setRevalidateDuration, triggerBackgroundRegeneration } from "./isr-cache.js";
7
8
  import { runWithPrivateCache } from "../shims/cache-runtime.js";
@@ -10,7 +11,6 @@ import { parseQueryString } from "../utils/query.js";
10
11
  import "../shims/router-state.js";
11
12
  import { runWithHeadState } from "../shims/head-state.js";
12
13
  import { runWithServerInsertedHTMLState } from "../shims/navigation-state.js";
13
- import { reportRequestError } from "./instrumentation.js";
14
14
  import { safeJsonStringify } from "./html.js";
15
15
  import { logRequest, now } from "./request-log.js";
16
16
  import { detectLocaleFromAcceptLanguage, extractLocaleFromUrl as extractLocaleFromUrl$1, parseCookieLocaleFromHeader, resolvePagesI18nRequest } from "./pages-i18n.js";
@@ -128,14 +128,14 @@ function parseCookieLocale(req, i18nConfig) {
128
128
  *
129
129
  * For each request:
130
130
  * 1. Match the URL against discovered routes
131
- * 2. Load the page module via Vite's SSR module loader
131
+ * 2. Load the page module via the ModuleRunner
132
132
  * 3. Call getServerSideProps/getStaticProps if present
133
133
  * 4. Render the component to HTML
134
134
  * 5. Wrap in _document shell and send response
135
135
  */
136
- function createSSRHandler(server, routes, pagesDir, i18nConfig, fileMatcher, basePath = "", trailingSlash = false) {
136
+ function createSSRHandler(server, runner, routes, pagesDir, i18nConfig, fileMatcher, basePath = "", trailingSlash = false) {
137
137
  const matcher = fileMatcher ?? createValidFileMatcher();
138
- const _alsRegistration = Promise.all([server.ssrLoadModule("vinext/head-state"), server.ssrLoadModule("vinext/router-state")]);
138
+ const _alsRegistration = Promise.all([runner.import("vinext/head-state"), runner.import("vinext/router-state")]);
139
139
  _alsRegistration.catch(() => {});
140
140
  return async (req, res, url, statusCode) => {
141
141
  const _reqStart = now();
@@ -171,7 +171,7 @@ function createSSRHandler(server, routes, pagesDir, i18nConfig, fileMatcher, bas
171
171
  }
172
172
  const match = matchRoute(localeStrippedUrl, routes);
173
173
  if (!match) {
174
- await renderErrorPage(server, req, res, url, pagesDir, 404, void 0, matcher);
174
+ await renderErrorPage(server, runner, req, res, url, pagesDir, 404, void 0, matcher);
175
175
  return;
176
176
  }
177
177
  const { route, params } = match;
@@ -179,7 +179,7 @@ function createSSRHandler(server, routes, pagesDir, i18nConfig, fileMatcher, bas
179
179
  ensureFetchPatch();
180
180
  try {
181
181
  await _alsRegistration;
182
- const routerShim = await server.ssrLoadModule("next/router");
182
+ const routerShim = await importModule(runner, "next/router");
183
183
  if (typeof routerShim.setSSRContext === "function") routerShim.setSSRContext({
184
184
  pathname: patternToNextFormat(route.pattern),
185
185
  query: {
@@ -193,8 +193,8 @@ function createSSRHandler(server, routes, pagesDir, i18nConfig, fileMatcher, bas
193
193
  domainLocales
194
194
  });
195
195
  if (i18nConfig) {
196
- await server.ssrLoadModule("vinext/i18n-state");
197
- const i18nCtx = await server.ssrLoadModule("vinext/i18n-context");
196
+ await runner.import("vinext/i18n-state");
197
+ const i18nCtx = await importModule(runner, "vinext/i18n-context");
198
198
  if (typeof i18nCtx.setI18nContext === "function") i18nCtx.setI18nContext({
199
199
  locale: locale ?? currentDefaultLocale,
200
200
  locales: i18nConfig.locales,
@@ -203,7 +203,7 @@ function createSSRHandler(server, routes, pagesDir, i18nConfig, fileMatcher, bas
203
203
  hostname: req.headers.host?.split(":", 1)[0]
204
204
  });
205
205
  }
206
- const pageModule = await server.ssrLoadModule(route.filePath);
206
+ const pageModule = await importModule(runner, route.filePath);
207
207
  _compileEnd = now();
208
208
  const PageComponent = pageModule.default;
209
209
  if (!PageComponent) {
@@ -227,7 +227,7 @@ function createSSRHandler(server, routes, pagesDir, i18nConfig, fileMatcher, bas
227
227
  return String(val) === String(actual);
228
228
  });
229
229
  })) {
230
- await renderErrorPage(server, req, res, url, pagesDir, 404, routerShim.wrapWithRouterContext, matcher);
230
+ await renderErrorPage(server, runner, req, res, url, pagesDir, 404, routerShim.wrapWithRouterContext, matcher);
231
231
  return;
232
232
  }
233
233
  }
@@ -258,7 +258,7 @@ function createSSRHandler(server, routes, pagesDir, i18nConfig, fileMatcher, bas
258
258
  return;
259
259
  }
260
260
  if (result && "notFound" in result && result.notFound) {
261
- await renderErrorPage(server, req, res, url, pagesDir, 404, routerShim.wrapWithRouterContext);
261
+ await renderErrorPage(server, runner, req, res, url, pagesDir, 404, routerShim.wrapWithRouterContext);
262
262
  return;
263
263
  }
264
264
  if (!statusCode && res.statusCode !== 200) statusCode = res.statusCode;
@@ -273,9 +273,9 @@ function createSSRHandler(server, routes, pagesDir, i18nConfig, fileMatcher, bas
273
273
  let earlyFontLinkHeader = "";
274
274
  try {
275
275
  const earlyPreloads = [];
276
- const fontGoogleEarly = await server.ssrLoadModule("next/font/google");
276
+ const fontGoogleEarly = await importModule(runner, "next/font/google");
277
277
  if (typeof fontGoogleEarly.getSSRFontPreloads === "function") earlyPreloads.push(...fontGoogleEarly.getSSRFontPreloads());
278
- const fontLocalEarly = await server.ssrLoadModule("next/font/local");
278
+ const fontLocalEarly = await importModule(runner, "next/font/local");
279
279
  if (typeof fontLocalEarly.getSSRFontPreloads === "function") earlyPreloads.push(...fontLocalEarly.getSSRFontPreloads());
280
280
  if (earlyPreloads.length > 0) earlyFontLinkHeader = earlyPreloads.map((p) => `<${p.href}>; rel=preload; as=font; type=${p.type}; crossorigin`).join(", ");
281
281
  } catch {}
@@ -325,8 +325,8 @@ function createSSRHandler(server, routes, pagesDir, i18nConfig, fileMatcher, bas
325
325
  domainLocales
326
326
  });
327
327
  if (i18nConfig) {
328
- await server.ssrLoadModule("vinext/i18n-state");
329
- const i18nCtx = await server.ssrLoadModule("vinext/i18n-context");
328
+ await runner.import("vinext/i18n-state");
329
+ const i18nCtx = await importModule(runner, "vinext/i18n-context");
330
330
  if (typeof i18nCtx.setI18nContext === "function") i18nCtx.setI18nContext({
331
331
  locale: locale ?? currentDefaultLocale,
332
332
  locales: i18nConfig.locales,
@@ -338,7 +338,7 @@ function createSSRHandler(server, routes, pagesDir, i18nConfig, fileMatcher, bas
338
338
  let RegenApp = null;
339
339
  const appPath = path.join(pagesDir, "_app");
340
340
  if (findFileWithExtensions(appPath, matcher)) try {
341
- RegenApp = (await server.ssrLoadModule(appPath)).default ?? null;
341
+ RegenApp = (await runner.import(appPath)).default ?? null;
342
342
  } catch {}
343
343
  let el = RegenApp ? React.createElement(RegenApp, {
344
344
  Component: pageModule.default,
@@ -398,7 +398,7 @@ function createSSRHandler(server, routes, pagesDir, i18nConfig, fileMatcher, bas
398
398
  return;
399
399
  }
400
400
  if (result && "notFound" in result && result.notFound) {
401
- await renderErrorPage(server, req, res, url, pagesDir, 404, routerShim.wrapWithRouterContext);
401
+ await renderErrorPage(server, runner, req, res, url, pagesDir, 404, routerShim.wrapWithRouterContext);
402
402
  return;
403
403
  }
404
404
  if (typeof result?.revalidate === "number" && result.revalidate > 0) isrRevalidateSeconds = result.revalidate;
@@ -406,7 +406,7 @@ function createSSRHandler(server, routes, pagesDir, i18nConfig, fileMatcher, bas
406
406
  let AppComponent = null;
407
407
  const appPath = path.join(pagesDir, "_app");
408
408
  if (findFileWithExtensions(appPath, matcher)) try {
409
- AppComponent = (await server.ssrLoadModule(appPath)).default ?? null;
409
+ AppComponent = (await importModule(runner, appPath)).default ?? null;
410
410
  } catch {}
411
411
  const createElement = React.createElement;
412
412
  let element;
@@ -417,15 +417,15 @@ function createSSRHandler(server, routes, pagesDir, i18nConfig, fileMatcher, bas
417
417
  });
418
418
  else element = createElement(PageComponent, pageProps);
419
419
  if (wrapWithRouterContext) element = wrapWithRouterContext(element);
420
- const headShim = await server.ssrLoadModule("next/head");
420
+ const headShim = await importModule(runner, "next/head");
421
421
  if (typeof headShim.resetSSRHead === "function") headShim.resetSSRHead();
422
- const dynamicShim = await server.ssrLoadModule("next/dynamic");
422
+ const dynamicShim = await importModule(runner, "next/dynamic");
423
423
  if (typeof dynamicShim.flushPreloads === "function") await dynamicShim.flushPreloads();
424
424
  let fontHeadHTML = "";
425
425
  const allFontStyles = [];
426
426
  const allFontPreloads = [];
427
427
  try {
428
- const fontGoogle = await server.ssrLoadModule("next/font/google");
428
+ const fontGoogle = await importModule(runner, "next/font/google");
429
429
  if (typeof fontGoogle.getSSRFontLinks === "function") {
430
430
  const fontUrls = fontGoogle.getSSRFontLinks();
431
431
  for (const fontUrl of fontUrls) {
@@ -437,7 +437,7 @@ function createSSRHandler(server, routes, pagesDir, i18nConfig, fileMatcher, bas
437
437
  if (typeof fontGoogle.getSSRFontPreloads === "function") allFontPreloads.push(...fontGoogle.getSSRFontPreloads());
438
438
  } catch {}
439
439
  try {
440
- const fontLocal = await server.ssrLoadModule("next/font/local");
440
+ const fontLocal = await importModule(runner, "next/font/local");
441
441
  if (typeof fontLocal.getSSRFontStyles === "function") allFontStyles.push(...fontLocal.getSSRFontStyles());
442
442
  if (typeof fontLocal.getSSRFontPreloads === "function") allFontPreloads.push(...fontLocal.getSSRFontPreloads());
443
443
  } catch {}
@@ -495,7 +495,7 @@ hydrate();
495
495
  const docPath = path.join(pagesDir, "_document");
496
496
  let DocumentComponent = null;
497
497
  if (findFileWithExtensions(docPath, matcher)) try {
498
- DocumentComponent = (await server.ssrLoadModule(docPath)).default ?? null;
498
+ DocumentComponent = (await runner.import(docPath)).default ?? null;
499
499
  } catch {}
500
500
  const allScripts = `${nextDataScript}\n ${hydrationScript}`;
501
501
  const extraHeaders = { ...gsspExtraHeaders };
@@ -528,7 +528,6 @@ hydrate();
528
528
  setRevalidateDuration(cacheKey, isrRevalidateSeconds);
529
529
  }
530
530
  } catch (e) {
531
- server.ssrFixStacktrace?.(e);
532
531
  console.error(e);
533
532
  reportRequestError(e instanceof Error ? e : new Error(String(e)), {
534
533
  path: url,
@@ -540,7 +539,7 @@ hydrate();
540
539
  routeType: "render"
541
540
  }).catch(() => {});
542
541
  try {
543
- await renderErrorPage(server, req, res, url, pagesDir, 500, void 0, matcher);
542
+ await renderErrorPage(server, runner, req, res, url, pagesDir, 500, void 0, matcher);
544
543
  } catch (fallbackErr) {
545
544
  res.statusCode = 500;
546
545
  res.end(`Internal Server Error: ${fallbackErr.message}`);
@@ -557,24 +556,24 @@ hydrate();
557
556
  * - 500: pages/500.tsx -> pages/_error.tsx -> default
558
557
  * - other: pages/_error.tsx -> default
559
558
  */
560
- async function renderErrorPage(server, _req, res, url, pagesDir, statusCode, wrapWithRouterContext, fileMatcher) {
559
+ async function renderErrorPage(server, runner, _req, res, url, pagesDir, statusCode, wrapWithRouterContext, fileMatcher) {
561
560
  const matcher = fileMatcher ?? createValidFileMatcher();
562
561
  const candidates = statusCode === 404 ? ["404", "_error"] : statusCode === 500 ? ["500", "_error"] : ["_error"];
563
562
  for (const candidate of candidates) try {
564
563
  const candidatePath = path.join(pagesDir, candidate);
565
564
  if (!findFileWithExtensions(candidatePath, matcher)) continue;
566
- const ErrorComponent = (await server.ssrLoadModule(candidatePath)).default;
565
+ const ErrorComponent = (await importModule(runner, candidatePath)).default;
567
566
  if (!ErrorComponent) continue;
568
567
  let AppComponent = null;
569
568
  const appPathErr = path.join(pagesDir, "_app");
570
569
  if (findFileWithExtensions(appPathErr, matcher)) try {
571
- AppComponent = (await server.ssrLoadModule(appPathErr)).default ?? null;
570
+ AppComponent = (await importModule(runner, appPathErr)).default ?? null;
572
571
  } catch {}
573
572
  const createElement = React.createElement;
574
573
  const errorProps = { statusCode };
575
574
  let wrapFn = wrapWithRouterContext;
576
575
  if (!wrapFn) try {
577
- wrapFn = (await server.ssrLoadModule("next/router")).wrapWithRouterContext;
576
+ wrapFn = (await importModule(runner, "next/router")).wrapWithRouterContext;
578
577
  } catch {}
579
578
  let element;
580
579
  if (AppComponent) element = createElement(AppComponent, {
@@ -588,7 +587,7 @@ async function renderErrorPage(server, _req, res, url, pagesDir, statusCode, wra
588
587
  let DocumentComponent = null;
589
588
  const docPathErr = path.join(pagesDir, "_document");
590
589
  if (findFileWithExtensions(docPathErr, matcher)) try {
591
- DocumentComponent = (await server.ssrLoadModule(docPathErr)).default ?? null;
590
+ DocumentComponent = (await importModule(runner, docPathErr)).default ?? null;
592
591
  } catch {}
593
592
  if (DocumentComponent) {
594
593
  let docHtml = await renderToStringAsync(createElement(DocumentComponent));