@bleedingdev/modern-js-runtime 3.9.0-ultramodern.4 → 3.9.0-ultramodern.6

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 (154) hide show
  1. package/dist/cjs/cli/ssr/index.js +2 -74
  2. package/dist/cjs/core/context/index.js +4 -43
  3. package/dist/cjs/core/context/public.js +4 -8
  4. package/dist/cjs/core/context/runtime.js +17 -6
  5. package/dist/cjs/core/react/wrapper.js +22 -65
  6. package/dist/cjs/core/server/helmet.js +5 -4
  7. package/dist/cjs/core/server/requestResponse.js +4 -4
  8. package/dist/cjs/core/server/routerCleanup.js +2 -2
  9. package/dist/cjs/core/server/shared.js +171 -4
  10. package/dist/cjs/core/server/stream/afterTemplate.js +21 -16
  11. package/dist/cjs/core/server/stream/beforeTemplate.js +34 -25
  12. package/dist/cjs/core/server/stream/beforeTemplate.worker.js +28 -21
  13. package/dist/cjs/core/server/stream/createReadableStream.js +208 -123
  14. package/dist/cjs/core/server/stream/createReadableStream.worker.js +159 -90
  15. package/dist/cjs/core/server/stream/deferredScript.js +3 -3
  16. package/dist/cjs/core/server/stream/shared.js +2 -2
  17. package/dist/cjs/core/server/string/index.js +100 -64
  18. package/dist/cjs/core/server/string/loadable.js +34 -19
  19. package/dist/cjs/core/server/string/ssrData.js +5 -12
  20. package/dist/cjs/core/server/utils.js +1 -2
  21. package/dist/cjs/exports/head.js +7 -14
  22. package/dist/cjs/router/runtime/PrefetchLink.js +67 -123
  23. package/dist/cjs/router/runtime/hooks.js +13 -2
  24. package/dist/cjs/router/runtime/internal.js +7 -45
  25. package/dist/cjs/router/runtime/plugin.js +2 -8
  26. package/dist/cjs/router/runtime/plugin.node.js +2 -30
  27. package/dist/cjs/router/runtime/redirect.js +1 -1
  28. package/dist/esm/cli/ssr/index.mjs +3 -72
  29. package/dist/esm/core/context/index.mjs +2 -5
  30. package/dist/esm/core/context/public.mjs +1 -6
  31. package/dist/esm/core/context/runtime.mjs +12 -4
  32. package/dist/esm/core/react/wrapper.mjs +21 -67
  33. package/dist/esm/core/server/helmet.mjs +5 -4
  34. package/dist/esm/core/server/requestResponse.mjs +3 -3
  35. package/dist/esm/core/server/routerCleanup.mjs +1 -1
  36. package/dist/esm/core/server/shared.mjs +153 -1
  37. package/dist/esm/core/server/stream/afterTemplate.mjs +23 -18
  38. package/dist/esm/core/server/stream/beforeTemplate.mjs +37 -28
  39. package/dist/esm/core/server/stream/beforeTemplate.worker.mjs +31 -24
  40. package/dist/esm/core/server/stream/createReadableStream.mjs +207 -122
  41. package/dist/esm/core/server/stream/createReadableStream.worker.mjs +149 -90
  42. package/dist/esm/core/server/stream/deferredScript.mjs +3 -3
  43. package/dist/esm/core/server/stream/shared.mjs +2 -2
  44. package/dist/esm/core/server/string/index.mjs +104 -68
  45. package/dist/esm/core/server/string/loadable.mjs +34 -19
  46. package/dist/esm/core/server/string/ssrData.mjs +5 -12
  47. package/dist/esm/core/server/utils.mjs +1 -2
  48. package/dist/esm/exports/head.mjs +7 -14
  49. package/dist/esm/router/runtime/PrefetchLink.mjs +67 -123
  50. package/dist/esm/router/runtime/hooks.mjs +9 -1
  51. package/dist/esm/router/runtime/internal.mjs +2 -33
  52. package/dist/esm/router/runtime/plugin.mjs +1 -7
  53. package/dist/esm/router/runtime/plugin.node.mjs +1 -29
  54. package/dist/esm/router/runtime/redirect.mjs +1 -1
  55. package/dist/esm-node/cli/ssr/index.mjs +3 -72
  56. package/dist/esm-node/core/context/index.mjs +2 -5
  57. package/dist/esm-node/core/context/public.mjs +1 -6
  58. package/dist/esm-node/core/context/runtime.mjs +12 -4
  59. package/dist/esm-node/core/react/wrapper.mjs +21 -67
  60. package/dist/esm-node/core/server/helmet.mjs +5 -4
  61. package/dist/esm-node/core/server/requestResponse.mjs +3 -3
  62. package/dist/esm-node/core/server/routerCleanup.mjs +1 -1
  63. package/dist/esm-node/core/server/shared.mjs +153 -1
  64. package/dist/esm-node/core/server/stream/afterTemplate.mjs +23 -18
  65. package/dist/esm-node/core/server/stream/beforeTemplate.mjs +37 -28
  66. package/dist/esm-node/core/server/stream/beforeTemplate.worker.mjs +31 -24
  67. package/dist/esm-node/core/server/stream/createReadableStream.mjs +207 -122
  68. package/dist/esm-node/core/server/stream/createReadableStream.worker.mjs +149 -90
  69. package/dist/esm-node/core/server/stream/deferredScript.mjs +3 -3
  70. package/dist/esm-node/core/server/stream/shared.mjs +2 -2
  71. package/dist/esm-node/core/server/string/index.mjs +104 -68
  72. package/dist/esm-node/core/server/string/loadable.mjs +34 -19
  73. package/dist/esm-node/core/server/string/ssrData.mjs +5 -12
  74. package/dist/esm-node/core/server/utils.mjs +1 -2
  75. package/dist/esm-node/exports/head.mjs +7 -14
  76. package/dist/esm-node/router/runtime/PrefetchLink.mjs +67 -123
  77. package/dist/esm-node/router/runtime/hooks.mjs +9 -1
  78. package/dist/esm-node/router/runtime/internal.mjs +2 -33
  79. package/dist/esm-node/router/runtime/plugin.mjs +1 -7
  80. package/dist/esm-node/router/runtime/plugin.node.mjs +1 -29
  81. package/dist/esm-node/router/runtime/redirect.mjs +1 -1
  82. package/dist/types/cli/ssr/index.d.ts +0 -3
  83. package/dist/types/core/context/index.d.ts +4 -6
  84. package/dist/types/core/context/public.d.ts +1 -23
  85. package/dist/types/core/context/runtime.d.ts +26 -2
  86. package/dist/types/core/react/wrapper.d.ts +6 -0
  87. package/dist/types/core/server/helmet.d.ts +4 -5
  88. package/dist/types/core/server/shared.d.ts +23 -0
  89. package/dist/types/core/server/stream/afterTemplate.d.ts +2 -1
  90. package/dist/types/core/server/stream/beforeTemplate.d.ts +4 -1
  91. package/dist/types/core/server/stream/beforeTemplate.worker.d.ts +4 -1
  92. package/dist/types/core/server/stream/shared.d.ts +1 -1
  93. package/dist/types/core/server/string/loadable.d.ts +6 -3
  94. package/dist/types/core/server/string/ssrData.d.ts +2 -1
  95. package/dist/types/core/server/string/types.d.ts +1 -5
  96. package/dist/types/exports/head.d.ts +2 -2
  97. package/dist/types/router/runtime/PrefetchLink.d.ts +27 -2
  98. package/dist/types/router/runtime/hooks.d.ts +19 -2
  99. package/dist/types/router/runtime/internal.d.ts +4 -21
  100. package/dist/types/router/runtime/types.d.ts +2 -43
  101. package/package.json +9 -38
  102. package/rstest.config.mts +32 -2
  103. package/dist/cjs/boundary-debugger/index.js +0 -317
  104. package/dist/cjs/core/context/extensions.js +0 -74
  105. package/dist/cjs/core/context/helmetContext.js +0 -54
  106. package/dist/cjs/core/server/federatedCss.js +0 -58
  107. package/dist/cjs/core/server/scriptOrder.js +0 -140
  108. package/dist/cjs/module-federation/consume-surface.js +0 -199
  109. package/dist/cjs/module-federation/distributed-ssr.js +0 -135
  110. package/dist/cjs/module-federation/index.js +0 -316
  111. package/dist/cjs/module-federation/last-known-good.js +0 -157
  112. package/dist/cjs/module-federation/manifest-recovery-runtime-plugin.js +0 -129
  113. package/dist/cjs/module-federation/surface-resolution-types.js +0 -61
  114. package/dist/cjs/router/runtime/lifecycle.js +0 -167
  115. package/dist/cjs/router/runtime/provider.js +0 -153
  116. package/dist/esm/boundary-debugger/index.mjs +0 -277
  117. package/dist/esm/core/context/extensions.mjs +0 -33
  118. package/dist/esm/core/context/helmetContext.mjs +0 -13
  119. package/dist/esm/core/server/federatedCss.mjs +0 -20
  120. package/dist/esm/core/server/scriptOrder.mjs +0 -90
  121. package/dist/esm/module-federation/consume-surface.mjs +0 -158
  122. package/dist/esm/module-federation/distributed-ssr.mjs +0 -82
  123. package/dist/esm/module-federation/index.mjs +0 -115
  124. package/dist/esm/module-federation/last-known-good.mjs +0 -113
  125. package/dist/esm/module-federation/manifest-recovery-runtime-plugin.mjs +0 -89
  126. package/dist/esm/module-federation/surface-resolution-types.mjs +0 -8
  127. package/dist/esm/router/runtime/lifecycle.mjs +0 -105
  128. package/dist/esm/router/runtime/provider.mjs +0 -100
  129. package/dist/esm-node/boundary-debugger/index.mjs +0 -278
  130. package/dist/esm-node/core/context/extensions.mjs +0 -34
  131. package/dist/esm-node/core/context/helmetContext.mjs +0 -14
  132. package/dist/esm-node/core/server/federatedCss.mjs +0 -21
  133. package/dist/esm-node/core/server/scriptOrder.mjs +0 -91
  134. package/dist/esm-node/module-federation/consume-surface.mjs +0 -159
  135. package/dist/esm-node/module-federation/distributed-ssr.mjs +0 -83
  136. package/dist/esm-node/module-federation/index.mjs +0 -116
  137. package/dist/esm-node/module-federation/last-known-good.mjs +0 -114
  138. package/dist/esm-node/module-federation/manifest-recovery-runtime-plugin.mjs +0 -90
  139. package/dist/esm-node/module-federation/surface-resolution-types.mjs +0 -9
  140. package/dist/esm-node/router/runtime/lifecycle.mjs +0 -106
  141. package/dist/esm-node/router/runtime/provider.mjs +0 -101
  142. package/dist/types/boundary-debugger/index.d.ts +0 -28
  143. package/dist/types/core/context/extensions.d.ts +0 -35
  144. package/dist/types/core/context/helmetContext.d.ts +0 -10
  145. package/dist/types/core/server/federatedCss.d.ts +0 -5
  146. package/dist/types/core/server/scriptOrder.d.ts +0 -25
  147. package/dist/types/module-federation/consume-surface.d.ts +0 -104
  148. package/dist/types/module-federation/distributed-ssr.d.ts +0 -61
  149. package/dist/types/module-federation/index.d.ts +0 -71
  150. package/dist/types/module-federation/last-known-good.d.ts +0 -52
  151. package/dist/types/module-federation/manifest-recovery-runtime-plugin.d.ts +0 -25
  152. package/dist/types/module-federation/surface-resolution-types.d.ts +0 -23
  153. package/dist/types/router/runtime/lifecycle.d.ts +0 -27
  154. package/dist/types/router/runtime/provider.d.ts +0 -78
@@ -1,122 +1,181 @@
1
1
  import "node:module";
2
2
  import { renderSSRStream } from "@modern-js/render/ssr";
3
3
  import { storage } from "@modern-js/runtime-utils/node";
4
+ import react from "react";
4
5
  import { ESCAPED_SHELL_STREAM_END_MARK } from "../../../common.mjs";
5
6
  import { RenderLevel } from "../../constants.mjs";
7
+ import { getGlobalEnableRsc, getGlobalInternalRuntimeContext } from "../../context/index.mjs";
8
+ import { wrapRuntimeComponentResolver } from "../../react/wrapper.mjs";
6
9
  import { createReplaceHelemt, getHelmetData } from "../helmet.mjs";
10
+ import { createSSRRenderLifecycle, createSSRStreamErrorReporter, observeSSRStream, orderSSRStreamTransforms } from "../shared.mjs";
7
11
  import { enqueueFromEntries } from "./deferredScript.mjs";
8
- import { ShellChunkStatus, encodeForWebStream, getReadableStreamFromString, resolveStreamingMode } from "./shared.mjs";
12
+ import { ShellChunkStatus, getReadableStreamFromString, resolveStreamingMode } from "./shared.mjs";
9
13
  import { getTemplates } from "./template.mjs";
10
- import * as __rspack_external__modern_js_runtime_extensions_ce611631 from "@modern-js/runtime-extensions";
11
14
  const createReadableStreamFromElement = async (request, rootElement, options)=>{
12
- let shellChunkStatus = ShellChunkStatus.START;
13
- const chunkVec = [];
14
- const { htmlTemplate, runtimeContext, config, ssrConfig, entryName, moduleFederationCssAssets, rscManifest, rscRoot } = options;
15
- __rspack_external__modern_js_runtime_extensions_ce611631.beginHeadRender(runtimeContext);
16
- const { shellBefore, shellAfter } = await getTemplates(htmlTemplate, {
17
- 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
+ isRsc,
26
+ terminalMarker: ESCAPED_SHELL_STREAM_END_MARK
27
+ }) || [];
28
+ const lifecycle = createSSRRenderLifecycle(extenders);
29
+ const reportOnce = createSSRStreamErrorReporter(options.onError);
30
+ const reportError = (error)=>{
31
+ if (!request.signal.aborted && lifecycle.terminal?.status !== 'cancelled') reportOnce(error);
32
+ };
33
+ const forceStream2String = Boolean("u" > typeof process && process.env?.MODERN_JS_STREAM_TO_STRING);
34
+ let pendingSource;
35
+ let bodyOpen = true;
36
+ let bodyPipe;
37
+ const templateOptions = {
18
38
  runtimeContext,
19
39
  ssrConfig,
20
40
  request,
21
41
  config,
22
42
  entryName,
23
- moduleFederationCssAssets
24
- });
43
+ lifecycle
44
+ };
25
45
  try {
46
+ request.signal.throwIfAborted();
47
+ for (const extender of extenders)extender.init?.({
48
+ rootElement,
49
+ forceStream2String
50
+ });
26
51
  const readableOriginal = await renderSSRStream(rootElement, {
27
52
  request,
53
+ signal: request.signal,
28
54
  nonce: config.nonce,
29
55
  rscManifest,
30
56
  rscRoot: rscRoot,
31
57
  routes: runtimeContext.routes,
32
- onError (error) {
33
- options.onError?.(error);
58
+ onError: reportError,
59
+ wrapHtmlRoot (root) {
60
+ let element = react.isValidElement(root) ? root : react.createElement(react.Fragment, null, root);
61
+ if (isRsc && false === runtimeContext.isBrowser) element = wrapRuntimeComponentResolver(element, hooks);
62
+ for (const extender of extenders)element = extender.modifyRootElement?.(element) ?? element;
63
+ lifecycle.beforeReact();
64
+ return element;
34
65
  }
35
66
  });
67
+ pendingSource = readableOriginal;
36
68
  options.onShellReady?.();
37
- readableOriginal.allReady.then(()=>{
38
- options?.onAllReady?.();
39
- });
40
- const forceStreamToString = Boolean("u" > typeof process && process.env?.MODERN_JS_STREAM_TO_STRING);
41
- const { waitForAllReady } = resolveStreamingMode(request, forceStreamToString);
69
+ readableOriginal.allReady.then(()=>options.onAllReady?.()).catch(reportError);
70
+ const { waitForAllReady } = resolveStreamingMode(request, forceStream2String);
42
71
  if (waitForAllReady) await readableOriginal.allReady;
43
- const reader = __rspack_external__modern_js_runtime_extensions_ce611631.createConservingWebShellStream(readableOriginal, runtimeContext, ESCAPED_SHELL_STREAM_END_MARK, options.onError).getReader();
44
- const stream = new ReadableStream({
72
+ request.signal.throwIfAborted();
73
+ const styledComponentsStyleTags = extenders.map((extender)=>extender.getStyleTags?.() ?? '').join('');
74
+ const { shellBefore, shellAfter } = await getTemplates(htmlTemplate, {
75
+ ...templateOptions,
76
+ renderLevel: RenderLevel.SERVER_RENDER,
77
+ styledComponentsStyleTags
78
+ });
79
+ for (const extender of orderSSRStreamTransforms(extenders))if (void 0 !== extender.processReadableStream) pendingSource = extender.processReadableStream(pendingSource);
80
+ const decoder = new TextDecoder();
81
+ const encoder = new TextEncoder();
82
+ const pendingScripts = [];
83
+ let buffered = '';
84
+ let shellChunkStatus = ShellChunkStatus.START;
85
+ let bodyController;
86
+ const emit = (chunk, controller)=>{
87
+ if (shellChunkStatus === ShellChunkStatus.FINISH) {
88
+ if (chunk.length > 0) controller.enqueue(encoder.encode(chunk));
89
+ return;
90
+ }
91
+ buffered += chunk;
92
+ const markerIndex = buffered.indexOf(ESCAPED_SHELL_STREAM_END_MARK);
93
+ if (-1 === markerIndex) return;
94
+ const beforeMark = lifecycle.completedBody(buffered.slice(0, markerIndex), 'shell');
95
+ const afterMark = buffered.slice(markerIndex + ESCAPED_SHELL_STREAM_END_MARK.length);
96
+ const completedShellBefore = createReplaceHelemt(getHelmetData(extenders))(shellBefore);
97
+ shellChunkStatus = ShellChunkStatus.FINISH;
98
+ buffered = '';
99
+ controller.enqueue(encoder.encode(`${completedShellBefore}${beforeMark}${shellAfter}`));
100
+ if (afterMark.length > 0) controller.enqueue(encoder.encode(afterMark));
101
+ for (const script of pendingScripts)controller.enqueue(encoder.encode(script));
102
+ pendingScripts.length = 0;
103
+ };
104
+ const body = new TransformStream({
45
105
  start (controller) {
46
- const pendingScripts = [];
47
- let isClosed = false;
48
- const safeEnqueue = (chunk)=>{
49
- if (isClosed) return;
50
- try {
51
- controller.enqueue(chunk);
52
- } catch {
53
- isClosed = true;
54
- }
55
- };
56
- const closeController = ()=>{
57
- if (!isClosed) {
58
- isClosed = true;
59
- try {
60
- controller.close();
61
- } catch {}
62
- }
63
- };
64
- const flushPendingScripts = ()=>{
65
- for (const s of pendingScripts)safeEnqueue(encodeForWebStream(s));
66
- pendingScripts.length = 0;
67
- };
68
- const enqueueScript = (script)=>{
69
- if (shellChunkStatus === ShellChunkStatus.FINISH) safeEnqueue(encodeForWebStream(script));
70
- else pendingScripts.push(script);
71
- };
72
- const storageContext = storage.useContext?.();
73
- const activeDeferreds = storageContext?.activeDeferreds;
74
- const entries = activeDeferreds instanceof Map ? Array.from(activeDeferreds.entries()) : [];
75
- if (entries.length > 0) enqueueFromEntries(entries, config.nonce, enqueueScript);
76
- async function push() {
77
- try {
78
- const { done, value } = await reader.read();
79
- if (done) return void closeController();
80
- if (isClosed) return;
81
- if (shellChunkStatus !== ShellChunkStatus.FINISH) {
82
- chunkVec.push(new TextDecoder().decode(value));
83
- const concatedChunk = chunkVec.join('');
84
- const markerIndex = concatedChunk.indexOf(ESCAPED_SHELL_STREAM_END_MARK);
85
- if (-1 !== markerIndex) {
86
- const beforeMark = concatedChunk.slice(0, markerIndex);
87
- const afterMark = concatedChunk.slice(markerIndex + ESCAPED_SHELL_STREAM_END_MARK.length);
88
- __rspack_external__modern_js_runtime_extensions_ce611631.publishHeadRender(runtimeContext);
89
- const completedShellBefore = createReplaceHelemt(getHelmetData(runtimeContext))(shellBefore);
90
- shellChunkStatus = ShellChunkStatus.FINISH;
91
- safeEnqueue(encodeForWebStream(`${completedShellBefore}${beforeMark}${shellAfter}`));
92
- if (afterMark.length > 0) safeEnqueue(encodeForWebStream(afterMark));
93
- flushPendingScripts();
94
- }
95
- } else safeEnqueue(value);
96
- if (!isClosed) push();
97
- } catch (error) {
98
- __rspack_external__modern_js_runtime_extensions_ce611631.abortHeadRender(runtimeContext);
99
- if (!isClosed) {
100
- isClosed = true;
101
- try {
102
- controller.error(error);
103
- } catch {}
104
- }
105
- }
106
- }
107
- push();
106
+ bodyController = controller;
107
+ },
108
+ transform (chunk, controller) {
109
+ emit(decoder.decode(chunk, {
110
+ stream: true
111
+ }), controller);
108
112
  },
109
- cancel (reason) {
110
- __rspack_external__modern_js_runtime_extensions_ce611631.abortHeadRender(runtimeContext);
111
- reader.cancel(reason).catch(()=>{});
113
+ flush (controller) {
114
+ bodyOpen = false;
115
+ emit(decoder.decode(), controller);
116
+ if (shellChunkStatus !== ShellChunkStatus.FINISH) throw new Error('React SSR stream ended before the shell marker');
112
117
  }
113
118
  });
114
- return stream;
115
- } catch (e) {
116
- __rspack_external__modern_js_runtime_extensions_ce611631.abortHeadRender(runtimeContext);
117
- const fallbackHtml = `${shellBefore}${shellAfter}`;
118
- const stream = getReadableStreamFromString(fallbackHtml);
119
- return stream;
119
+ bodyPipe = pendingSource.pipeTo(body.writable);
120
+ bodyPipe.catch(()=>{});
121
+ pendingSource = body.readable;
122
+ const activeDeferreds = storage.useContext?.()?.activeDeferreds;
123
+ const entries = activeDeferreds instanceof Map ? Array.from(activeDeferreds.entries()) : [];
124
+ enqueueFromEntries(entries, config.nonce, (script)=>{
125
+ if (!bodyOpen) return;
126
+ if (shellChunkStatus === ShellChunkStatus.FINISH) try {
127
+ bodyController.enqueue(encoder.encode(script));
128
+ } catch {
129
+ bodyOpen = false;
130
+ }
131
+ else pendingScripts.push(script);
132
+ });
133
+ return observeSSRStream(pendingSource, {
134
+ lifecycle,
135
+ async onError (error) {
136
+ bodyOpen = false;
137
+ await bodyPipe?.catch(()=>{});
138
+ reportError(error);
139
+ },
140
+ signal: request.signal,
141
+ async onCancel (reason) {
142
+ bodyOpen = false;
143
+ await bodyPipe?.catch((error)=>{
144
+ if (error !== reason) throw error;
145
+ });
146
+ },
147
+ onComplete: ()=>bodyPipe
148
+ });
149
+ } catch (error) {
150
+ bodyOpen = false;
151
+ if (void 0 !== pendingSource) try {
152
+ await pendingSource.cancel(error);
153
+ await bodyPipe?.catch(()=>{});
154
+ } catch (cancelError) {
155
+ if (!request.signal.aborted) reportError(cancelError);
156
+ }
157
+ if (request.signal.aborted) {
158
+ lifecycle.finish({
159
+ status: 'cancelled',
160
+ reason: request.signal.reason
161
+ });
162
+ throw request.signal.reason;
163
+ }
164
+ lifecycle.finish({
165
+ status: 'fallback',
166
+ error
167
+ });
168
+ reportError(error);
169
+ const { shellBefore, shellAfter } = await getTemplates(htmlTemplate, {
170
+ ...templateOptions,
171
+ renderLevel: RenderLevel.CLIENT_RENDER,
172
+ helmetData: getHelmetData(extenders)
173
+ });
174
+ return observeSSRStream(getReadableStreamFromString(`${shellBefore}${shellAfter}`), {
175
+ lifecycle,
176
+ onError: reportError,
177
+ signal: request.signal
178
+ });
120
179
  }
121
180
  };
122
181
  export { createReadableStreamFromElement };
@@ -21,13 +21,13 @@ function isDeferredDataLike(v) {
21
21
  return hasPending && hasData;
22
22
  }
23
23
  function isPromiseLike(value) {
24
- return !!value && 'function' == typeof value.then;
24
+ return Boolean(value) && 'function' == typeof value.then;
25
25
  }
26
26
  function toErrorInfo(error) {
27
27
  if (shouldRedactServerError()) return {
28
28
  message: 'Unexpected Server Error'
29
29
  };
30
- if (error && 'object' == typeof error) {
30
+ if (null !== error && 'object' == typeof error) {
31
31
  const maybeMsg = error.message;
32
32
  const maybeStack = error.stack;
33
33
  return {
@@ -42,7 +42,7 @@ function toErrorInfo(error) {
42
42
  function buildDeferredDataScript(nonce, args) {
43
43
  const payload = JSON.stringify(args);
44
44
  const escaped = escapeAttr(payload);
45
- const nonceAttr = nonce ? ` nonce="${nonce}"` : '';
45
+ const nonceAttr = void 0 !== nonce && '' !== nonce ? ` nonce="${nonce}"` : '';
46
46
  return `<script async${nonceAttr} data-fn-name="r" data-script-src="modern-run-router-data-fn" data-fn-args='${escaped}' suppressHydrationWarning>${runRouterDataFnStr}</script>`;
47
47
  }
48
48
  function enqueueFromEntries(entries, nonce, emit) {
@@ -64,7 +64,7 @@ function createRenderStreaming(createReadableStreamPromise) {
64
64
  const end = time();
65
65
  const { runtimeContext, config, resource } = options;
66
66
  const { onError, onTiming } = options;
67
- const { htmlTemplate, entryName, moduleFederationCssAssets } = resource;
67
+ const { htmlTemplate, entryName } = resource;
68
68
  const ssrConfig = getSSRConfigByEntry(entryName, config.ssr, config.ssrByEntries);
69
69
  const StreamServerRootWrapper = ({ children })=>/*#__PURE__*/ jsxs(Fragment, {
70
70
  children: [
@@ -84,7 +84,7 @@ function createRenderStreaming(createReadableStreamPromise) {
84
84
  runtimeContext,
85
85
  ssrConfig,
86
86
  entryName,
87
- moduleFederationCssAssets,
87
+ resource,
88
88
  rscClientManifest: options.rscClientManifest,
89
89
  rscSSRManifest: options.rscSSRManifest,
90
90
  rscServerManifest: options.rscServerManifest,
@@ -3,17 +3,15 @@ import { time } from "@modern-js/runtime-utils/time";
3
3
  import { SSR_HYDRATION_ID_PREFIX } from "@modern-js/utils/universal/constants";
4
4
  import server from "react-dom/server";
5
5
  import { RenderLevel } from "../../constants.mjs";
6
- import { getGlobalInternalRuntimeContext } from "../../context/index.mjs";
7
- import { wrapRuntimeContextProvider } from "../../react/wrapper.mjs";
8
- import { CHUNK_CSS_PLACEHOLDER, HTML_PLACEHOLDER, SSR_DATA_PLACEHOLDER } from "../constants.mjs";
6
+ import { getGlobalEnableRsc, getGlobalInternalRuntimeContext } from "../../context/index.mjs";
7
+ import { wrapRuntimeComponentResolver, wrapRuntimeContextProvider } from "../../react/wrapper.mjs";
8
+ import { CHUNK_CSS_PLACEHOLDER, CHUNK_JS_PLACEHOLDER, HTML_PLACEHOLDER, SSR_DATA_PLACEHOLDER } from "../constants.mjs";
9
9
  import { createReplaceHelemt, getHelmetData } from "../helmet.mjs";
10
- import { replaceChunkJsPlaceholder } from "../scriptOrder.mjs";
11
- import { buildHtml } from "../shared.mjs";
10
+ import { buildHtml, createSSRRenderLifecycle, replaceSSRTemplateChunk } from "../shared.mjs";
12
11
  import { SSRErrors, SSRTimings } from "../tracer.mjs";
13
12
  import { getSSRConfigByEntry, safeReplace } from "../utils.mjs";
14
13
  import { LoadableCollector } from "./loadable.mjs";
15
14
  import { SSRDataCollector } from "./ssrData.mjs";
16
- import * as __rspack_external__modern_js_runtime_extensions_ce611631 from "@modern-js/runtime-extensions";
17
15
  const renderString = async (request, serverRoot, options)=>{
18
16
  const { resource, runtimeContext, config, onError, onTiming } = options;
19
17
  const tracer = {
@@ -21,7 +19,7 @@ const renderString = async (request, serverRoot, options)=>{
21
19
  onTiming
22
20
  };
23
21
  const routerContext = runtimeContext.routerContext;
24
- const { htmlTemplate, entryName, loadableStats, routeManifest, moduleFederationCssAssets } = resource;
22
+ const { htmlTemplate, entryName, loadableStats, routeManifest } = resource;
25
23
  const ssrConfig = getSSRConfigByEntry(entryName, config.ssr, config.ssrByEntries);
26
24
  const chunkSet = {
27
25
  renderLevel: RenderLevel.CLIENT_RENDER,
@@ -29,83 +27,121 @@ const renderString = async (request, serverRoot, options)=>{
29
27
  jsChunk: '',
30
28
  cssChunk: ''
31
29
  };
32
- const collectors = [
33
- new LoadableCollector({
34
- stats: loadableStats,
35
- nonce: config.nonce,
36
- routeManifest,
37
- runtimeContext,
38
- template: htmlTemplate,
39
- entryName,
40
- moduleFederationCssAssets,
41
- chunkSet,
42
- config
43
- }),
44
- new SSRDataCollector({
45
- runtimeContext,
46
- request,
47
- ssrConfig,
48
- ssrContext: runtimeContext.ssrContext,
49
- chunkSet,
50
- routerContext,
51
- nonce: config.nonce,
52
- useJsonScript: config.useJsonScript
53
- })
54
- ];
30
+ const collectors = [];
31
+ const lifecycle = createSSRRenderLifecycle(collectors);
32
+ const loadableCollector = new LoadableCollector({
33
+ stats: loadableStats,
34
+ nonce: config.nonce,
35
+ routeManifest,
36
+ template: htmlTemplate,
37
+ entryName,
38
+ chunkSet,
39
+ config,
40
+ lifecycle
41
+ });
42
+ collectors.push(loadableCollector, new SSRDataCollector({
43
+ runtimeContext,
44
+ request,
45
+ ssrConfig,
46
+ ssrContext: runtimeContext.ssrContext,
47
+ chunkSet,
48
+ routerContext,
49
+ nonce: config.nonce,
50
+ useJsonScript: config.useJsonScript,
51
+ lifecycle
52
+ }));
55
53
  const internalRuntimeContext = getGlobalInternalRuntimeContext();
56
54
  const hooks = internalRuntimeContext.hooks;
57
55
  const extraCollectors = hooks.extendStringSSRCollectors.call({
58
- chunkSet
56
+ chunkSet,
57
+ render: {
58
+ runtimeContext,
59
+ request,
60
+ resource,
61
+ config,
62
+ platform: 'node',
63
+ mode: 'string',
64
+ isRsc: true === getGlobalEnableRsc()
65
+ }
59
66
  });
60
67
  for (const c of extraCollectors)if (c) collectors.unshift(c);
61
- const rootElement = wrapRuntimeContextProvider(serverRoot, Object.assign(runtimeContext, {
68
+ let rootElement = wrapRuntimeContextProvider(serverRoot, Object.assign(runtimeContext, {
62
69
  ssr: true
63
70
  }));
64
- const html = await generateHtml(rootElement, htmlTemplate, chunkSet, collectors, runtimeContext.ssrContext?.htmlModifiers || [], runtimeContext, entryName, tracer);
71
+ if (true === getGlobalEnableRsc() && false === runtimeContext.isBrowser) rootElement = wrapRuntimeComponentResolver(rootElement, hooks);
72
+ const html = await generateHtml(rootElement, htmlTemplate, chunkSet, collectors, runtimeContext.ssrContext?.htmlModifiers || [], tracer, request.signal, lifecycle, loadableCollector.stylesheetInfo);
65
73
  return html;
66
74
  };
67
- async function generateHtml(App, htmlTemplate, chunkSet, collectors, htmlModifiers, runtimeContext, entryName, { onError, onTiming }) {
75
+ async function generateHtml(App, htmlTemplate, chunkSet, collectors, htmlModifiers, { onError, onTiming }, signal, lifecycle, stylesheetInfo) {
68
76
  let html = '';
69
77
  let helmetData;
70
- const finalApp = collectors.reduce((pre, creator)=>creator.collect?.(pre) || pre, App);
71
- __rspack_external__modern_js_runtime_extensions_ce611631.beginHeadRender(runtimeContext);
72
78
  try {
73
- const end = time();
74
- html = server.renderToString(finalApp, {
75
- identifierPrefix: SSR_HYDRATION_ID_PREFIX
79
+ signal.throwIfAborted();
80
+ try {
81
+ const finalApp = collectors.reduce((pre, creator)=>creator.collect?.(pre) || pre, App);
82
+ lifecycle.beforeReact();
83
+ const end = time();
84
+ html = server.renderToString(finalApp, {
85
+ identifierPrefix: SSR_HYDRATION_ID_PREFIX
86
+ });
87
+ html = lifecycle.completedBody(html, 'complete');
88
+ chunkSet.renderLevel = RenderLevel.SERVER_RENDER;
89
+ helmetData = getHelmetData(collectors);
90
+ const cost = end();
91
+ onTiming(SSRTimings.RENDER_HTML, cost);
92
+ } catch (error) {
93
+ lifecycle.finish({
94
+ status: 'fallback',
95
+ error
96
+ });
97
+ html = '';
98
+ chunkSet.renderLevel = RenderLevel.CLIENT_RENDER;
99
+ onError(error, SSRErrors.RENDER_HTML);
100
+ }
101
+ await Promise.all(collectors.map((component)=>component.effect()));
102
+ signal.throwIfAborted();
103
+ const { ssrScripts, cssChunk, jsChunk } = chunkSet;
104
+ const finalHtml = await buildHtml(htmlTemplate, [
105
+ createReplaceHtml(html),
106
+ (template)=>replaceSSRTemplateChunk({
107
+ name: "scripts",
108
+ template,
109
+ placeholder: CHUNK_JS_PLACEHOLDER,
110
+ content: jsChunk
111
+ }, lifecycle),
112
+ (template)=>replaceSSRTemplateChunk({
113
+ name: 'styles',
114
+ template,
115
+ placeholder: CHUNK_CSS_PLACEHOLDER,
116
+ content: cssChunk,
117
+ ...stylesheetInfo
118
+ }, lifecycle),
119
+ (template)=>replaceSSRTemplateChunk({
120
+ name: 'data',
121
+ template,
122
+ placeholder: SSR_DATA_PLACEHOLDER,
123
+ content: ssrScripts
124
+ }, lifecycle),
125
+ createReplaceHelemt(helmetData),
126
+ ...htmlModifiers
127
+ ]);
128
+ signal.throwIfAborted();
129
+ lifecycle.finish({
130
+ status: 'complete'
131
+ });
132
+ return finalHtml;
133
+ } catch (error) {
134
+ lifecycle.finish(signal.aborted ? {
135
+ status: 'cancelled',
136
+ reason: signal.reason
137
+ } : {
138
+ status: 'error',
139
+ error
76
140
  });
77
- html = __rspack_external__modern_js_runtime_extensions_ce611631.completeHeadRender(runtimeContext, html);
78
- chunkSet.renderLevel = RenderLevel.SERVER_RENDER;
79
- helmetData = getHelmetData(runtimeContext);
80
- const cost = end();
81
- onTiming(SSRTimings.RENDER_HTML, cost);
82
- } catch (e) {
83
- __rspack_external__modern_js_runtime_extensions_ce611631.abortHeadRender(runtimeContext);
84
- chunkSet.renderLevel = RenderLevel.CLIENT_RENDER;
85
- onError(e, SSRErrors.RENDER_HTML);
141
+ throw error;
86
142
  }
87
- await Promise.all(collectors.map((component)=>component.effect()));
88
- const { ssrScripts, cssChunk, jsChunk } = chunkSet;
89
- const finalHtml = await buildHtml(htmlTemplate, [
90
- createReplaceHtml(html),
91
- createReplaceChunkJs(jsChunk, entryName),
92
- createReplaceChunkCss(cssChunk),
93
- createReplaceSSRDataScript(ssrScripts, entryName),
94
- createReplaceHelemt(helmetData),
95
- ...htmlModifiers
96
- ]);
97
- return finalHtml;
98
143
  }
99
144
  function createReplaceHtml(html) {
100
145
  return (template)=>safeReplace(template, HTML_PLACEHOLDER, html);
101
146
  }
102
- function createReplaceSSRDataScript(data, entryName) {
103
- return (template)=>replaceChunkJsPlaceholder(template, data, entryName, SSR_DATA_PLACEHOLDER);
104
- }
105
- function createReplaceChunkJs(js, entryName) {
106
- return (template)=>replaceChunkJsPlaceholder(template, js, entryName);
107
- }
108
- function createReplaceChunkCss(css) {
109
- return (template)=>safeReplace(template, CHUNK_CSS_PLACEHOLDER, css);
110
- }
111
147
  export { renderString };
@@ -1,7 +1,5 @@
1
1
  import "node:module";
2
2
  import { ChunkExtractor } from "@loadable/server";
3
- import { createFederatedCssLinks } from "../federatedCss.mjs";
4
- import { getMatchedRouteChunks, orderHydrationScriptChunks } from "../scriptOrder.mjs";
5
3
  import { attributesToString, checkIsNode, hasStylesheetLink } from "../utils.mjs";
6
4
  import { fileURLToPath as __rspack_fileURLToPath } from "node:url";
7
5
  import { dirname as __rspack_dirname } from "node:path";
@@ -11,7 +9,7 @@ const extname = (uri)=>{
11
9
  return `.${uri?.split('.').pop()}` || '';
12
10
  };
13
11
  const generateChunks = (chunks, ext)=>chunks.filter((chunk)=>Boolean(chunk.url)).filter((chunk)=>extname(chunk.url).slice(1) === ext);
14
- const routeAssetToChunk = (asset)=>({
12
+ const assetToChunk = (asset)=>({
15
13
  chunk: asset,
16
14
  filename: asset.replace(/^\//, ''),
17
15
  linkType: 'preload',
@@ -57,16 +55,32 @@ class LoadableCollector {
57
55
  ]));
58
56
  } catch (e) {}
59
57
  const collectedChunks = extractor ? extractor.getChunkAssets(extractor.chunks) : [];
60
- const matchedRouteChunks = getMatchedRouteChunks(options.runtimeContext, options.routeManifest, routeAssetToChunk);
61
- const orderedScriptChunks = orderHydrationScriptChunks({
62
- asyncEntryChunks: asyncChunks,
63
- collectedChunks,
64
- matchedRouteChunks,
65
- entryName
66
- });
67
- const chunks = [].concat(asyncChunks).concat(collectedChunks).concat(matchedRouteChunks);
68
- const scriptChunks = generateChunks(orderedScriptChunks, 'js');
69
- const styleChunks = generateChunks(chunks, 'css');
58
+ const groups = [
59
+ {
60
+ name: 'async-entry',
61
+ assets: asyncChunks
62
+ },
63
+ {
64
+ name: 'loadable',
65
+ assets: collectedChunks
66
+ }
67
+ ];
68
+ const nativeChunks = [
69
+ ...asyncChunks,
70
+ ...collectedChunks
71
+ ];
72
+ const prepare = (kind)=>options.lifecycle?.transformAssets(groups, {
73
+ kind,
74
+ source: 'loadable',
75
+ template: options.template,
76
+ createAsset: assetToChunk
77
+ }) ?? nativeChunks;
78
+ const scriptChunks = generateChunks([
79
+ ...prepare("script")
80
+ ], 'js');
81
+ const styleChunks = generateChunks([
82
+ ...prepare('style')
83
+ ], 'css');
70
84
  if (extractor) {
71
85
  this.emitLoadableScripts(extractor);
72
86
  await this.emitScriptAssets(scriptChunks);
@@ -105,7 +119,7 @@ class LoadableCollector {
105
119
  chunkSet.jsChunk += scripts.filter((script)=>Boolean(script)).join('');
106
120
  }
107
121
  async emitStyleAssets(chunks) {
108
- const { template, chunkSet, config, moduleFederationCssAssets } = this.options;
122
+ const { template, chunkSet, config } = this.options;
109
123
  const { inlineStyles } = config;
110
124
  const atrributes = attributesToString(this.generateAttributes());
111
125
  const emittedAssetUrls = new Set();
@@ -120,11 +134,8 @@ class LoadableCollector {
120
134
  return link;
121
135
  }));
122
136
  chunkSet.cssChunk += css.filter((css)=>Boolean(css)).join('');
123
- chunkSet.cssChunk += createFederatedCssLinks(moduleFederationCssAssets, {
124
- template,
125
- attributes: this.generateAttributes(),
126
- existingAssets: emittedChunks.map((chunk)=>chunk.url)
127
- });
137
+ this.stylesheetInfo.emittedAssets = emittedChunks.map((chunk)=>chunk.url);
138
+ this.stylesheetInfo.attributes = this.generateAttributes();
128
139
  }
129
140
  generateAttributes(extraAtr = {}) {
130
141
  const { config } = this.options;
@@ -137,6 +148,10 @@ class LoadableCollector {
137
148
  };
138
149
  }
139
150
  constructor(options){
151
+ this.stylesheetInfo = {
152
+ emittedAssets: [],
153
+ attributes: {}
154
+ };
140
155
  this.options = options;
141
156
  }
142
157
  }
@@ -1,6 +1,5 @@
1
1
  import "node:module";
2
2
  import { serializeJson } from "@modern-js/runtime-utils/node";
3
- import { getRouterHydrationScripts, getRouterServerSnapshot } from "../../../router/runtime/lifecycle.mjs";
4
3
  import { ROUTER_DATA_JSON_ID, SSR_DATA_JSON_ID } from "../../constants.mjs";
5
4
  import { attributesToString, serializeErrors } from "../utils.mjs";
6
5
  function _check_private_redeclaration(obj, privateCollection) {
@@ -89,20 +88,15 @@ function getSSRData() {
89
88
  };
90
89
  }
91
90
  function getRouterData() {
92
- const { routerContext, runtimeContext } = _class_private_field_get(this, _options);
93
- const snapshotRouterData = getRouterServerSnapshot(runtimeContext)?.routerData;
94
- if (snapshotRouterData) return {
95
- loaderData: snapshotRouterData.loaderData,
96
- errors: serializeErrors(snapshotRouterData.errors || null)
97
- };
98
- return routerContext ? {
99
- loaderData: routerContext.loaderData,
100
- errors: serializeErrors(routerContext.errors)
91
+ const { routerContext, lifecycle } = _class_private_field_get(this, _options);
92
+ const data = lifecycle?.getRouterData() ?? routerContext;
93
+ return data ? {
94
+ loaderData: data.loaderData,
95
+ errors: serializeErrors(data.errors || null)
101
96
  } : void 0;
102
97
  }
103
98
  function getSSRDataScripts(ssrData, routerData) {
104
99
  const { nonce, useJsonScript = false } = _class_private_field_get(this, _options);
105
- const hydrationScripts = getRouterHydrationScripts(_class_private_field_get(this, _options).runtimeContext);
106
100
  const serializeSSRData = serializeJson(ssrData);
107
101
  const attrsStr = attributesToString({
108
102
  nonce
@@ -112,7 +106,6 @@ function getSSRDataScripts(ssrData, routerData) {
112
106
  const serializedRouterData = serializeJson(routerData);
113
107
  ssrDataScripts += useJsonScript ? `\n<script type="application/json" id="${ROUTER_DATA_JSON_ID}">${serializedRouterData}</script>` : `\n<script${attrsStr}>window._ROUTER_DATA = ${serializedRouterData}</script>`;
114
108
  }
115
- if (hydrationScripts.length) ssrDataScripts += `\n${hydrationScripts.join('\n')}`;
116
109
  return ssrDataScripts;
117
110
  }
118
111
  export { SSRDataCollector };