@bleedingdev/modern-js-runtime 3.9.0-ultramodern.2 → 3.9.0-ultramodern.21

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 (213) hide show
  1. package/dist/cjs/cli/code.js +3 -1
  2. package/dist/cjs/cli/ssr/index.js +2 -74
  3. package/dist/cjs/cli/ssr/loadable-bundler-plugin.js +2 -0
  4. package/dist/cjs/cli/template.server.js +1 -2
  5. package/dist/cjs/core/browser/hydrate.js +9 -10
  6. package/dist/cjs/core/browser/index.js +4 -5
  7. package/dist/cjs/core/context/index.js +12 -45
  8. package/dist/cjs/core/context/public.js +4 -7
  9. package/dist/cjs/core/context/runtime.js +10 -4
  10. package/dist/cjs/core/index.js +3 -3
  11. package/dist/cjs/core/plugin/index.js +2 -2
  12. package/dist/cjs/core/react/index.js +3 -3
  13. package/dist/cjs/core/react/wrapper.js +23 -67
  14. package/dist/cjs/core/server/helmet.js +5 -4
  15. package/dist/cjs/core/server/requestHandler.js +6 -7
  16. package/dist/cjs/core/server/requestResponse.js +4 -4
  17. package/dist/cjs/core/server/routerCleanup.js +2 -2
  18. package/dist/cjs/core/server/shared.js +171 -4
  19. package/dist/cjs/core/server/stream/afterTemplate.js +21 -16
  20. package/dist/cjs/core/server/stream/beforeTemplate.js +37 -28
  21. package/dist/cjs/core/server/stream/beforeTemplate.worker.js +30 -23
  22. package/dist/cjs/core/server/stream/createReadableStream.js +222 -125
  23. package/dist/cjs/core/server/stream/createReadableStream.worker.js +171 -90
  24. package/dist/cjs/core/server/stream/deferredScript.js +3 -3
  25. package/dist/cjs/core/server/stream/shared.js +6 -2
  26. package/dist/cjs/core/server/string/index.js +104 -66
  27. package/dist/cjs/core/server/string/loadable.js +38 -23
  28. package/dist/cjs/core/server/string/ssrData.js +5 -12
  29. package/dist/cjs/core/server/utils.js +1 -2
  30. package/dist/cjs/document/cli/index.js +14 -5
  31. package/dist/cjs/exports/head.js +7 -14
  32. package/dist/cjs/internal.js +2 -2
  33. package/dist/cjs/router/cli/code/nestedRoutes.js +1 -2
  34. package/dist/cjs/router/cli/code/templates.js +1 -1
  35. package/dist/cjs/router/cli/code/utils.js +2 -2
  36. package/dist/cjs/router/runtime/DeferredDataScripts.node.js +10 -9
  37. package/dist/cjs/router/runtime/PrefetchLink.js +69 -125
  38. package/dist/cjs/router/runtime/hooks.js +13 -2
  39. package/dist/cjs/router/runtime/internal.js +7 -45
  40. package/dist/cjs/router/runtime/plugin.js +19 -34
  41. package/dist/cjs/router/runtime/plugin.node.js +9 -37
  42. package/dist/cjs/router/runtime/redirect.js +1 -1
  43. package/dist/esm/cli/code.mjs +3 -1
  44. package/dist/esm/cli/ssr/index.mjs +3 -72
  45. package/dist/esm/cli/ssr/loadable-bundler-plugin.mjs +2 -0
  46. package/dist/esm/cli/template.server.mjs +1 -2
  47. package/dist/esm/core/browser/hydrate.mjs +10 -11
  48. package/dist/esm/core/browser/index.mjs +1 -2
  49. package/dist/esm/core/context/index.mjs +2 -5
  50. package/dist/esm/core/context/public.mjs +1 -5
  51. package/dist/esm/core/context/runtime.mjs +6 -3
  52. package/dist/esm/core/index.mjs +1 -1
  53. package/dist/esm/core/plugin/index.mjs +1 -1
  54. package/dist/esm/core/react/index.mjs +1 -1
  55. package/dist/esm/core/react/wrapper.mjs +20 -67
  56. package/dist/esm/core/server/helmet.mjs +5 -4
  57. package/dist/esm/core/server/requestHandler.mjs +1 -2
  58. package/dist/esm/core/server/requestResponse.mjs +3 -3
  59. package/dist/esm/core/server/routerCleanup.mjs +1 -1
  60. package/dist/esm/core/server/shared.mjs +153 -1
  61. package/dist/esm/core/server/stream/afterTemplate.mjs +23 -18
  62. package/dist/esm/core/server/stream/beforeTemplate.mjs +40 -31
  63. package/dist/esm/core/server/stream/beforeTemplate.worker.mjs +33 -26
  64. package/dist/esm/core/server/stream/createReadableStream.mjs +220 -123
  65. package/dist/esm/core/server/stream/createReadableStream.worker.mjs +161 -90
  66. package/dist/esm/core/server/stream/deferredScript.mjs +3 -3
  67. package/dist/esm/core/server/stream/shared.mjs +4 -3
  68. package/dist/esm/core/server/string/index.mjs +106 -68
  69. package/dist/esm/core/server/string/loadable.mjs +38 -23
  70. package/dist/esm/core/server/string/ssrData.mjs +5 -12
  71. package/dist/esm/core/server/utils.mjs +1 -2
  72. package/dist/esm/document/cli/index.mjs +12 -6
  73. package/dist/esm/exports/head.mjs +7 -14
  74. package/dist/esm/internal.mjs +1 -1
  75. package/dist/esm/router/cli/code/nestedRoutes.mjs +1 -2
  76. package/dist/esm/router/cli/code/templates.mjs +1 -1
  77. package/dist/esm/router/cli/code/utils.mjs +2 -2
  78. package/dist/esm/router/runtime/DeferredDataScripts.node.mjs +10 -9
  79. package/dist/esm/router/runtime/PrefetchLink.mjs +68 -124
  80. package/dist/esm/router/runtime/hooks.mjs +9 -1
  81. package/dist/esm/router/runtime/internal.mjs +2 -33
  82. package/dist/esm/router/runtime/plugin.mjs +10 -25
  83. package/dist/esm/router/runtime/plugin.node.mjs +3 -31
  84. package/dist/esm/router/runtime/redirect.mjs +1 -1
  85. package/dist/esm-node/cli/code.mjs +3 -1
  86. package/dist/esm-node/cli/ssr/index.mjs +3 -72
  87. package/dist/esm-node/cli/ssr/loadable-bundler-plugin.mjs +2 -0
  88. package/dist/esm-node/cli/template.server.mjs +1 -2
  89. package/dist/esm-node/core/browser/hydrate.mjs +10 -11
  90. package/dist/esm-node/core/browser/index.mjs +1 -2
  91. package/dist/esm-node/core/context/index.mjs +2 -5
  92. package/dist/esm-node/core/context/public.mjs +1 -5
  93. package/dist/esm-node/core/context/runtime.mjs +6 -3
  94. package/dist/esm-node/core/index.mjs +1 -1
  95. package/dist/esm-node/core/plugin/index.mjs +1 -1
  96. package/dist/esm-node/core/react/index.mjs +1 -1
  97. package/dist/esm-node/core/react/wrapper.mjs +20 -67
  98. package/dist/esm-node/core/server/helmet.mjs +5 -4
  99. package/dist/esm-node/core/server/requestHandler.mjs +1 -2
  100. package/dist/esm-node/core/server/requestResponse.mjs +3 -3
  101. package/dist/esm-node/core/server/routerCleanup.mjs +1 -1
  102. package/dist/esm-node/core/server/shared.mjs +153 -1
  103. package/dist/esm-node/core/server/stream/afterTemplate.mjs +23 -18
  104. package/dist/esm-node/core/server/stream/beforeTemplate.mjs +40 -31
  105. package/dist/esm-node/core/server/stream/beforeTemplate.worker.mjs +33 -26
  106. package/dist/esm-node/core/server/stream/createReadableStream.mjs +220 -123
  107. package/dist/esm-node/core/server/stream/createReadableStream.worker.mjs +161 -90
  108. package/dist/esm-node/core/server/stream/deferredScript.mjs +3 -3
  109. package/dist/esm-node/core/server/stream/shared.mjs +4 -3
  110. package/dist/esm-node/core/server/string/index.mjs +106 -68
  111. package/dist/esm-node/core/server/string/loadable.mjs +38 -23
  112. package/dist/esm-node/core/server/string/ssrData.mjs +5 -12
  113. package/dist/esm-node/core/server/utils.mjs +1 -2
  114. package/dist/esm-node/document/cli/index.mjs +12 -6
  115. package/dist/esm-node/exports/head.mjs +7 -14
  116. package/dist/esm-node/internal.mjs +1 -1
  117. package/dist/esm-node/router/cli/code/nestedRoutes.mjs +1 -2
  118. package/dist/esm-node/router/cli/code/templates.mjs +1 -1
  119. package/dist/esm-node/router/cli/code/utils.mjs +2 -2
  120. package/dist/esm-node/router/runtime/DeferredDataScripts.node.mjs +10 -9
  121. package/dist/esm-node/router/runtime/PrefetchLink.mjs +68 -124
  122. package/dist/esm-node/router/runtime/hooks.mjs +9 -1
  123. package/dist/esm-node/router/runtime/internal.mjs +2 -33
  124. package/dist/esm-node/router/runtime/plugin.mjs +10 -25
  125. package/dist/esm-node/router/runtime/plugin.node.mjs +3 -31
  126. package/dist/esm-node/router/runtime/redirect.mjs +1 -1
  127. package/dist/types/cli/ssr/index.d.ts +0 -3
  128. package/dist/types/core/context/index.d.ts +4 -6
  129. package/dist/types/core/context/public.d.ts +1 -23
  130. package/dist/types/core/context/runtime.d.ts +26 -2
  131. package/dist/types/core/index.d.ts +1 -1
  132. package/dist/types/core/react/wrapper.d.ts +7 -1
  133. package/dist/types/core/server/helmet.d.ts +4 -5
  134. package/dist/types/core/server/requestHandler.d.ts +3 -3
  135. package/dist/types/core/server/requestResponse.d.ts +1 -1
  136. package/dist/types/core/server/routerCleanup.d.ts +1 -1
  137. package/dist/types/core/server/shared.d.ts +24 -1
  138. package/dist/types/core/server/stream/afterTemplate.d.ts +2 -1
  139. package/dist/types/core/server/stream/beforeTemplate.d.ts +4 -1
  140. package/dist/types/core/server/stream/beforeTemplate.worker.d.ts +4 -1
  141. package/dist/types/core/server/stream/shared.d.ts +16 -2
  142. package/dist/types/core/server/string/loadable.d.ts +6 -3
  143. package/dist/types/core/server/string/ssrData.d.ts +2 -1
  144. package/dist/types/core/server/string/types.d.ts +1 -5
  145. package/dist/types/core/server/tracer.d.ts +1 -1
  146. package/dist/types/core/server/utils.d.ts +1 -1
  147. package/dist/types/core/types.d.ts +1 -2
  148. package/dist/types/document/cli/index.d.ts +1 -0
  149. package/dist/types/exports/head.d.ts +2 -2
  150. package/dist/types/internal.d.ts +1 -1
  151. package/dist/types/router/runtime/PrefetchLink.d.ts +27 -2
  152. package/dist/types/router/runtime/hooks.d.ts +19 -2
  153. package/dist/types/router/runtime/internal.d.ts +4 -21
  154. package/dist/types/router/runtime/types.d.ts +2 -43
  155. package/package.json +18 -46
  156. package/rslib.config.mts +3 -0
  157. package/rstest.config.mts +28 -2
  158. package/dist/cjs/boundary-debugger/index.js +0 -317
  159. package/dist/cjs/core/context/extensions.js +0 -74
  160. package/dist/cjs/core/context/helmetContext.js +0 -54
  161. package/dist/cjs/core/server/federatedCss.js +0 -58
  162. package/dist/cjs/core/server/scriptOrder.js +0 -140
  163. package/dist/cjs/module-federation/consume-surface.js +0 -199
  164. package/dist/cjs/module-federation/distributed-ssr.js +0 -135
  165. package/dist/cjs/module-federation/index.js +0 -316
  166. package/dist/cjs/module-federation/last-known-good.js +0 -157
  167. package/dist/cjs/module-federation/manifest-recovery-runtime-plugin.js +0 -129
  168. package/dist/cjs/module-federation/surface-resolution-types.js +0 -61
  169. package/dist/cjs/router/runtime/lifecycle.js +0 -167
  170. package/dist/cjs/router/runtime/provider.js +0 -153
  171. package/dist/cjs/rsc/server.worker.js +0 -62
  172. package/dist/esm/boundary-debugger/index.mjs +0 -277
  173. package/dist/esm/core/context/extensions.mjs +0 -33
  174. package/dist/esm/core/context/helmetContext.mjs +0 -13
  175. package/dist/esm/core/server/federatedCss.mjs +0 -20
  176. package/dist/esm/core/server/scriptOrder.mjs +0 -90
  177. package/dist/esm/module-federation/consume-surface.mjs +0 -158
  178. package/dist/esm/module-federation/distributed-ssr.mjs +0 -82
  179. package/dist/esm/module-federation/index.mjs +0 -115
  180. package/dist/esm/module-federation/last-known-good.mjs +0 -113
  181. package/dist/esm/module-federation/manifest-recovery-runtime-plugin.mjs +0 -89
  182. package/dist/esm/module-federation/surface-resolution-types.mjs +0 -8
  183. package/dist/esm/router/runtime/lifecycle.mjs +0 -105
  184. package/dist/esm/router/runtime/provider.mjs +0 -100
  185. package/dist/esm/rsc/server.worker.mjs +0 -1
  186. package/dist/esm-node/boundary-debugger/index.mjs +0 -278
  187. package/dist/esm-node/core/context/extensions.mjs +0 -34
  188. package/dist/esm-node/core/context/helmetContext.mjs +0 -14
  189. package/dist/esm-node/core/server/federatedCss.mjs +0 -21
  190. package/dist/esm-node/core/server/scriptOrder.mjs +0 -91
  191. package/dist/esm-node/module-federation/consume-surface.mjs +0 -159
  192. package/dist/esm-node/module-federation/distributed-ssr.mjs +0 -83
  193. package/dist/esm-node/module-federation/index.mjs +0 -116
  194. package/dist/esm-node/module-federation/last-known-good.mjs +0 -114
  195. package/dist/esm-node/module-federation/manifest-recovery-runtime-plugin.mjs +0 -90
  196. package/dist/esm-node/module-federation/surface-resolution-types.mjs +0 -9
  197. package/dist/esm-node/router/runtime/lifecycle.mjs +0 -106
  198. package/dist/esm-node/router/runtime/provider.mjs +0 -101
  199. package/dist/esm-node/rsc/server.worker.mjs +0 -2
  200. package/dist/types/boundary-debugger/index.d.ts +0 -28
  201. package/dist/types/core/context/extensions.d.ts +0 -35
  202. package/dist/types/core/context/helmetContext.d.ts +0 -10
  203. package/dist/types/core/server/federatedCss.d.ts +0 -5
  204. package/dist/types/core/server/scriptOrder.d.ts +0 -25
  205. package/dist/types/module-federation/consume-surface.d.ts +0 -104
  206. package/dist/types/module-federation/distributed-ssr.d.ts +0 -61
  207. package/dist/types/module-federation/index.d.ts +0 -71
  208. package/dist/types/module-federation/last-known-good.d.ts +0 -52
  209. package/dist/types/module-federation/manifest-recovery-runtime-plugin.d.ts +0 -25
  210. package/dist/types/module-federation/surface-resolution-types.d.ts +0 -23
  211. package/dist/types/router/runtime/lifecycle.d.ts +0 -27
  212. package/dist/types/router/runtime/provider.d.ts +0 -78
  213. package/dist/types/rsc/server.worker.d.ts +0 -1
@@ -1,147 +1,244 @@
1
+ import { getGlobalEnableRsc, getGlobalInternalRuntimeContext } from "@modern-js/runtime/context";
1
2
  import { storage } from "@modern-js/runtime-utils/node";
2
3
  import { SSR_HYDRATION_ID_PREFIX } from "@modern-js/utils/universal/constants";
3
- import { PassThrough, Readable, Transform } from "stream";
4
+ import { PassThrough, Readable, Transform, finished, pipeline } from "stream";
4
5
  import { ESCAPED_SHELL_STREAM_END_MARK } from "../../../common.mjs";
5
6
  import { RenderLevel } from "../../constants.mjs";
6
- import { getGlobalInternalRuntimeContext } from "../../context/index.mjs";
7
7
  import { getMonitors } from "../../context/monitors/index.mjs";
8
+ import { wrapRuntimeComponentResolver } from "../../react/wrapper.mjs";
8
9
  import { createReplaceHelemt, getHelmetData } from "../helmet.mjs";
10
+ import { createSSRRenderLifecycle, createSSRStreamErrorReporter, observeSSRStream, orderSSRStreamTransforms } from "../shared.mjs";
9
11
  import { enqueueFromEntries } from "./deferredScript.mjs";
10
- import { ShellChunkStatus, getReadableStreamFromString, resolveStreamingMode } from "./shared.mjs";
12
+ import { SHELL_PROGRESSIVE_CHUNK_SIZE, ShellChunkStatus, getReadableStreamFromString, resolveStreamingMode } from "./shared.mjs";
11
13
  import { getTemplates } from "./template.mjs";
12
- import * as __rspack_external__modern_js_runtime_extensions_node_f016b1ee from "@modern-js/runtime-extensions/node";
13
- const defaultExtender = {
14
- modifyRootElement: (rootElement)=>rootElement,
15
- getStyleTags: ()=>'',
16
- processStream: (stream)=>stream
17
- };
18
14
  const createReadableStreamFromElement = async (request, rootElement, options)=>{
19
15
  const { renderToPipeableStream } = await import("react-dom/server");
20
- const { runtimeContext, htmlTemplate, config, ssrConfig, entryName, moduleFederationCssAssets } = options;
21
- let shellChunkStatus = ShellChunkStatus.START;
22
- let renderLevel = RenderLevel.SERVER_RENDER;
16
+ const { runtimeContext, htmlTemplate, config, ssrConfig, entryName, resource } = options;
17
+ const hooks = getGlobalInternalRuntimeContext().hooks;
18
+ const isRsc = true === getGlobalEnableRsc();
19
+ const extenders = hooks.extendStreamSSR.call({
20
+ runtimeContext,
21
+ request,
22
+ resource,
23
+ config,
24
+ platform: 'node',
25
+ mode: 'stream',
26
+ monitors: getMonitors(),
27
+ isRsc,
28
+ terminalMarker: ESCAPED_SHELL_STREAM_END_MARK
29
+ }) || [];
30
+ const lifecycle = createSSRRenderLifecycle(extenders);
31
+ const reportError = createSSRStreamErrorReporter(options.onError);
23
32
  const forceStream2String = Boolean(process.env.MODERN_JS_STREAM_TO_STRING);
24
33
  const { onReady } = resolveStreamingMode(request, forceStream2String);
25
- const internalRuntimeContext = getGlobalInternalRuntimeContext();
26
- const hooks = internalRuntimeContext.hooks;
27
- const extenders = hooks.extendStreamSSR.call() || [];
28
- if (0 === extenders.length) extenders.push(defaultExtender);
29
- extenders.forEach((extender)=>{
30
- if (extender.init) extender.init({
31
- rootElement,
32
- forceStream2String
33
- });
34
- });
35
- let processedRootElement = rootElement;
36
- extenders.forEach((extender)=>{
37
- if (extender.modifyRootElement) processedRootElement = extender.modifyRootElement(processedRootElement);
38
- });
39
- const chunkVec = [];
34
+ let renderLevel = RenderLevel.SERVER_RENDER;
40
35
  let hasStartedPipe = false;
41
- __rspack_external__modern_js_runtime_extensions_node_f016b1ee.beginHeadRender(runtimeContext);
42
- const reportError = __rspack_external__modern_js_runtime_extensions_node_f016b1ee.createOnceErrorReporter(options.onError);
43
- return new Promise((resolve)=>{
44
- const { pipe: reactStreamingPipe } = renderToPipeableStream(processedRootElement, {
45
- nonce: config.nonce,
46
- identifierPrefix: SSR_HYDRATION_ID_PREFIX,
47
- [onReady] () {
48
- if (hasStartedPipe) return;
49
- hasStartedPipe = true;
50
- let styledComponentsStyleTags = '';
51
- extenders.forEach((extender)=>{
52
- if (extender.getStyleTags) styledComponentsStyleTags += extender.getStyleTags();
36
+ let failed = false;
37
+ let reactStream;
38
+ const ownedStreams = new Set();
39
+ const streamCompletions = [];
40
+ let teardown;
41
+ return new Promise((resolve, reject)=>{
42
+ const destroyOwnedStreams = (reason)=>{
43
+ if (teardown) return teardown;
44
+ const error = void 0 === reason ? void 0 : reason instanceof Error ? reason : new Error(String(reason));
45
+ for (const stream of ownedStreams){
46
+ const destroyable = stream;
47
+ destroyable.destroy?.(error);
48
+ }
49
+ teardown = Promise.all(streamCompletions).then((errors)=>{
50
+ const cleanupError = errors.find((value)=>void 0 !== value && value !== error && 'ERR_STREAM_PREMATURE_CLOSE' !== value.code);
51
+ if (cleanupError) throw cleanupError;
52
+ });
53
+ return teardown;
54
+ };
55
+ const abortReact = (reason)=>reactStream?.abort(reason);
56
+ const fail = (error)=>{
57
+ if (failed) return;
58
+ failed = true;
59
+ request.signal.removeEventListener('abort', onStartupAbort);
60
+ if (request.signal.aborted) lifecycle.finish({
61
+ status: 'cancelled',
62
+ reason: request.signal.reason
63
+ });
64
+ else {
65
+ lifecycle.finish({
66
+ status: 'error',
67
+ error
53
68
  });
54
- options[onReady]?.();
55
- getTemplates(htmlTemplate, {
56
- request,
57
- ssrConfig,
58
- renderLevel,
59
- runtimeContext,
60
- config,
61
- entryName,
62
- moduleFederationCssAssets,
63
- styledComponentsStyleTags
64
- }).then(({ shellAfter, shellBefore })=>{
65
- const pendingScripts = [];
66
- const body = new Transform({
67
- transform (chunk, _encoding, callback) {
68
- try {
69
- if (shellChunkStatus !== ShellChunkStatus.FINISH) {
70
- chunkVec.push(Buffer.isBuffer(chunk) ? chunk : Buffer.from(chunk));
71
- const concatedChunk = Buffer.concat(chunkVec).toString('utf-8');
72
- const markerIndex = concatedChunk.indexOf(ESCAPED_SHELL_STREAM_END_MARK);
73
- if (-1 !== markerIndex) {
74
- const beforeMark = concatedChunk.slice(0, markerIndex);
75
- const afterMark = concatedChunk.slice(markerIndex + ESCAPED_SHELL_STREAM_END_MARK.length);
76
- __rspack_external__modern_js_runtime_extensions_node_f016b1ee.publishHeadRender(runtimeContext);
77
- const completedShellBefore = createReplaceHelemt(getHelmetData(runtimeContext))(shellBefore);
78
- shellChunkStatus = ShellChunkStatus.FINISH;
79
- this.push(`${completedShellBefore}${beforeMark}${shellAfter}`);
80
- if (afterMark) this.push(afterMark);
81
- if (pendingScripts.length > 0) for (const s of pendingScripts)this.push(s);
82
- }
83
- } else this.push(chunk);
84
- callback();
85
- } catch (e) {
86
- e instanceof Error ? callback(e) : callback(new Error('Received unknown error when streaming'));
87
- }
69
+ reportError(error);
70
+ }
71
+ abortReact(error);
72
+ destroyOwnedStreams(error).then(()=>reject(error), ()=>reject(error));
73
+ };
74
+ const own = (stream)=>{
75
+ if (!ownedStreams.has(stream)) {
76
+ ownedStreams.add(stream);
77
+ streamCompletions.push(new Promise((done)=>{
78
+ finished(stream, (error)=>done(error ?? void 0));
79
+ }));
80
+ stream.on('error', fail);
81
+ }
82
+ return stream;
83
+ };
84
+ const onStartupAbort = ()=>fail(request.signal.reason);
85
+ const deliver = (source)=>{
86
+ const stream = observeSSRStream(source, {
87
+ lifecycle,
88
+ signal: request.signal,
89
+ async onError (error) {
90
+ failed = true;
91
+ abortReact(error);
92
+ await destroyOwnedStreams(error);
93
+ reportError(error);
94
+ },
95
+ onCancel (reason) {
96
+ failed = true;
97
+ const cleanup = destroyOwnedStreams();
98
+ abortReact(reason);
99
+ return cleanup;
100
+ }
101
+ });
102
+ request.signal.removeEventListener('abort', onStartupAbort);
103
+ resolve(stream);
104
+ };
105
+ const templateOptions = ()=>({
106
+ request,
107
+ ssrConfig,
108
+ renderLevel,
109
+ runtimeContext,
110
+ config,
111
+ entryName,
112
+ lifecycle
113
+ });
114
+ const startOutput = async ()=>{
115
+ if (hasStartedPipe || failed) return;
116
+ hasStartedPipe = true;
117
+ const styledComponentsStyleTags = extenders.map((extender)=>extender.getStyleTags?.() ?? '').join('');
118
+ options[onReady]?.();
119
+ const { shellBefore, shellAfter } = await getTemplates(htmlTemplate, {
120
+ ...templateOptions(),
121
+ styledComponentsStyleTags
122
+ });
123
+ if (failed) return;
124
+ const chunks = [];
125
+ let bufferedLength = 0;
126
+ const marker = Buffer.from(ESCAPED_SHELL_STREAM_END_MARK);
127
+ let markerTail = Buffer.alloc(0);
128
+ const pendingScripts = [];
129
+ let shellChunkStatus = ShellChunkStatus.START;
130
+ const emitShell = (destination, buffered, markerIndex)=>{
131
+ const beforeMark = lifecycle.completedBody(buffered.subarray(0, markerIndex).toString('utf8'), 'shell');
132
+ const completedShellBefore = createReplaceHelemt(getHelmetData(extenders))(shellBefore);
133
+ shellChunkStatus = ShellChunkStatus.FINISH;
134
+ chunks.length = 0;
135
+ bufferedLength = 0;
136
+ destination.push(`${completedShellBefore}${beforeMark}${shellAfter}`);
137
+ const afterMark = buffered.subarray(markerIndex + marker.length);
138
+ if (afterMark.length > 0) destination.push(afterMark);
139
+ for (const script of pendingScripts)destination.push(script);
140
+ pendingScripts.length = 0;
141
+ };
142
+ const body = new Transform({
143
+ transform (chunk, _encoding, callback) {
144
+ try {
145
+ if (shellChunkStatus === ShellChunkStatus.FINISH) this.push(chunk);
146
+ else {
147
+ const bytes = Buffer.isBuffer(chunk) ? chunk : Buffer.from(chunk);
148
+ const window = Buffer.concat([
149
+ markerTail,
150
+ bytes
151
+ ]);
152
+ const windowIndex = window.indexOf(marker);
153
+ const windowStart = bufferedLength - markerTail.length;
154
+ chunks.push(bytes);
155
+ bufferedLength += bytes.length;
156
+ if (-1 === windowIndex) markerTail = window.subarray(Math.max(0, window.length - marker.length + 1));
157
+ else emitShell(this, Buffer.concat(chunks, bufferedLength), windowStart + windowIndex);
88
158
  }
89
- });
90
- const passThrough = new PassThrough();
91
- const stream = Readable.toWeb(body);
92
- resolve(stream);
93
- let processedStream = passThrough;
94
- extenders.forEach((extender)=>{
95
- if (extender.processStream) processedStream = extender.processStream(processedStream);
96
- });
97
- __rspack_external__modern_js_runtime_extensions_node_f016b1ee.pipeNodeHeadStream({
98
- source: processedStream,
99
- destination: body,
100
- context: runtimeContext,
101
- terminalMarker: ESCAPED_SHELL_STREAM_END_MARK,
102
- onError: reportError
103
- });
104
- reactStreamingPipe(passThrough);
159
+ callback();
160
+ } catch (error) {
161
+ callback(error instanceof Error ? error : new Error(String(error)));
162
+ }
163
+ },
164
+ flush (callback) {
105
165
  try {
106
- const storageContext = storage.useContext?.();
107
- const activeDeferreds = storageContext?.activeDeferreds;
108
- const entries = activeDeferreds instanceof Map ? Array.from(activeDeferreds.entries()) : [];
109
- if (entries.length > 0) {
110
- const enqueueScript = (s)=>{
111
- if (shellChunkStatus === ShellChunkStatus.FINISH) body.write(s);
112
- else pendingScripts.push(s);
113
- };
114
- enqueueFromEntries(entries, config.nonce, (s)=>enqueueScript(s));
166
+ if (shellChunkStatus !== ShellChunkStatus.FINISH) {
167
+ const buffered = Buffer.concat(chunks);
168
+ emitShell(this, buffered, buffered.length);
115
169
  }
116
- } catch (err) {
117
- const monitors = getMonitors();
118
- monitors.error("cannot inject router data script", err);
170
+ callback();
171
+ } catch (error) {
172
+ callback(error instanceof Error ? error : new Error(String(error)));
119
173
  }
174
+ }
175
+ });
176
+ own(body);
177
+ const passThrough = new PassThrough();
178
+ let processedStream = own(passThrough);
179
+ for (const extender of orderSSRStreamTransforms(extenders))if (extender.processStream) processedStream = own(extender.processStream(processedStream));
180
+ pipeline(processedStream, body, (error)=>{
181
+ if (null != error && !failed) fail(error);
182
+ });
183
+ deliver(Readable.toWeb(body));
184
+ reactStream.pipe(passThrough);
185
+ try {
186
+ const activeDeferreds = storage.useContext?.()?.activeDeferreds;
187
+ const entries = activeDeferreds instanceof Map ? Array.from(activeDeferreds.entries()) : [];
188
+ enqueueFromEntries(entries, config.nonce, (script)=>{
189
+ if (failed || body.destroyed || body.writableEnded) return;
190
+ if (shellChunkStatus === ShellChunkStatus.FINISH) body.write(script);
191
+ else pendingScripts.push(script);
120
192
  });
121
- },
122
- onShellError (error) {
123
- __rspack_external__modern_js_runtime_extensions_node_f016b1ee.abortHeadRender(runtimeContext);
124
- renderLevel = RenderLevel.CLIENT_RENDER;
125
- getTemplates(htmlTemplate, {
126
- request,
127
- ssrConfig,
128
- renderLevel,
129
- runtimeContext,
130
- entryName,
131
- config,
132
- moduleFederationCssAssets
133
- }).then(({ shellAfter, shellBefore })=>{
134
- const fallbackHtml = `${shellBefore}${shellAfter}`;
135
- const readableStream = getReadableStreamFromString(fallbackHtml);
136
- resolve(readableStream);
137
- options?.onShellError?.(error);
138
- });
139
- },
140
- onError (error) {
141
- renderLevel = RenderLevel.CLIENT_RENDER;
142
- reportError(error);
193
+ } catch (error) {
194
+ getMonitors().error("cannot inject router data script", error);
143
195
  }
196
+ };
197
+ const renderFallback = async (error)=>{
198
+ if (failed || hasStartedPipe) return;
199
+ lifecycle.finish({
200
+ status: 'fallback',
201
+ error
202
+ });
203
+ renderLevel = RenderLevel.CLIENT_RENDER;
204
+ const { shellBefore, shellAfter } = await getTemplates(htmlTemplate, {
205
+ ...templateOptions(),
206
+ helmetData: getHelmetData(extenders)
207
+ });
208
+ if (failed) return;
209
+ options.onShellError?.(error);
210
+ deliver(getReadableStreamFromString(`${shellBefore}${shellAfter}`));
211
+ };
212
+ request.signal.addEventListener('abort', onStartupAbort, {
213
+ once: true
144
214
  });
215
+ try {
216
+ request.signal.throwIfAborted();
217
+ for (const extender of extenders)extender.init?.({
218
+ rootElement,
219
+ forceStream2String
220
+ });
221
+ let processedRootElement = isRsc && false === runtimeContext.isBrowser ? wrapRuntimeComponentResolver(rootElement, hooks) : rootElement;
222
+ for (const extender of extenders)processedRootElement = extender.modifyRootElement?.(processedRootElement) ?? processedRootElement;
223
+ lifecycle.beforeReact();
224
+ reactStream = renderToPipeableStream(processedRootElement, {
225
+ nonce: config.nonce,
226
+ identifierPrefix: SSR_HYDRATION_ID_PREFIX,
227
+ progressiveChunkSize: SHELL_PROGRESSIVE_CHUNK_SIZE,
228
+ [onReady] () {
229
+ startOutput().catch(fail);
230
+ },
231
+ onShellError (error) {
232
+ renderFallback(error).catch(fail);
233
+ },
234
+ onError (error) {
235
+ renderLevel = RenderLevel.CLIENT_RENDER;
236
+ if (!request.signal.aborted && !failed) reportError(error);
237
+ }
238
+ });
239
+ } catch (error) {
240
+ fail(error);
241
+ }
145
242
  });
146
243
  };
147
244
  export { createReadableStreamFromElement };
@@ -1,121 +1,192 @@
1
1
  import { renderSSRStream } from "@modern-js/render/ssr";
2
+ import { getGlobalEnableRsc, getGlobalInternalRuntimeContext } from "@modern-js/runtime/context";
2
3
  import { storage } from "@modern-js/runtime-utils/node";
4
+ import react from "react";
3
5
  import { ESCAPED_SHELL_STREAM_END_MARK } from "../../../common.mjs";
4
6
  import { RenderLevel } from "../../constants.mjs";
7
+ import { getMonitors } from "../../context/monitors/index.mjs";
8
+ import { wrapRuntimeComponentResolver } from "../../react/wrapper.mjs";
5
9
  import { createReplaceHelemt, getHelmetData } from "../helmet.mjs";
10
+ import { createSSRRenderLifecycle, createSSRStreamErrorReporter, observeSSRStream, orderSSRStreamTransforms } from "../shared.mjs";
6
11
  import { enqueueFromEntries } from "./deferredScript.mjs";
7
- import { ShellChunkStatus, encodeForWebStream, getReadableStreamFromString, resolveStreamingMode } from "./shared.mjs";
12
+ import { SHELL_PROGRESSIVE_CHUNK_SIZE, ShellChunkStatus, getReadableStreamFromString, resolveStreamingMode } from "./shared.mjs";
8
13
  import { getTemplates } from "./template.mjs";
9
- import * as __rspack_external__modern_js_runtime_extensions_ce611631 from "@modern-js/runtime-extensions";
10
14
  const createReadableStreamFromElement = async (request, rootElement, options)=>{
11
- let shellChunkStatus = ShellChunkStatus.START;
12
- const chunkVec = [];
13
- const { htmlTemplate, runtimeContext, config, ssrConfig, entryName, moduleFederationCssAssets, rscManifest, rscRoot } = options;
14
- __rspack_external__modern_js_runtime_extensions_ce611631.beginHeadRender(runtimeContext);
15
- const { shellBefore, shellAfter } = await getTemplates(htmlTemplate, {
16
- renderLevel: RenderLevel.SERVER_RENDER,
15
+ const { htmlTemplate, runtimeContext, config, ssrConfig, entryName, resource, rscManifest, rscRoot } = options;
16
+ const hooks = getGlobalInternalRuntimeContext().hooks;
17
+ const isRsc = true === getGlobalEnableRsc();
18
+ const extenders = hooks.extendStreamSSR.call({
19
+ runtimeContext,
20
+ request,
21
+ resource,
22
+ config,
23
+ platform: 'web',
24
+ mode: 'stream',
25
+ monitors: getMonitors(),
26
+ isRsc,
27
+ terminalMarker: ESCAPED_SHELL_STREAM_END_MARK
28
+ }) || [];
29
+ const lifecycle = createSSRRenderLifecycle(extenders);
30
+ const reportOnce = createSSRStreamErrorReporter(options.onError);
31
+ const reportError = (error)=>{
32
+ if (!request.signal.aborted && lifecycle.terminal?.status !== 'cancelled') reportOnce(error);
33
+ };
34
+ const forceStream2String = Boolean("u" > typeof process && process.env?.MODERN_JS_STREAM_TO_STRING);
35
+ let pendingSource;
36
+ let bodyOpen = true;
37
+ let bodyPipe;
38
+ const templateOptions = {
17
39
  runtimeContext,
18
40
  ssrConfig,
19
41
  request,
20
42
  config,
21
43
  entryName,
22
- moduleFederationCssAssets
23
- });
44
+ lifecycle
45
+ };
24
46
  try {
47
+ request.signal.throwIfAborted();
48
+ for (const extender of extenders)extender.init?.({
49
+ rootElement,
50
+ forceStream2String
51
+ });
25
52
  const readableOriginal = await renderSSRStream(rootElement, {
26
53
  request,
54
+ signal: request.signal,
27
55
  nonce: config.nonce,
56
+ progressiveChunkSize: SHELL_PROGRESSIVE_CHUNK_SIZE,
28
57
  rscManifest,
29
58
  rscRoot: rscRoot,
30
59
  routes: runtimeContext.routes,
31
- onError (error) {
32
- options.onError?.(error);
60
+ onError: reportError,
61
+ wrapHtmlRoot (root) {
62
+ let element = react.isValidElement(root) ? root : react.createElement(react.Fragment, null, root);
63
+ if (isRsc && false === runtimeContext.isBrowser) element = wrapRuntimeComponentResolver(element, hooks);
64
+ for (const extender of extenders)element = extender.modifyRootElement?.(element) ?? element;
65
+ lifecycle.beforeReact();
66
+ return element;
33
67
  }
34
68
  });
69
+ pendingSource = readableOriginal;
35
70
  options.onShellReady?.();
36
- readableOriginal.allReady.then(()=>{
37
- options?.onAllReady?.();
38
- });
39
- const forceStreamToString = Boolean("u" > typeof process && process.env?.MODERN_JS_STREAM_TO_STRING);
40
- const { waitForAllReady } = resolveStreamingMode(request, forceStreamToString);
71
+ readableOriginal.allReady.then(()=>options.onAllReady?.()).catch(reportError);
72
+ const { waitForAllReady } = resolveStreamingMode(request, forceStream2String);
41
73
  if (waitForAllReady) await readableOriginal.allReady;
42
- const reader = __rspack_external__modern_js_runtime_extensions_ce611631.createConservingWebShellStream(readableOriginal, runtimeContext, ESCAPED_SHELL_STREAM_END_MARK, options.onError).getReader();
43
- const stream = new ReadableStream({
74
+ request.signal.throwIfAborted();
75
+ const styledComponentsStyleTags = extenders.map((extender)=>extender.getStyleTags?.() ?? '').join('');
76
+ const { shellBefore, shellAfter } = await getTemplates(htmlTemplate, {
77
+ ...templateOptions,
78
+ renderLevel: RenderLevel.SERVER_RENDER,
79
+ styledComponentsStyleTags
80
+ });
81
+ for (const extender of orderSSRStreamTransforms(extenders))if (void 0 !== extender.processReadableStream) pendingSource = extender.processReadableStream(pendingSource);
82
+ const decoder = new TextDecoder();
83
+ const encoder = new TextEncoder();
84
+ const pendingScripts = [];
85
+ const buffered = [];
86
+ let bufferedLength = 0;
87
+ let markerTail = '';
88
+ let shellChunkStatus = ShellChunkStatus.START;
89
+ let bodyController;
90
+ const emit = (chunk, controller)=>{
91
+ if (shellChunkStatus === ShellChunkStatus.FINISH) {
92
+ if (chunk.length > 0) controller.enqueue(encoder.encode(chunk));
93
+ return;
94
+ }
95
+ const window = markerTail + chunk;
96
+ const windowIndex = window.indexOf(ESCAPED_SHELL_STREAM_END_MARK);
97
+ const markerIndex = bufferedLength - markerTail.length + windowIndex;
98
+ buffered.push(chunk);
99
+ bufferedLength += chunk.length;
100
+ if (-1 === windowIndex) {
101
+ markerTail = window.slice(Math.max(0, window.length - ESCAPED_SHELL_STREAM_END_MARK.length + 1));
102
+ return;
103
+ }
104
+ const shell = buffered.join('');
105
+ const beforeMark = lifecycle.completedBody(shell.slice(0, markerIndex), 'shell');
106
+ const afterMark = shell.slice(markerIndex + ESCAPED_SHELL_STREAM_END_MARK.length);
107
+ const completedShellBefore = createReplaceHelemt(getHelmetData(extenders))(shellBefore);
108
+ shellChunkStatus = ShellChunkStatus.FINISH;
109
+ buffered.length = 0;
110
+ controller.enqueue(encoder.encode(`${completedShellBefore}${beforeMark}${shellAfter}`));
111
+ if (afterMark.length > 0) controller.enqueue(encoder.encode(afterMark));
112
+ for (const script of pendingScripts)controller.enqueue(encoder.encode(script));
113
+ pendingScripts.length = 0;
114
+ };
115
+ const body = new TransformStream({
44
116
  start (controller) {
45
- const pendingScripts = [];
46
- let isClosed = false;
47
- const safeEnqueue = (chunk)=>{
48
- if (isClosed) return;
49
- try {
50
- controller.enqueue(chunk);
51
- } catch {
52
- isClosed = true;
53
- }
54
- };
55
- const closeController = ()=>{
56
- if (!isClosed) {
57
- isClosed = true;
58
- try {
59
- controller.close();
60
- } catch {}
61
- }
62
- };
63
- const flushPendingScripts = ()=>{
64
- for (const s of pendingScripts)safeEnqueue(encodeForWebStream(s));
65
- pendingScripts.length = 0;
66
- };
67
- const enqueueScript = (script)=>{
68
- if (shellChunkStatus === ShellChunkStatus.FINISH) safeEnqueue(encodeForWebStream(script));
69
- else pendingScripts.push(script);
70
- };
71
- const storageContext = storage.useContext?.();
72
- const activeDeferreds = storageContext?.activeDeferreds;
73
- const entries = activeDeferreds instanceof Map ? Array.from(activeDeferreds.entries()) : [];
74
- if (entries.length > 0) enqueueFromEntries(entries, config.nonce, enqueueScript);
75
- async function push() {
76
- try {
77
- const { done, value } = await reader.read();
78
- if (done) return void closeController();
79
- if (isClosed) return;
80
- if (shellChunkStatus !== ShellChunkStatus.FINISH) {
81
- chunkVec.push(new TextDecoder().decode(value));
82
- const concatedChunk = chunkVec.join('');
83
- const markerIndex = concatedChunk.indexOf(ESCAPED_SHELL_STREAM_END_MARK);
84
- if (-1 !== markerIndex) {
85
- const beforeMark = concatedChunk.slice(0, markerIndex);
86
- const afterMark = concatedChunk.slice(markerIndex + ESCAPED_SHELL_STREAM_END_MARK.length);
87
- __rspack_external__modern_js_runtime_extensions_ce611631.publishHeadRender(runtimeContext);
88
- const completedShellBefore = createReplaceHelemt(getHelmetData(runtimeContext))(shellBefore);
89
- shellChunkStatus = ShellChunkStatus.FINISH;
90
- safeEnqueue(encodeForWebStream(`${completedShellBefore}${beforeMark}${shellAfter}`));
91
- if (afterMark.length > 0) safeEnqueue(encodeForWebStream(afterMark));
92
- flushPendingScripts();
93
- }
94
- } else safeEnqueue(value);
95
- if (!isClosed) push();
96
- } catch (error) {
97
- __rspack_external__modern_js_runtime_extensions_ce611631.abortHeadRender(runtimeContext);
98
- if (!isClosed) {
99
- isClosed = true;
100
- try {
101
- controller.error(error);
102
- } catch {}
103
- }
104
- }
105
- }
106
- push();
117
+ bodyController = controller;
118
+ },
119
+ transform (chunk, controller) {
120
+ emit(decoder.decode(chunk, {
121
+ stream: true
122
+ }), controller);
107
123
  },
108
- cancel (reason) {
109
- __rspack_external__modern_js_runtime_extensions_ce611631.abortHeadRender(runtimeContext);
110
- reader.cancel(reason).catch(()=>{});
124
+ flush (controller) {
125
+ bodyOpen = false;
126
+ emit(decoder.decode(), controller);
127
+ if (shellChunkStatus !== ShellChunkStatus.FINISH) throw new Error('React SSR stream ended before the shell marker');
111
128
  }
112
129
  });
113
- return stream;
114
- } catch (e) {
115
- __rspack_external__modern_js_runtime_extensions_ce611631.abortHeadRender(runtimeContext);
116
- const fallbackHtml = `${shellBefore}${shellAfter}`;
117
- const stream = getReadableStreamFromString(fallbackHtml);
118
- return stream;
130
+ bodyPipe = pendingSource.pipeTo(body.writable);
131
+ bodyPipe.catch(()=>{});
132
+ pendingSource = body.readable;
133
+ const activeDeferreds = storage.useContext?.()?.activeDeferreds;
134
+ const entries = activeDeferreds instanceof Map ? Array.from(activeDeferreds.entries()) : [];
135
+ enqueueFromEntries(entries, config.nonce, (script)=>{
136
+ if (!bodyOpen) return;
137
+ if (shellChunkStatus === ShellChunkStatus.FINISH) try {
138
+ bodyController.enqueue(encoder.encode(script));
139
+ } catch {
140
+ bodyOpen = false;
141
+ }
142
+ else pendingScripts.push(script);
143
+ });
144
+ return observeSSRStream(pendingSource, {
145
+ lifecycle,
146
+ async onError (error) {
147
+ bodyOpen = false;
148
+ await bodyPipe?.catch(()=>{});
149
+ reportError(error);
150
+ },
151
+ signal: request.signal,
152
+ async onCancel (reason) {
153
+ bodyOpen = false;
154
+ await bodyPipe?.catch((error)=>{
155
+ if (error !== reason) throw error;
156
+ });
157
+ },
158
+ onComplete: ()=>bodyPipe
159
+ });
160
+ } catch (error) {
161
+ bodyOpen = false;
162
+ if (void 0 !== pendingSource) try {
163
+ await pendingSource.cancel(error);
164
+ await bodyPipe?.catch(()=>{});
165
+ } catch (cancelError) {
166
+ if (!request.signal.aborted) reportError(cancelError);
167
+ }
168
+ if (request.signal.aborted) {
169
+ lifecycle.finish({
170
+ status: 'cancelled',
171
+ reason: request.signal.reason
172
+ });
173
+ throw request.signal.reason;
174
+ }
175
+ lifecycle.finish({
176
+ status: 'fallback',
177
+ error
178
+ });
179
+ reportError(error);
180
+ const { shellBefore, shellAfter } = await getTemplates(htmlTemplate, {
181
+ ...templateOptions,
182
+ renderLevel: RenderLevel.CLIENT_RENDER,
183
+ helmetData: getHelmetData(extenders)
184
+ });
185
+ return observeSSRStream(getReadableStreamFromString(`${shellBefore}${shellAfter}`), {
186
+ lifecycle,
187
+ onError: reportError,
188
+ signal: request.signal
189
+ });
119
190
  }
120
191
  };
121
192
  export { createReadableStreamFromElement };