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

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