@bleedingdev/modern-js-runtime 3.2.0-ultramodern.120 → 3.2.0-ultramodern.121

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 (203) hide show
  1. package/dist/cjs/boundary-debugger/index.js +4 -0
  2. package/dist/cjs/cli/index.js +11 -0
  3. package/dist/cjs/{router/runtime/tanstack/rsc/ClientSlot.js → core/context/extensions.js} +33 -21
  4. package/dist/cjs/{router/runtime/tanstack/rsc/SlotContext.js → core/context/helmetContext.js} +16 -20
  5. package/dist/cjs/core/context/index.js +65 -0
  6. package/dist/cjs/core/react/wrapper.js +6 -4
  7. package/dist/cjs/core/server/helmet.js +2 -1
  8. package/dist/cjs/core/server/requestHandler.js +42 -29
  9. package/dist/cjs/core/server/routerCleanup.js +110 -0
  10. package/dist/cjs/core/server/scriptOrder.js +75 -4
  11. package/dist/cjs/core/server/stream/afterTemplate.js +6 -18
  12. package/dist/cjs/core/server/stream/deferredScript.js +4 -1
  13. package/dist/cjs/core/server/string/index.js +1 -7
  14. package/dist/cjs/core/server/string/loadable.js +13 -40
  15. package/dist/cjs/core/server/string/ssrData.js +1 -1
  16. package/dist/cjs/core/server/utils.js +31 -8
  17. package/dist/cjs/exports/head.js +135 -74
  18. package/dist/cjs/exports/tanstack-router.js +36 -305
  19. package/dist/cjs/module-federation/index.js +178 -0
  20. package/dist/cjs/router/cli/code/index.js +1 -47
  21. package/dist/cjs/router/cli/code/templates.js +1 -14
  22. package/dist/cjs/router/cli/handler.js +1 -1
  23. package/dist/cjs/router/cli/index.js +2 -23
  24. package/dist/cjs/router/runtime/DeferredDataScripts.node.js +16 -4
  25. package/dist/cjs/router/runtime/PrefetchLink.js +2 -3
  26. package/dist/cjs/router/runtime/internal.js +20 -13
  27. package/dist/cjs/router/runtime/lifecycle.js +37 -22
  28. package/dist/cjs/router/runtime/plugin.js +2 -9
  29. package/dist/cjs/router/runtime/plugin.node.js +2 -7
  30. package/dist/cjs/router/runtime/provider.js +107 -0
  31. package/dist/cjs/router/runtime/utils.js +35 -9
  32. package/dist/esm/boundary-debugger/index.mjs +4 -0
  33. package/dist/esm/cli/index.mjs +4 -2
  34. package/dist/esm/core/context/extensions.mjs +28 -0
  35. package/dist/esm/core/context/helmetContext.mjs +13 -0
  36. package/dist/esm/core/context/index.mjs +5 -0
  37. package/dist/esm/core/react/wrapper.mjs +6 -4
  38. package/dist/esm/core/server/helmet.mjs +2 -1
  39. package/dist/esm/core/server/requestHandler.mjs +43 -30
  40. package/dist/esm/core/server/routerCleanup.mjs +66 -0
  41. package/dist/esm/core/server/scriptOrder.mjs +60 -1
  42. package/dist/esm/core/server/stream/afterTemplate.mjs +8 -20
  43. package/dist/esm/core/server/stream/deferredScript.mjs +4 -1
  44. package/dist/esm/core/server/string/index.mjs +3 -9
  45. package/dist/esm/core/server/string/loadable.mjs +11 -38
  46. package/dist/esm/core/server/string/ssrData.mjs +2 -2
  47. package/dist/esm/core/server/utils.mjs +31 -8
  48. package/dist/esm/exports/head.mjs +135 -74
  49. package/dist/esm/exports/tanstack-router.mjs +30 -4
  50. package/dist/esm/module-federation/index.mjs +109 -0
  51. package/dist/esm/router/cli/code/index.mjs +1 -47
  52. package/dist/esm/router/cli/code/templates.mjs +1 -14
  53. package/dist/esm/router/cli/handler.mjs +1 -1
  54. package/dist/esm/router/cli/index.mjs +3 -24
  55. package/dist/esm/router/runtime/DeferredDataScripts.node.mjs +16 -4
  56. package/dist/esm/router/runtime/PrefetchLink.mjs +2 -3
  57. package/dist/esm/router/runtime/internal.mjs +16 -15
  58. package/dist/esm/router/runtime/lifecycle.mjs +22 -13
  59. package/dist/esm/router/runtime/plugin.mjs +4 -11
  60. package/dist/esm/router/runtime/plugin.node.mjs +4 -9
  61. package/dist/esm/router/runtime/provider.mjs +57 -0
  62. package/dist/esm/router/runtime/utils.mjs +35 -9
  63. package/dist/esm-node/boundary-debugger/index.mjs +4 -0
  64. package/dist/esm-node/cli/index.mjs +4 -2
  65. package/dist/esm-node/core/context/extensions.mjs +29 -0
  66. package/dist/esm-node/core/context/helmetContext.mjs +14 -0
  67. package/dist/esm-node/core/context/index.mjs +5 -0
  68. package/dist/esm-node/core/react/wrapper.mjs +6 -4
  69. package/dist/esm-node/core/server/helmet.mjs +2 -1
  70. package/dist/esm-node/core/server/requestHandler.mjs +43 -30
  71. package/dist/esm-node/core/server/routerCleanup.mjs +67 -0
  72. package/dist/esm-node/core/server/scriptOrder.mjs +60 -1
  73. package/dist/esm-node/core/server/stream/afterTemplate.mjs +8 -20
  74. package/dist/esm-node/core/server/stream/deferredScript.mjs +4 -1
  75. package/dist/esm-node/core/server/string/index.mjs +3 -9
  76. package/dist/esm-node/core/server/string/loadable.mjs +11 -38
  77. package/dist/esm-node/core/server/string/ssrData.mjs +2 -2
  78. package/dist/esm-node/core/server/utils.mjs +31 -8
  79. package/dist/esm-node/exports/head.mjs +135 -74
  80. package/dist/esm-node/exports/tanstack-router.mjs +30 -4
  81. package/dist/esm-node/module-federation/index.mjs +110 -0
  82. package/dist/esm-node/router/cli/code/index.mjs +1 -47
  83. package/dist/esm-node/router/cli/code/templates.mjs +1 -14
  84. package/dist/esm-node/router/cli/handler.mjs +1 -1
  85. package/dist/esm-node/router/cli/index.mjs +3 -24
  86. package/dist/esm-node/router/runtime/DeferredDataScripts.node.mjs +16 -4
  87. package/dist/esm-node/router/runtime/PrefetchLink.mjs +2 -3
  88. package/dist/esm-node/router/runtime/internal.mjs +16 -15
  89. package/dist/esm-node/router/runtime/lifecycle.mjs +22 -13
  90. package/dist/esm-node/router/runtime/plugin.mjs +4 -11
  91. package/dist/esm-node/router/runtime/plugin.node.mjs +4 -9
  92. package/dist/esm-node/router/runtime/provider.mjs +58 -0
  93. package/dist/esm-node/router/runtime/utils.mjs +35 -9
  94. package/dist/types/cli/index.d.ts +3 -1
  95. package/dist/types/core/context/extensions.d.ts +37 -0
  96. package/dist/types/core/context/helmetContext.d.ts +10 -0
  97. package/dist/types/core/context/index.d.ts +6 -0
  98. package/dist/types/core/context/runtime.d.ts +1 -11
  99. package/dist/types/core/server/routerCleanup.d.ts +28 -0
  100. package/dist/types/core/server/scriptOrder.d.ts +24 -0
  101. package/dist/types/core/server/string/loadable.d.ts +1 -7
  102. package/dist/types/core/server/utils.d.ts +1 -0
  103. package/dist/types/exports/tanstack-router.d.ts +88 -7
  104. package/dist/types/module-federation/index.d.ts +65 -0
  105. package/dist/types/router/cli/code/index.d.ts +1 -3
  106. package/dist/types/router/cli/handler.d.ts +0 -3
  107. package/dist/types/router/runtime/internal.d.ts +1 -0
  108. package/dist/types/router/runtime/lifecycle.d.ts +2 -0
  109. package/dist/types/router/runtime/plugin.d.ts +1 -1
  110. package/dist/types/router/runtime/plugin.node.d.ts +1 -1
  111. package/dist/types/router/runtime/provider.d.ts +61 -0
  112. package/package.json +15 -11
  113. package/rstest.config.mts +2 -4
  114. package/dist/cjs/router/cli/code/tanstackTypes.js +0 -447
  115. package/dist/cjs/router/runtime/tanstack/basepathRewrite.js +0 -66
  116. package/dist/cjs/router/runtime/tanstack/dataMutation.js +0 -349
  117. package/dist/cjs/router/runtime/tanstack/hydrationBoundary.js +0 -48
  118. package/dist/cjs/router/runtime/tanstack/outlet.js +0 -58
  119. package/dist/cjs/router/runtime/tanstack/plugin.js +0 -342
  120. package/dist/cjs/router/runtime/tanstack/plugin.node.js +0 -272
  121. package/dist/cjs/router/runtime/tanstack/prefetchLink.js +0 -59
  122. package/dist/cjs/router/runtime/tanstack/routeTree.js +0 -525
  123. package/dist/cjs/router/runtime/tanstack/rsc/CompositeComponent.js +0 -79
  124. package/dist/cjs/router/runtime/tanstack/rsc/ReplayableStream.js +0 -146
  125. package/dist/cjs/router/runtime/tanstack/rsc/RscNodeRenderer.js +0 -69
  126. package/dist/cjs/router/runtime/tanstack/rsc/client.js +0 -97
  127. package/dist/cjs/router/runtime/tanstack/rsc/createRscProxy.js +0 -145
  128. package/dist/cjs/router/runtime/tanstack/rsc/index.js +0 -46
  129. package/dist/cjs/router/runtime/tanstack/rsc/server.js +0 -250
  130. package/dist/cjs/router/runtime/tanstack/rsc/slotUsageSanitizer.js +0 -69
  131. package/dist/cjs/router/runtime/tanstack/rsc/symbols.js +0 -77
  132. package/dist/cjs/ssr/index.node.js +0 -125
  133. package/dist/cjs/ssr/serverRender/renderToStream/buildTemplate.after.js +0 -88
  134. package/dist/cjs/ssr/serverRender/renderToString/entry.js +0 -200
  135. package/dist/cjs/ssr/serverRender/types.js +0 -40
  136. package/dist/esm/router/cli/code/tanstackTypes.mjs +0 -396
  137. package/dist/esm/router/runtime/tanstack/basepathRewrite.mjs +0 -28
  138. package/dist/esm/router/runtime/tanstack/dataMutation.mjs +0 -305
  139. package/dist/esm/router/runtime/tanstack/hydrationBoundary.mjs +0 -10
  140. package/dist/esm/router/runtime/tanstack/outlet.mjs +0 -17
  141. package/dist/esm/router/runtime/tanstack/plugin.mjs +0 -304
  142. package/dist/esm/router/runtime/tanstack/plugin.node.mjs +0 -234
  143. package/dist/esm/router/runtime/tanstack/prefetchLink.mjs +0 -18
  144. package/dist/esm/router/runtime/tanstack/routeTree.mjs +0 -481
  145. package/dist/esm/router/runtime/tanstack/rsc/ClientSlot.mjs +0 -19
  146. package/dist/esm/router/runtime/tanstack/rsc/CompositeComponent.mjs +0 -41
  147. package/dist/esm/router/runtime/tanstack/rsc/ReplayableStream.mjs +0 -104
  148. package/dist/esm/router/runtime/tanstack/rsc/RscNodeRenderer.mjs +0 -31
  149. package/dist/esm/router/runtime/tanstack/rsc/SlotContext.mjs +0 -17
  150. package/dist/esm/router/runtime/tanstack/rsc/client.mjs +0 -53
  151. package/dist/esm/router/runtime/tanstack/rsc/createRscProxy.mjs +0 -107
  152. package/dist/esm/router/runtime/tanstack/rsc/index.mjs +0 -1
  153. package/dist/esm/router/runtime/tanstack/rsc/server.mjs +0 -200
  154. package/dist/esm/router/runtime/tanstack/rsc/slotUsageSanitizer.mjs +0 -31
  155. package/dist/esm/router/runtime/tanstack/rsc/symbols.mjs +0 -17
  156. package/dist/esm/ssr/index.node.mjs +0 -44
  157. package/dist/esm/ssr/serverRender/renderToStream/buildTemplate.after.mjs +0 -50
  158. package/dist/esm/ssr/serverRender/renderToString/entry.mjs +0 -151
  159. package/dist/esm/ssr/serverRender/types.mjs +0 -1
  160. package/dist/esm-node/router/cli/code/tanstackTypes.mjs +0 -397
  161. package/dist/esm-node/router/runtime/tanstack/basepathRewrite.mjs +0 -29
  162. package/dist/esm-node/router/runtime/tanstack/dataMutation.mjs +0 -306
  163. package/dist/esm-node/router/runtime/tanstack/hydrationBoundary.mjs +0 -11
  164. package/dist/esm-node/router/runtime/tanstack/outlet.mjs +0 -18
  165. package/dist/esm-node/router/runtime/tanstack/plugin.mjs +0 -305
  166. package/dist/esm-node/router/runtime/tanstack/plugin.node.mjs +0 -235
  167. package/dist/esm-node/router/runtime/tanstack/prefetchLink.mjs +0 -19
  168. package/dist/esm-node/router/runtime/tanstack/routeTree.mjs +0 -482
  169. package/dist/esm-node/router/runtime/tanstack/rsc/ClientSlot.mjs +0 -20
  170. package/dist/esm-node/router/runtime/tanstack/rsc/CompositeComponent.mjs +0 -42
  171. package/dist/esm-node/router/runtime/tanstack/rsc/ReplayableStream.mjs +0 -105
  172. package/dist/esm-node/router/runtime/tanstack/rsc/RscNodeRenderer.mjs +0 -32
  173. package/dist/esm-node/router/runtime/tanstack/rsc/SlotContext.mjs +0 -18
  174. package/dist/esm-node/router/runtime/tanstack/rsc/client.mjs +0 -54
  175. package/dist/esm-node/router/runtime/tanstack/rsc/createRscProxy.mjs +0 -108
  176. package/dist/esm-node/router/runtime/tanstack/rsc/index.mjs +0 -2
  177. package/dist/esm-node/router/runtime/tanstack/rsc/server.mjs +0 -201
  178. package/dist/esm-node/router/runtime/tanstack/rsc/slotUsageSanitizer.mjs +0 -32
  179. package/dist/esm-node/router/runtime/tanstack/rsc/symbols.mjs +0 -18
  180. package/dist/esm-node/ssr/index.node.mjs +0 -45
  181. package/dist/esm-node/ssr/serverRender/renderToStream/buildTemplate.after.mjs +0 -51
  182. package/dist/esm-node/ssr/serverRender/renderToString/entry.mjs +0 -152
  183. package/dist/esm-node/ssr/serverRender/types.mjs +0 -2
  184. package/dist/types/router/cli/code/tanstackTypes.d.ts +0 -10
  185. package/dist/types/router/runtime/tanstack/basepathRewrite.d.ts +0 -8
  186. package/dist/types/router/runtime/tanstack/dataMutation.d.ts +0 -29
  187. package/dist/types/router/runtime/tanstack/hydrationBoundary.d.ts +0 -2
  188. package/dist/types/router/runtime/tanstack/outlet.d.ts +0 -2
  189. package/dist/types/router/runtime/tanstack/plugin.d.ts +0 -6
  190. package/dist/types/router/runtime/tanstack/plugin.node.d.ts +0 -6
  191. package/dist/types/router/runtime/tanstack/prefetchLink.d.ts +0 -11
  192. package/dist/types/router/runtime/tanstack/routeTree.d.ts +0 -8
  193. package/dist/types/router/runtime/tanstack/rsc/ClientSlot.d.ts +0 -5
  194. package/dist/types/router/runtime/tanstack/rsc/CompositeComponent.d.ts +0 -3
  195. package/dist/types/router/runtime/tanstack/rsc/ReplayableStream.d.ts +0 -24
  196. package/dist/types/router/runtime/tanstack/rsc/RscNodeRenderer.d.ts +0 -5
  197. package/dist/types/router/runtime/tanstack/rsc/SlotContext.d.ts +0 -11
  198. package/dist/types/router/runtime/tanstack/rsc/client.d.ts +0 -11
  199. package/dist/types/router/runtime/tanstack/rsc/createRscProxy.d.ts +0 -7
  200. package/dist/types/router/runtime/tanstack/rsc/index.d.ts +0 -2
  201. package/dist/types/router/runtime/tanstack/rsc/server.d.ts +0 -14
  202. package/dist/types/router/runtime/tanstack/rsc/slotUsageSanitizer.d.ts +0 -2
  203. package/dist/types/router/runtime/tanstack/rsc/symbols.d.ts +0 -46
@@ -2,13 +2,14 @@ import { jsx } from "react/jsx-runtime";
2
2
  import { storage } from "@modern-js/runtime-utils/node";
3
3
  import { getPathname, parseCookie, parseHeaders, parseQuery } from "@modern-js/runtime-utils/universal/request";
4
4
  import react, { Fragment } from "react";
5
- import { cleanupRouterRuntimeState } from "../../router/runtime/lifecycle.mjs";
5
+ import { getRouterServerSnapshot } from "../../router/runtime/lifecycle.mjs";
6
6
  import { handleRSCRedirect } from "../../router/runtime/rsc-router.mjs";
7
7
  import { getGlobalInternalRuntimeContext, getGlobalRSCRoot } from "../context/index.mjs";
8
8
  import { getInitialContext } from "../context/runtime.mjs";
9
9
  import { getServerPayload } from "../context/serverPayload/index.mjs";
10
10
  import { createRoot } from "../react/index.mjs";
11
11
  import { CHUNK_CSS_PLACEHOLDER } from "./constants.mjs";
12
+ import { withRouterCleanup } from "./routerCleanup.mjs";
12
13
  import { SSRErrors } from "./tracer.mjs";
13
14
  import { getSSRConfigByEntry, getSSRMode } from "./utils.mjs";
14
15
  async function handleRSCRequest(request, Root, context, options, handleRequest) {
@@ -37,6 +38,39 @@ const processRedirect = (headers, status, ctx)=>{
37
38
  headers
38
39
  });
39
40
  };
41
+ const applyRouterSnapshotResult = (context, onError)=>{
42
+ const routerServerSnapshot = getRouterServerSnapshot(context);
43
+ const routerStatusCode = routerServerSnapshot?.statusCode ?? context.routerContext?.statusCode;
44
+ if (routerStatusCode && 200 !== routerStatusCode) context.ssrContext?.response.status(routerStatusCode);
45
+ const errors = Object.values(routerServerSnapshot?.errors || context.routerContext?.errors || {});
46
+ if (errors.length > 0) onError(errors[0], SSRErrors.LOADER_ERROR);
47
+ };
48
+ const createLoaderRedirectResponse = (beforeRenderResult, redirectCtx)=>{
49
+ if (!beforeRenderResult || !isRedirectStatus(beforeRenderResult.status)) return;
50
+ if (beforeRenderResult.headers.has('X-Modernjs-Redirect')) return beforeRenderResult;
51
+ const redirectUrl = beforeRenderResult.headers.get('Location') || '/';
52
+ return processRedirect(new Headers({
53
+ Location: redirectUrl
54
+ }), beforeRenderResult.status, redirectCtx);
55
+ };
56
+ const renderRequest = async (request, Root, context, options, handleRequest, enableRsc)=>{
57
+ if (enableRsc) return handleRSCRequest(request, Root, context, options, handleRequest);
58
+ return handleRequest(request, Root, {
59
+ ...options,
60
+ runtimeContext: context
61
+ });
62
+ };
63
+ const finalizeRenderResponse = (response, responseProxy, redirectCtx, routerCleanup)=>{
64
+ if (-1 !== responseProxy.status && isRedirectStatus(responseProxy.status) && responseProxy.headers.Location) return processRedirect(new Headers(responseProxy.headers), responseProxy.status, redirectCtx);
65
+ Object.entries(responseProxy.headers).forEach(([key, value])=>{
66
+ response.headers.set(key, value);
67
+ });
68
+ if (-1 !== responseProxy.status) return routerCleanup.deferUntilBodyDone(new Response(response.body, {
69
+ status: responseProxy.status,
70
+ headers: response.headers
71
+ }));
72
+ return routerCleanup.deferUntilBodyDone(response);
73
+ };
40
74
  function createSSRContext(request, options) {
41
75
  const { config, loaderContext, onError, onTiming, locals, resource, params, responseProxy, reporter } = options;
42
76
  const { nonce, useJsonScript } = config;
@@ -132,41 +166,20 @@ const createRequestHandler = async (handleRequest, createRequestOptions)=>{
132
166
  isRSCNavigation: 'true' === request.headers.get('x-rsc-tree'),
133
167
  basename: ssrContext.baseUrl || '/'
134
168
  };
135
- try {
169
+ return withRouterCleanup(context, options.onError, async (routerCleanup)=>{
136
170
  const beforeRenderResult = await runBeforeRender(context);
137
- const routerServerSnapshot = context.routerServerSnapshot;
138
- const routerStatusCode = routerServerSnapshot?.statusCode ?? context.routerContext?.statusCode;
139
- if (routerStatusCode && 200 !== routerStatusCode) context.ssrContext?.response.status(routerStatusCode);
140
- const errors = Object.values(routerServerSnapshot?.errors || context.routerContext?.errors || {});
141
- if (errors.length > 0) options.onError(errors[0], SSRErrors.LOADER_ERROR);
142
- if ("u" > typeof Response && beforeRenderResult instanceof Response && isRedirectStatus(beforeRenderResult.status)) {
143
- if (beforeRenderResult.headers.has('X-Modernjs-Redirect')) return beforeRenderResult;
144
- const redirectUrl = beforeRenderResult.headers.get('Location') || '/';
145
- return processRedirect(new Headers({
146
- Location: redirectUrl
147
- }), beforeRenderResult.status, redirectCtx);
171
+ applyRouterSnapshotResult(context, options.onError);
172
+ if ("u" > typeof Response) {
173
+ const redirectResponse = createLoaderRedirectResponse(beforeRenderResult, redirectCtx);
174
+ if (redirectResponse) return redirectResponse;
148
175
  }
149
176
  if (!createRequestOptions?.enableRsc) {
150
177
  const { htmlTemplate } = options.resource;
151
178
  options.resource.htmlTemplate = htmlTemplate.replace('</head>', `${CHUNK_CSS_PLACEHOLDER}</head>`);
152
179
  }
153
- let response;
154
- response = createRequestOptions?.enableRsc ? await handleRSCRequest(request, Root, context, options, handleRequest) : await handleRequest(request, Root, {
155
- ...options,
156
- runtimeContext: context
157
- });
158
- if (-1 !== responseProxy.status && isRedirectStatus(responseProxy.status) && responseProxy.headers.Location) return processRedirect(new Headers(responseProxy.headers), responseProxy.status, redirectCtx);
159
- Object.entries(responseProxy.headers).forEach(([key, value])=>{
160
- response.headers.set(key, value);
161
- });
162
- if (-1 !== responseProxy.status) return new Response(response.body, {
163
- status: responseProxy.status,
164
- headers: response.headers
165
- });
166
- return response;
167
- } finally{
168
- await cleanupRouterRuntimeState(context);
169
- }
180
+ const response = await renderRequest(request, Root, context, options, handleRequest, !!createRequestOptions?.enableRsc);
181
+ return finalizeRenderResponse(response, responseProxy, redirectCtx, routerCleanup);
182
+ });
170
183
  });
171
184
  };
172
185
  return requestHandler;
@@ -0,0 +1,66 @@
1
+ import { getRouterRuntimeState } from "../../router/runtime/lifecycle.mjs";
2
+ const ROUTER_CLEANUP_ERROR = 'An error occurs during router runtime cleanup';
3
+ async function withRouterCleanup(runtimeContext, onError, callback) {
4
+ const routerCleanup = createRouterCleanup(runtimeContext, onError);
5
+ try {
6
+ return await callback(routerCleanup);
7
+ } finally{
8
+ if (!routerCleanup.deferred) await routerCleanup.run();
9
+ }
10
+ }
11
+ function createRouterCleanup(runtimeContext, onError) {
12
+ let deferred = false;
13
+ let finished = false;
14
+ const run = async ()=>{
15
+ if (finished) return;
16
+ finished = true;
17
+ try {
18
+ await getRouterRuntimeState(runtimeContext)?.cleanup?.();
19
+ } catch (error) {
20
+ onError(error, ROUTER_CLEANUP_ERROR);
21
+ }
22
+ };
23
+ const deferUntilBodyDone = (response)=>{
24
+ const { body } = response;
25
+ if (!body || body.locked) return response;
26
+ deferred = true;
27
+ const reader = body.getReader();
28
+ const wrappedBody = new ReadableStream({
29
+ async pull (controller) {
30
+ let result;
31
+ try {
32
+ result = await reader.read();
33
+ } catch (error) {
34
+ controller.error(error);
35
+ await run();
36
+ return;
37
+ }
38
+ if (result.done) {
39
+ controller.close();
40
+ await run();
41
+ return;
42
+ }
43
+ controller.enqueue(result.value);
44
+ },
45
+ async cancel (reason) {
46
+ try {
47
+ await reader.cancel(reason);
48
+ } catch {}
49
+ await run();
50
+ }
51
+ });
52
+ return new Response(wrappedBody, {
53
+ status: response.status,
54
+ statusText: response.statusText,
55
+ headers: response.headers
56
+ });
57
+ };
58
+ return {
59
+ get deferred () {
60
+ return deferred;
61
+ },
62
+ run,
63
+ deferUntilBodyDone
64
+ };
65
+ }
66
+ export { ROUTER_CLEANUP_ERROR, createRouterCleanup, withRouterCleanup };
@@ -1,3 +1,6 @@
1
+ import { getRouterMatchedRouteIds } from "../../router/runtime/lifecycle.mjs";
2
+ import { CHUNK_JS_PLACEHOLDER } from "./constants.mjs";
3
+ import { safeReplace } from "./utils.mjs";
1
4
  function getScriptTags(template) {
2
5
  const scriptRegExp = /<script\b[^>]*\bsrc=(["'])(.*?)\1[^>]*><\/script>/g;
3
6
  return Array.from(template.matchAll(scriptRegExp)).map((match)=>({
@@ -15,6 +18,42 @@ function isEntryScript(src, entryName, asyncEntry) {
15
18
  const prefix = asyncEntry ? `async-${entryName}` : entryName;
16
19
  return basename === `${prefix}.js` || basename.startsWith(`${prefix}.`) || basename.startsWith(`${prefix}-`);
17
20
  }
21
+ const dedupeByUrl = (chunks)=>{
22
+ const seen = new Set();
23
+ return chunks.filter((chunk)=>{
24
+ if (void 0 === chunk.url || '' === chunk.url || seen.has(chunk.url)) return false;
25
+ seen.add(chunk.url);
26
+ return true;
27
+ });
28
+ };
29
+ const isAsyncEntryScriptChunk = (chunk, entryName)=>{
30
+ if (void 0 === chunk.url || !chunk.url.endsWith('.js')) return false;
31
+ const asyncEntryName = `async-${entryName}`;
32
+ const filename = chunk.filename ?? chunk.url;
33
+ const basename = filename.split('/').pop() ?? filename;
34
+ return basename === `${asyncEntryName}.js` || basename.startsWith(`${asyncEntryName}.`) || basename.startsWith(`${asyncEntryName}-`);
35
+ };
36
+ function getRouteAssets(runtimeContext, routeManifest = runtimeContext.routeManifest) {
37
+ return routeManifest?.routeAssets;
38
+ }
39
+ function getMatchedRouteAssets(runtimeContext, routeManifest) {
40
+ const routeAssets = getRouteAssets(runtimeContext, routeManifest);
41
+ if (void 0 === routeAssets) return [];
42
+ const matchedRouteIds = getRouterMatchedRouteIds(runtimeContext) ?? [];
43
+ return matchedRouteIds.flatMap((routeId)=>routeAssets[routeId]?.assets ?? []);
44
+ }
45
+ const orderHydrationScriptChunks = ({ asyncEntryChunks, collectedChunks, matchedRouteChunks, entryName })=>{
46
+ const asyncEntryScriptChunks = [];
47
+ const asyncEntryDependencyChunks = [];
48
+ for (const chunk of asyncEntryChunks)if (isAsyncEntryScriptChunk(chunk, entryName)) asyncEntryScriptChunks.push(chunk);
49
+ else asyncEntryDependencyChunks.push(chunk);
50
+ return dedupeByUrl([
51
+ ...asyncEntryDependencyChunks,
52
+ ...collectedChunks,
53
+ ...matchedRouteChunks,
54
+ ...asyncEntryScriptChunks
55
+ ]);
56
+ };
18
57
  function injectBeforeHydrationEntryScript(template, scripts, entryName = 'index') {
19
58
  if ('' === scripts) return template;
20
59
  const scriptTags = getScriptTags(template);
@@ -22,4 +61,24 @@ function injectBeforeHydrationEntryScript(template, scripts, entryName = 'index'
22
61
  if (void 0 === target) return template;
23
62
  return `${template.slice(0, target.index)}${scripts}${template.slice(target.index)}`;
24
63
  }
25
- export { injectBeforeHydrationEntryScript };
64
+ function replaceChunkJsPlaceholder(template, scripts, entryName, placeholder = CHUNK_JS_PLACEHOLDER) {
65
+ if ('' === scripts) return safeReplace(template, placeholder, '');
66
+ const withoutPlaceholder = safeReplace(template, placeholder, '');
67
+ const withEarlyScripts = injectBeforeHydrationEntryScript(withoutPlaceholder, scripts, entryName);
68
+ if (withEarlyScripts !== withoutPlaceholder) return withEarlyScripts;
69
+ return safeReplace(template, placeholder, scripts);
70
+ }
71
+ function createRouteHydrationScriptTags(runtimeContext, entryName, options = {}) {
72
+ const { nonce, template } = options;
73
+ const routeAssets = getRouteAssets(runtimeContext);
74
+ if (void 0 === routeAssets) return '';
75
+ const matchedRouteIds = getRouterMatchedRouteIds(runtimeContext) ?? [];
76
+ const assetEntries = [
77
+ ...matchedRouteIds.map((routeId)=>routeAssets[routeId]),
78
+ routeAssets[`async-${entryName}`]
79
+ ].filter((entry)=>void 0 !== entry);
80
+ const jsAssets = Array.from(new Set(assetEntries.flatMap((entry)=>(entry.assets ?? []).filter((asset)=>asset.endsWith('.js')))));
81
+ const nonceAttr = void 0 === nonce || '' === nonce ? '' : ` nonce="${nonce}"`;
82
+ return jsAssets.filter((asset)=>template?.includes(asset) !== true).map((asset)=>`<script src=${asset}${nonceAttr}></script>`).join(' ');
83
+ }
84
+ export { createRouteHydrationScriptTags, getMatchedRouteAssets, injectBeforeHydrationEntryScript, orderHydrationScriptChunks, replaceChunkJsPlaceholder };
@@ -1,8 +1,8 @@
1
1
  import { serializeJson } from "@modern-js/runtime-utils/node";
2
- import { getRouterHydrationScripts, getRouterMatchedRouteIds } from "../../../router/runtime/lifecycle.mjs";
2
+ import { getRouterHydrationScripts } from "../../../router/runtime/lifecycle.mjs";
3
3
  import { SSR_DATA_JSON_ID } from "../../constants.mjs";
4
4
  import { SSR_DATA_PLACEHOLDER } from "../constants.mjs";
5
- import { injectBeforeHydrationEntryScript } from "../scriptOrder.mjs";
5
+ import { createRouteHydrationScriptTags, replaceChunkJsPlaceholder } from "../scriptOrder.mjs";
6
6
  import { buildHtml } from "../shared.mjs";
7
7
  import { attributesToString, safeReplace } from "../utils.mjs";
8
8
  function buildShellAfterTemplate(afterAppTemplate, options) {
@@ -19,24 +19,12 @@ function buildShellAfterTemplate(afterAppTemplate, options) {
19
19
  (template)=>injectJs(template, entryName, config.nonce)
20
20
  ];
21
21
  async function injectJs(template, entryName, nonce) {
22
- const { routeManifest } = runtimeContext;
23
- if (!routeManifest) return template;
24
- const { routeAssets } = routeManifest;
25
- if (!routeAssets) return template;
26
- const matchedRouteIds = getRouterMatchedRouteIds(runtimeContext) ?? [];
27
- const assetEntries = [
28
- ...matchedRouteIds.map((routeId)=>routeAssets[routeId]),
29
- routeAssets[`async-${entryName}`]
30
- ].filter(Boolean);
31
- const jsAssets = Array.from(new Set(assetEntries.flatMap((entry)=>(entry.assets ?? []).filter((asset)=>asset.endsWith('.js')))));
32
- const nonceAttr = nonce ? ` nonce="${nonce}"` : '';
33
- const jsChunkStr = jsAssets.filter((asset)=>!template.includes(asset)).map((asset)=>`<script src=${asset}${nonceAttr}></script>`).join(' ');
34
- if (jsChunkStr) {
35
- const withoutPlaceholder = safeReplace(template, '<!--<?- chunksMap.js ?>-->', '');
36
- const withEarlyScripts = injectBeforeHydrationEntryScript(withoutPlaceholder, jsChunkStr, entryName);
37
- return withEarlyScripts !== withoutPlaceholder ? withEarlyScripts : safeReplace(template, '<!--<?- chunksMap.js ?>-->', jsChunkStr);
38
- }
39
- return template;
22
+ const jsChunkStr = createRouteHydrationScriptTags(runtimeContext, entryName, {
23
+ nonce,
24
+ template
25
+ });
26
+ if (!jsChunkStr) return template;
27
+ return replaceChunkJsPlaceholder(template, jsChunkStr, entryName);
40
28
  }
41
29
  return buildHtml(afterAppTemplate, callbacks);
42
30
  }
@@ -22,12 +22,15 @@ function isPromiseLike(value) {
22
22
  return !!value && 'function' == typeof value.then;
23
23
  }
24
24
  function toErrorInfo(error) {
25
+ if ('production' === process.env.NODE_ENV) return {
26
+ message: 'Unexpected Server Error'
27
+ };
25
28
  if (error && 'object' == typeof error) {
26
29
  const maybeMsg = error.message;
27
30
  const maybeStack = error.stack;
28
31
  return {
29
32
  message: 'string' == typeof maybeMsg ? maybeMsg : String(maybeMsg ?? error),
30
- stack: 'production' !== process.env.NODE_ENV ? maybeStack : void 0
33
+ stack: maybeStack
31
34
  };
32
35
  }
33
36
  return {
@@ -4,9 +4,9 @@ import server from "react-dom/server";
4
4
  import { RenderLevel } from "../../constants.mjs";
5
5
  import { getGlobalInternalRuntimeContext } from "../../context/index.mjs";
6
6
  import { wrapRuntimeContextProvider } from "../../react/wrapper.mjs";
7
- import { CHUNK_CSS_PLACEHOLDER, CHUNK_JS_PLACEHOLDER, HTML_PLACEHOLDER, SSR_DATA_PLACEHOLDER } from "../constants.mjs";
7
+ import { CHUNK_CSS_PLACEHOLDER, HTML_PLACEHOLDER, SSR_DATA_PLACEHOLDER } from "../constants.mjs";
8
8
  import { createReplaceHelemt, getHelmetData } from "../helmet.mjs";
9
- import { injectBeforeHydrationEntryScript } from "../scriptOrder.mjs";
9
+ import { replaceChunkJsPlaceholder } from "../scriptOrder.mjs";
10
10
  import { buildHtml } from "../shared.mjs";
11
11
  import { SSRErrors, SSRTimings } from "../tracer.mjs";
12
12
  import { getSSRConfigByEntry, safeReplace } from "../utils.mjs";
@@ -98,13 +98,7 @@ function createReplaceSSRDataScript(data) {
98
98
  return (template)=>safeReplace(template, SSR_DATA_PLACEHOLDER, data);
99
99
  }
100
100
  function createReplaceChunkJs(js, entryName) {
101
- return (template)=>{
102
- if (!js) return safeReplace(template, CHUNK_JS_PLACEHOLDER, '');
103
- const withoutPlaceholder = safeReplace(template, CHUNK_JS_PLACEHOLDER, '');
104
- const withEarlyScripts = injectBeforeHydrationEntryScript(withoutPlaceholder, js, entryName);
105
- if (withEarlyScripts !== withoutPlaceholder) return withEarlyScripts;
106
- return safeReplace(template, CHUNK_JS_PLACEHOLDER, js);
107
- };
101
+ return (template)=>replaceChunkJsPlaceholder(template, js, entryName);
108
102
  }
109
103
  function createReplaceChunkCss(css) {
110
104
  return (template)=>safeReplace(template, CHUNK_CSS_PLACEHOLDER, css);
@@ -1,39 +1,21 @@
1
1
  import { ChunkExtractor } from "@loadable/server";
2
- import { getRouterMatchedRouteIds } from "../../../router/runtime/lifecycle.mjs";
3
2
  import { createFederatedCssLinks } from "../federatedCss.mjs";
3
+ import { getMatchedRouteAssets, orderHydrationScriptChunks } from "../scriptOrder.mjs";
4
4
  import { attributesToString, checkIsNode } from "../utils.mjs";
5
5
  const extname = (uri)=>{
6
6
  if ('string' != typeof uri || !uri.includes('.')) return '';
7
7
  return `.${uri?.split('.').pop()}` || '';
8
8
  };
9
9
  const generateChunks = (chunks, ext)=>chunks.filter((chunk)=>Boolean(chunk.url)).filter((chunk)=>extname(chunk.url).slice(1) === ext);
10
- const dedupeChunksByUrl = (chunks)=>{
11
- const seen = new Set();
12
- return chunks.filter((chunk)=>{
13
- if (!chunk.url || seen.has(chunk.url)) return false;
14
- seen.add(chunk.url);
15
- return true;
10
+ const routeAssetToChunk = (asset)=>({
11
+ chunk: asset,
12
+ filename: asset.replace(/^\//, ''),
13
+ linkType: 'preload',
14
+ path: asset,
15
+ scriptType: asset.endsWith('.css') ? 'style' : "script",
16
+ type: 'routeAsset',
17
+ url: asset
16
18
  });
17
- };
18
- const isAsyncEntryScriptChunk = (chunk, entryName)=>{
19
- if (!chunk.url?.endsWith('.js')) return false;
20
- const asyncEntryName = `async-${entryName}`;
21
- const filename = chunk.filename || chunk.url;
22
- const basename = filename.split('/').pop() || filename;
23
- return basename === `${asyncEntryName}.js` || basename.startsWith(`${asyncEntryName}.`) || basename.startsWith(`${asyncEntryName}-`);
24
- };
25
- const orderHydrationScriptChunks = ({ asyncEntryChunks, collectedChunks, matchedRouteChunks, entryName })=>{
26
- const asyncEntryScriptChunks = [];
27
- const asyncEntryDependencyChunks = [];
28
- for (const chunk of asyncEntryChunks)if (isAsyncEntryScriptChunk(chunk, entryName)) asyncEntryScriptChunks.push(chunk);
29
- else asyncEntryDependencyChunks.push(chunk);
30
- return dedupeChunksByUrl([
31
- ...asyncEntryDependencyChunks,
32
- ...collectedChunks,
33
- ...matchedRouteChunks,
34
- ...asyncEntryScriptChunks
35
- ]);
36
- };
37
19
  const checkIsInline = (chunk, enableInline)=>{
38
20
  if ('production' !== process.env.NODE_ENV) return false;
39
21
  if (enableInline instanceof RegExp) return enableInline.test(chunk.url);
@@ -52,17 +34,8 @@ class LoadableCollector {
52
34
  }
53
35
  getMatchedRouteChunks() {
54
36
  const { routeManifest, runtimeContext } = this.options;
55
- const routeAssets = routeManifest?.routeAssets;
56
- if (!routeAssets) return [];
57
- const matchedRouteIds = getRouterMatchedRouteIds(runtimeContext) ?? [];
58
- return matchedRouteIds.flatMap((routeId)=>{
59
- const routeAsset = routeAssets[routeId];
60
- return (routeAsset?.assets ?? []).map((asset)=>({
61
- filename: asset.replace(/^\//, ''),
62
- path: asset,
63
- url: asset
64
- }));
65
- });
37
+ if (!routeManifest) return [];
38
+ return getMatchedRouteAssets(runtimeContext, routeManifest).map(routeAssetToChunk);
66
39
  }
67
40
  collect(comopnent) {
68
41
  const { stats, entryName } = this.options;
@@ -1,5 +1,5 @@
1
1
  import { serializeJson } from "@modern-js/runtime-utils/node";
2
- import { getRouterHydrationScripts } from "../../../router/runtime/lifecycle.mjs";
2
+ import { getRouterHydrationScripts, getRouterServerSnapshot } from "../../../router/runtime/lifecycle.mjs";
3
3
  import { ROUTER_DATA_JSON_ID, SSR_DATA_JSON_ID } from "../../constants.mjs";
4
4
  import { attributesToString, serializeErrors } from "../utils.mjs";
5
5
  function _check_private_redeclaration(obj, privateCollection) {
@@ -89,7 +89,7 @@ function getSSRData() {
89
89
  }
90
90
  function getRouterData() {
91
91
  const { routerContext, runtimeContext } = _class_private_field_get(this, _options);
92
- const snapshotRouterData = runtimeContext.routerServerSnapshot?.routerData;
92
+ const snapshotRouterData = getRouterServerSnapshot(runtimeContext)?.routerData;
93
93
  if (snapshotRouterData) return {
94
94
  loaderData: snapshotRouterData.loaderData,
95
95
  errors: serializeErrors(snapshotRouterData.errors || null)
@@ -12,17 +12,40 @@ function serializeErrors(errors) {
12
12
  if (!errors) return null;
13
13
  const entries = Object.entries(errors);
14
14
  const serialized = {};
15
- for (const [key, val] of entries)if (isRouteErrorResponse(val)) serialized[key] = {
16
- ...val,
17
- __type: 'RouteErrorResponse'
15
+ for (const [key, val] of entries)if (isRouteErrorResponse(val)) serialized[key] = serializeRouteErrorResponse(val);
16
+ else if (val instanceof Error) serialized[key] = serializeError(val);
17
+ else serialized[key] = val;
18
+ return serialized;
19
+ }
20
+ function shouldRedactServerError() {
21
+ return 'development' !== process.env.NODE_ENV && 'test' !== process.env.NODE_ENV;
22
+ }
23
+ function serializeError(error) {
24
+ if (shouldRedactServerError()) return {
25
+ message: 'Unexpected Server Error',
26
+ stack: void 0,
27
+ __type: 'Error'
18
28
  };
19
- else if (val instanceof Error) serialized[key] = {
20
- message: val.message,
21
- stack: val.stack,
29
+ return {
30
+ message: error.message,
31
+ stack: error.stack,
22
32
  __type: 'Error'
23
33
  };
24
- else serialized[key] = val;
25
- return serialized;
34
+ }
35
+ function serializeRouteErrorResponse(error) {
36
+ if (!isRouteErrorResponse(error)) return error;
37
+ if (error.status >= 500 && shouldRedactServerError()) return {
38
+ status: error.status,
39
+ statusText: 'Internal Server Error',
40
+ data: 'Unexpected Server Error',
41
+ __type: 'RouteErrorResponse'
42
+ };
43
+ return {
44
+ status: error.status,
45
+ statusText: error.statusText,
46
+ data: error.data,
47
+ __type: 'RouteErrorResponse'
48
+ };
26
49
  }
27
50
  function getSSRConfigByEntry(entryName, ssr, ssrByEntries) {
28
51
  if (ssrByEntries?.[entryName]) return ssrByEntries[entryName];