@bleedingdev/modern-js-runtime 3.2.0-ultramodern.11 → 3.2.0-ultramodern.111

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 (229) hide show
  1. package/dist/cjs/boundary-debugger/index.js +303 -0
  2. package/dist/cjs/cache/index.js +9 -5
  3. package/dist/cjs/cli/alias.js +9 -5
  4. package/dist/cjs/cli/code.js +9 -5
  5. package/dist/cjs/cli/constants.js +20 -16
  6. package/dist/cjs/cli/entry.js +9 -5
  7. package/dist/cjs/cli/index.js +9 -5
  8. package/dist/cjs/cli/ssr/index.js +14 -20
  9. package/dist/cjs/cli/ssr/loadable-bundler-plugin.js +9 -5
  10. package/dist/cjs/cli/ssr/mode.js +12 -8
  11. package/dist/cjs/cli/template.js +9 -5
  12. package/dist/cjs/cli/template.server.js +10 -5
  13. package/dist/cjs/common.js +14 -10
  14. package/dist/cjs/core/browser/hydrate.js +9 -5
  15. package/dist/cjs/core/browser/index.js +9 -5
  16. package/dist/cjs/core/browser/withCallback.js +9 -5
  17. package/dist/cjs/core/compat/hooks.js +14 -10
  18. package/dist/cjs/core/compat/index.js +9 -5
  19. package/dist/cjs/core/compat/requestContext.js +13 -9
  20. package/dist/cjs/core/config.js +12 -8
  21. package/dist/cjs/core/constants.js +15 -10
  22. package/dist/cjs/core/context/index.js +9 -5
  23. package/dist/cjs/core/context/monitors/default.js +12 -8
  24. package/dist/cjs/core/context/monitors/index.js +9 -5
  25. package/dist/cjs/core/context/monitors/index.server.js +9 -5
  26. package/dist/cjs/core/context/request/index.js +12 -8
  27. package/dist/cjs/core/context/request/index.server.js +9 -5
  28. package/dist/cjs/core/context/response/index.js +15 -11
  29. package/dist/cjs/core/context/response/index.server.js +9 -5
  30. package/dist/cjs/core/context/runtime.js +9 -5
  31. package/dist/cjs/core/context/serverPayload/index.js +13 -9
  32. package/dist/cjs/core/context/serverPayload/index.server.js +9 -5
  33. package/dist/cjs/core/index.js +9 -5
  34. package/dist/cjs/core/plugin/index.js +9 -5
  35. package/dist/cjs/core/react/index.js +9 -5
  36. package/dist/cjs/core/react/wrapper.js +18 -8
  37. package/dist/cjs/core/server/constants.js +15 -11
  38. package/dist/cjs/core/server/federatedCss.js +51 -0
  39. package/dist/cjs/core/server/helmet.js +17 -7
  40. package/dist/cjs/core/server/index.js +9 -5
  41. package/dist/cjs/core/server/react/index.js +9 -5
  42. package/dist/cjs/core/server/react/no-ssr-cache/index.js +9 -5
  43. package/dist/cjs/core/server/react/nossr/index.js +9 -5
  44. package/dist/cjs/core/server/requestHandler.js +9 -5
  45. package/dist/cjs/core/server/scriptOrder.js +63 -0
  46. package/dist/cjs/core/server/server.js +9 -5
  47. package/dist/cjs/core/server/shared.js +12 -8
  48. package/dist/cjs/core/server/stream/afterTemplate.js +22 -10
  49. package/dist/cjs/core/server/stream/beforeTemplate.js +22 -25
  50. package/dist/cjs/core/server/stream/beforeTemplate.worker.js +102 -0
  51. package/dist/cjs/core/server/stream/createReadableStream.js +16 -7
  52. package/dist/cjs/core/server/stream/createReadableStream.worker.js +13 -7
  53. package/dist/cjs/core/server/stream/deferredScript.js +9 -5
  54. package/dist/cjs/core/server/stream/index.js +9 -5
  55. package/dist/cjs/core/server/stream/shared.js +12 -6
  56. package/dist/cjs/core/server/stream/template.js +9 -5
  57. package/dist/cjs/core/server/string/index.js +25 -14
  58. package/dist/cjs/core/server/string/loadable.js +83 -15
  59. package/dist/cjs/core/server/string/ssrData.js +9 -5
  60. package/dist/cjs/core/server/tracer.js +13 -9
  61. package/dist/cjs/core/server/utils.js +9 -5
  62. package/dist/cjs/document/Body.js +9 -5
  63. package/dist/cjs/document/Comment.js +9 -5
  64. package/dist/cjs/document/DocumentContext.js +9 -5
  65. package/dist/cjs/document/DocumentStructureContext.js +9 -5
  66. package/dist/cjs/document/Head.js +9 -5
  67. package/dist/cjs/document/Html.js +9 -5
  68. package/dist/cjs/document/Links.js +9 -5
  69. package/dist/cjs/document/Root.js +9 -5
  70. package/dist/cjs/document/Script.js +9 -5
  71. package/dist/cjs/document/Scripts.js +9 -5
  72. package/dist/cjs/document/Style.js +9 -5
  73. package/dist/cjs/document/Title.js +9 -5
  74. package/dist/cjs/document/cli/index.js +12 -6
  75. package/dist/cjs/document/constants.js +9 -5
  76. package/dist/cjs/document/index.js +9 -5
  77. package/dist/cjs/exports/config-routes.js +12 -8
  78. package/dist/cjs/exports/head.js +209 -10
  79. package/dist/cjs/exports/loadable.js +51 -12
  80. package/dist/cjs/exports/tanstack-router.js +320 -59
  81. package/dist/cjs/index.js +9 -5
  82. package/dist/cjs/internal.js +9 -5
  83. package/dist/cjs/react-server.js +9 -5
  84. package/dist/cjs/router/cli/code/getClientRoutes/getRoutes.js +9 -5
  85. package/dist/cjs/router/cli/code/getClientRoutes/index.js +9 -5
  86. package/dist/cjs/router/cli/code/getClientRoutes/utils.js +9 -5
  87. package/dist/cjs/router/cli/code/index.js +9 -5
  88. package/dist/cjs/router/cli/code/inspect.js +9 -5
  89. package/dist/cjs/router/cli/code/makeLegalIdentifier.js +12 -8
  90. package/dist/cjs/router/cli/code/nestedRoutes.js +9 -5
  91. package/dist/cjs/router/cli/code/tanstackTypes.js +125 -56
  92. package/dist/cjs/router/cli/code/templates.js +24 -14
  93. package/dist/cjs/router/cli/code/utils.js +9 -5
  94. package/dist/cjs/router/cli/config-routes/converter.js +9 -5
  95. package/dist/cjs/router/cli/config-routes/parseRouteConfig.js +9 -5
  96. package/dist/cjs/router/cli/constants.js +23 -19
  97. package/dist/cjs/router/cli/entry.js +9 -5
  98. package/dist/cjs/router/cli/handler.js +9 -5
  99. package/dist/cjs/router/cli/index.js +9 -5
  100. package/dist/cjs/router/index.js +9 -5
  101. package/dist/cjs/router/internal.js +12 -8
  102. package/dist/cjs/router/runtime/CSSLinks.js +9 -5
  103. package/dist/cjs/router/runtime/DefaultNotFound.js +9 -5
  104. package/dist/cjs/router/runtime/DeferredDataScripts.js +12 -8
  105. package/dist/cjs/router/runtime/DeferredDataScripts.node.js +9 -5
  106. package/dist/cjs/router/runtime/PrefetchLink.js +162 -26
  107. package/dist/cjs/router/runtime/constants.js +9 -5
  108. package/dist/cjs/router/runtime/hooks.js +9 -5
  109. package/dist/cjs/router/runtime/index.js +15 -10
  110. package/dist/cjs/router/runtime/internal.js +9 -5
  111. package/dist/cjs/router/runtime/lifecycle.js +18 -14
  112. package/dist/cjs/router/runtime/plugin.js +9 -5
  113. package/dist/cjs/router/runtime/plugin.node.js +9 -5
  114. package/dist/cjs/router/runtime/routerHelper.js +9 -5
  115. package/dist/cjs/router/runtime/rsc-router.js +9 -5
  116. package/dist/cjs/router/runtime/rsc.js +9 -5
  117. package/dist/cjs/router/runtime/server.js +9 -5
  118. package/dist/cjs/router/runtime/tanstack/basepathRewrite.js +12 -8
  119. package/dist/cjs/router/runtime/tanstack/dataMutation.js +9 -5
  120. package/dist/cjs/router/runtime/tanstack/hydrationBoundary.js +48 -0
  121. package/dist/cjs/router/runtime/tanstack/outlet.js +58 -0
  122. package/dist/cjs/router/runtime/tanstack/plugin.js +199 -96
  123. package/dist/cjs/router/runtime/tanstack/plugin.node.js +13 -19
  124. package/dist/cjs/router/runtime/tanstack/prefetchLink.js +10 -6
  125. package/dist/cjs/router/runtime/tanstack/routeTree.js +73 -17
  126. package/dist/cjs/router/runtime/tanstack/rsc/ClientSlot.js +9 -5
  127. package/dist/cjs/router/runtime/tanstack/rsc/CompositeComponent.js +9 -5
  128. package/dist/cjs/router/runtime/tanstack/rsc/ReplayableStream.js +14 -9
  129. package/dist/cjs/router/runtime/tanstack/rsc/RscNodeRenderer.js +9 -5
  130. package/dist/cjs/router/runtime/tanstack/rsc/SlotContext.js +9 -5
  131. package/dist/cjs/router/runtime/tanstack/rsc/client.js +9 -5
  132. package/dist/cjs/router/runtime/tanstack/rsc/createRscProxy.js +9 -5
  133. package/dist/cjs/router/runtime/tanstack/rsc/index.js +9 -5
  134. package/dist/cjs/router/runtime/tanstack/rsc/server.js +9 -5
  135. package/dist/cjs/router/runtime/tanstack/rsc/slotUsageSanitizer.js +9 -5
  136. package/dist/cjs/router/runtime/tanstack/rsc/symbols.js +20 -15
  137. package/dist/cjs/router/runtime/utils.js +9 -5
  138. package/dist/cjs/router/runtime/withRouter.js +9 -5
  139. package/dist/cjs/rsc/client.js +12 -8
  140. package/dist/cjs/rsc/server.js +9 -5
  141. package/dist/cjs/rsc/server.worker.js +62 -0
  142. package/dist/cjs/ssr/index.node.js +13 -9
  143. package/dist/cjs/ssr/serverRender/renderToStream/buildTemplate.after.js +9 -5
  144. package/dist/cjs/ssr/serverRender/renderToString/entry.js +18 -13
  145. package/dist/cjs/ssr/serverRender/types.js +9 -5
  146. package/dist/esm/boundary-debugger/index.mjs +263 -0
  147. package/dist/esm/cli/ssr/index.mjs +5 -15
  148. package/dist/esm/cli/template.server.mjs +1 -0
  149. package/dist/esm/core/react/wrapper.mjs +9 -3
  150. package/dist/esm/core/server/federatedCss.mjs +13 -0
  151. package/dist/esm/core/server/helmet.mjs +5 -2
  152. package/dist/esm/core/server/scriptOrder.mjs +25 -0
  153. package/dist/esm/core/server/stream/afterTemplate.mjs +14 -6
  154. package/dist/esm/core/server/stream/beforeTemplate.mjs +14 -11
  155. package/dist/esm/core/server/stream/beforeTemplate.worker.mjs +64 -0
  156. package/dist/esm/core/server/stream/createReadableStream.mjs +7 -2
  157. package/dist/esm/core/server/stream/createReadableStream.worker.mjs +4 -2
  158. package/dist/esm/core/server/stream/shared.mjs +3 -1
  159. package/dist/esm/core/server/string/index.mjs +17 -9
  160. package/dist/esm/core/server/string/loadable.mjs +70 -9
  161. package/dist/esm/document/cli/index.mjs +3 -1
  162. package/dist/esm/exports/head.mjs +193 -4
  163. package/dist/esm/exports/loadable.mjs +26 -3
  164. package/dist/esm/exports/tanstack-router.mjs +2 -1
  165. package/dist/esm/router/cli/code/tanstackTypes.mjs +116 -51
  166. package/dist/esm/router/cli/code/templates.mjs +15 -9
  167. package/dist/esm/router/runtime/PrefetchLink.mjs +153 -21
  168. package/dist/esm/router/runtime/tanstack/hydrationBoundary.mjs +10 -0
  169. package/dist/esm/router/runtime/tanstack/outlet.mjs +17 -0
  170. package/dist/esm/router/runtime/tanstack/plugin.mjs +193 -94
  171. package/dist/esm/router/runtime/tanstack/plugin.node.mjs +5 -15
  172. package/dist/esm/router/runtime/tanstack/prefetchLink.mjs +1 -1
  173. package/dist/esm/router/runtime/tanstack/routeTree.mjs +65 -13
  174. package/dist/esm/rsc/server.worker.mjs +1 -0
  175. package/dist/esm/ssr/serverRender/renderToString/entry.mjs +9 -6
  176. package/dist/esm-node/boundary-debugger/index.mjs +264 -0
  177. package/dist/esm-node/cli/ssr/index.mjs +5 -15
  178. package/dist/esm-node/cli/template.server.mjs +1 -0
  179. package/dist/esm-node/core/react/wrapper.mjs +9 -3
  180. package/dist/esm-node/core/server/federatedCss.mjs +14 -0
  181. package/dist/esm-node/core/server/helmet.mjs +5 -2
  182. package/dist/esm-node/core/server/scriptOrder.mjs +26 -0
  183. package/dist/esm-node/core/server/stream/afterTemplate.mjs +14 -6
  184. package/dist/esm-node/core/server/stream/beforeTemplate.mjs +14 -11
  185. package/dist/esm-node/core/server/stream/beforeTemplate.worker.mjs +65 -0
  186. package/dist/esm-node/core/server/stream/createReadableStream.mjs +7 -2
  187. package/dist/esm-node/core/server/stream/createReadableStream.worker.mjs +4 -2
  188. package/dist/esm-node/core/server/stream/shared.mjs +3 -1
  189. package/dist/esm-node/core/server/string/index.mjs +17 -9
  190. package/dist/esm-node/core/server/string/loadable.mjs +70 -9
  191. package/dist/esm-node/document/cli/index.mjs +3 -1
  192. package/dist/esm-node/exports/head.mjs +193 -4
  193. package/dist/esm-node/exports/loadable.mjs +26 -3
  194. package/dist/esm-node/exports/tanstack-router.mjs +2 -1
  195. package/dist/esm-node/router/cli/code/tanstackTypes.mjs +116 -51
  196. package/dist/esm-node/router/cli/code/templates.mjs +15 -9
  197. package/dist/esm-node/router/runtime/PrefetchLink.mjs +153 -21
  198. package/dist/esm-node/router/runtime/tanstack/hydrationBoundary.mjs +11 -0
  199. package/dist/esm-node/router/runtime/tanstack/outlet.mjs +18 -0
  200. package/dist/esm-node/router/runtime/tanstack/plugin.mjs +193 -94
  201. package/dist/esm-node/router/runtime/tanstack/plugin.node.mjs +5 -15
  202. package/dist/esm-node/router/runtime/tanstack/prefetchLink.mjs +1 -1
  203. package/dist/esm-node/router/runtime/tanstack/routeTree.mjs +65 -13
  204. package/dist/esm-node/rsc/server.worker.mjs +2 -0
  205. package/dist/esm-node/ssr/serverRender/renderToString/entry.mjs +9 -6
  206. package/dist/types/boundary-debugger/index.d.ts +28 -0
  207. package/dist/types/cli/entry.d.ts +2 -2
  208. package/dist/types/core/context/response/index.server.d.ts +4 -1
  209. package/dist/types/core/context/runtime.d.ts +4 -0
  210. package/dist/types/core/plugin/index.d.ts +1 -1
  211. package/dist/types/core/server/federatedCss.d.ts +5 -0
  212. package/dist/types/core/server/helmet.d.ts +5 -3
  213. package/dist/types/core/server/scriptOrder.d.ts +1 -0
  214. package/dist/types/core/server/stream/beforeTemplate.d.ts +1 -0
  215. package/dist/types/core/server/stream/beforeTemplate.worker.d.ts +10 -0
  216. package/dist/types/core/server/stream/shared.d.ts +8 -0
  217. package/dist/types/core/server/string/loadable.d.ts +11 -0
  218. package/dist/types/core/server/utils.d.ts +11 -1
  219. package/dist/types/document/constants.d.ts +3 -1
  220. package/dist/types/exports/head.d.ts +10 -3
  221. package/dist/types/exports/loadable.d.ts +8 -1
  222. package/dist/types/exports/tanstack-router.d.ts +3 -1
  223. package/dist/types/router/cli/code/utils.d.ts +1 -1
  224. package/dist/types/router/cli/entry.d.ts +1 -1
  225. package/dist/types/router/runtime/PrefetchLink.d.ts +5 -1
  226. package/dist/types/router/runtime/tanstack/hydrationBoundary.d.ts +2 -0
  227. package/dist/types/router/runtime/tanstack/outlet.d.ts +2 -0
  228. package/dist/types/rsc/server.worker.d.ts +1 -0
  229. package/package.json +31 -25
@@ -1,7 +1,8 @@
1
1
  import { serializeJson } from "@modern-js/runtime-utils/node";
2
- import { getRouterHydrationScripts } from "../../../router/runtime/lifecycle.mjs";
2
+ import { getRouterHydrationScripts, getRouterMatchedRouteIds } from "../../../router/runtime/lifecycle.mjs";
3
3
  import { SSR_DATA_JSON_ID } from "../../constants.mjs";
4
4
  import { SSR_DATA_PLACEHOLDER } from "../constants.mjs";
5
+ import { injectBeforeHydrationEntryScript } from "../scriptOrder.mjs";
5
6
  import { buildHtml } from "../shared.mjs";
6
7
  import { attributesToString, safeReplace } from "../utils.mjs";
7
8
  function buildShellAfterTemplate(afterAppTemplate, options) {
@@ -22,11 +23,18 @@ function buildShellAfterTemplate(afterAppTemplate, options) {
22
23
  if (!routeManifest) return template;
23
24
  const { routeAssets } = routeManifest;
24
25
  if (!routeAssets) return template;
25
- const asyncEntry = routeAssets[`async-${entryName}`];
26
- if (asyncEntry) {
27
- const { assets } = asyncEntry;
28
- const jsChunkStr = assets?.filter((asset)=>asset.endsWith('.js'))?.map((asset)=>`<script src=${asset} nonce="${nonce}"></script>`).join(' ');
29
- if (jsChunkStr) return safeReplace(template, '<!--<?- chunksMap.js ?>-->', jsChunkStr);
26
+ const matchedRouteIds = getRouterMatchedRouteIds(runtimeContext) ?? [];
27
+ const assetEntries = [
28
+ ...matchedRouteIds.map((routeId)=>routeAssets[routeId]),
29
+ routeAssets[`async-${entryName}`]
30
+ ].filter(Boolean);
31
+ const jsAssets = Array.from(new Set(assetEntries.flatMap((entry)=>(entry.assets ?? []).filter((asset)=>asset.endsWith('.js')))));
32
+ const nonceAttr = nonce ? ` nonce="${nonce}"` : '';
33
+ const jsChunkStr = jsAssets.filter((asset)=>!template.includes(asset)).map((asset)=>`<script src=${asset}${nonceAttr}></script>`).join(' ');
34
+ if (jsChunkStr) {
35
+ const withoutPlaceholder = safeReplace(template, '<!--<?- chunksMap.js ?>-->', '');
36
+ const withEarlyScripts = injectBeforeHydrationEntryScript(withoutPlaceholder, jsChunkStr, entryName);
37
+ return withEarlyScripts !== withoutPlaceholder ? withEarlyScripts : safeReplace(template, '<!--<?- chunksMap.js ?>-->', jsChunkStr);
30
38
  }
31
39
  return template;
32
40
  }
@@ -1,8 +1,8 @@
1
1
  import { matchRoutes } from "@modern-js/runtime-utils/router";
2
- import react_helmet from "react-helmet";
3
2
  import { getRouterMatchedRouteIds } from "../../../router/runtime/lifecycle.mjs";
4
3
  import { CHUNK_CSS_PLACEHOLDER } from "../constants.mjs";
5
- import { createReplaceHelemt } from "../helmet.mjs";
4
+ import { createFederatedCssLinks } from "../federatedCss.mjs";
5
+ import { createReplaceHelemt, getHelmetData } from "../helmet.mjs";
6
6
  import { buildHtml } from "../shared.mjs";
7
7
  import { checkIsNode, safeReplace } from "../utils.mjs";
8
8
  const readAsset = async (chunk)=>{
@@ -17,8 +17,8 @@ const checkIsInline = (chunk, enableInline)=>{
17
17
  return Boolean(enableInline);
18
18
  };
19
19
  async function buildShellBeforeTemplate(beforeAppTemplate, options) {
20
- const { config, runtimeContext, styledComponentsStyleTags, entryName } = options;
21
- const helmetData = react_helmet.renderStatic();
20
+ const { config, runtimeContext, styledComponentsStyleTags, entryName, moduleFederationCssAssets } = options;
21
+ const helmetData = getHelmetData(runtimeContext);
22
22
  const callbacks = [
23
23
  createReplaceHelemt(helmetData),
24
24
  (template)=>injectCss(template, entryName, styledComponentsStyleTags)
@@ -27,33 +27,36 @@ async function buildShellBeforeTemplate(beforeAppTemplate, options) {
27
27
  async function injectCss(template, entryName, styledComponentsStyleTags) {
28
28
  let css = await getCssChunks();
29
29
  if (styledComponentsStyleTags) css += styledComponentsStyleTags;
30
+ css += createFederatedCssLinks(moduleFederationCssAssets, {
31
+ template,
32
+ existingAssets: css.match(/href="([^"]+)"/g)?.map((item)=>item.replace(/^href="/, '').replace(/"$/, ''))
33
+ });
30
34
  return safeReplace(template, CHUNK_CSS_PLACEHOLDER, css);
31
35
  async function getCssChunks() {
32
36
  const { routeManifest, routerContext, routes } = runtimeContext;
33
37
  if (!routeManifest) return '';
34
38
  const { routeAssets } = routeManifest;
35
- let matchedRouteManifests;
39
+ let matchedRouteManifests = [];
36
40
  const matchedRouteIds = getRouterMatchedRouteIds(runtimeContext);
37
41
  if (matchedRouteIds?.length) matchedRouteManifests = matchedRouteIds.map((routeId)=>routeAssets[routeId]).filter(Boolean);
38
- else {
39
- if (!routerContext || !routes) return '';
42
+ else if (routerContext && routes) {
40
43
  const matches = matchRoutes(routes, routerContext.location, routerContext.basename);
41
44
  matchedRouteManifests = matches?.map((match, index)=>{
42
45
  if (!index) return;
43
46
  const routeId = match.route.id;
44
47
  if (routeId) return routeAssets[routeId];
45
- }).filter(Boolean);
48
+ }).filter((routeManifest)=>void 0 !== routeManifest) ?? [];
46
49
  }
47
50
  const asyncEntry = routeAssets[`async-${entryName}`];
48
- if (asyncEntry) matchedRouteManifests?.push(asyncEntry);
49
- const cssChunks = matchedRouteManifests ? matchedRouteManifests.reduce((chunks, routeManifest)=>{
51
+ if (asyncEntry) matchedRouteManifests.push(asyncEntry);
52
+ const cssChunks = matchedRouteManifests.reduce((chunks, routeManifest)=>{
50
53
  const { referenceCssAssets = [] } = routeManifest;
51
54
  const _cssChunks = referenceCssAssets.filter((asset)=>asset?.endsWith('.css') && !template.includes(asset));
52
55
  return [
53
56
  ...chunks,
54
57
  ..._cssChunks
55
58
  ];
56
- }, []) : [];
59
+ }, []);
57
60
  const { inlineStyles } = config;
58
61
  const styles = await Promise.all(cssChunks.map(async (chunk)=>{
59
62
  const link = `<link href="${chunk}" rel="stylesheet" />`;
@@ -0,0 +1,64 @@
1
+ import { matchRoutes } from "@modern-js/runtime-utils/router";
2
+ import { getRouterMatchedRouteIds } from "../../../router/runtime/lifecycle.mjs";
3
+ 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 { safeReplace } from "../utils.mjs";
8
+ const checkIsInline = (chunk, enableInline)=>{
9
+ if ('production' !== process.env.NODE_ENV) return false;
10
+ if (enableInline instanceof RegExp) return enableInline.test(chunk);
11
+ return Boolean(enableInline);
12
+ };
13
+ async function buildShellBeforeTemplate(beforeAppTemplate, options) {
14
+ const { config, runtimeContext, styledComponentsStyleTags, entryName, moduleFederationCssAssets } = options;
15
+ const helmetData = getHelmetData(runtimeContext);
16
+ const callbacks = [
17
+ createReplaceHelemt(helmetData),
18
+ (template)=>injectCss(template, entryName, styledComponentsStyleTags)
19
+ ];
20
+ return buildHtml(beforeAppTemplate, callbacks);
21
+ async function injectCss(template, entryName, styledComponentsStyleTags) {
22
+ let css = await getCssChunks();
23
+ if (styledComponentsStyleTags) css += styledComponentsStyleTags;
24
+ css += createFederatedCssLinks(moduleFederationCssAssets, {
25
+ template,
26
+ existingAssets: css.match(/href="([^"]+)"/g)?.map((item)=>item.replace(/^href="/, '').replace(/"$/, ''))
27
+ });
28
+ return safeReplace(template, CHUNK_CSS_PLACEHOLDER, css);
29
+ async function getCssChunks() {
30
+ const { routeManifest, routerContext, routes } = runtimeContext;
31
+ if (!routeManifest) return '';
32
+ const { routeAssets } = routeManifest;
33
+ let matchedRouteManifests = [];
34
+ const matchedRouteIds = getRouterMatchedRouteIds(runtimeContext);
35
+ if (matchedRouteIds?.length) matchedRouteManifests = matchedRouteIds.map((routeId)=>routeAssets[routeId]).filter(Boolean);
36
+ else if (routerContext && routes) {
37
+ const matches = matchRoutes(routes, routerContext.location, routerContext.basename);
38
+ matchedRouteManifests = matches?.map((match, index)=>{
39
+ if (!index) return;
40
+ const routeId = match.route.id;
41
+ if (routeId) return routeAssets[routeId];
42
+ }).filter((routeManifest)=>void 0 !== routeManifest) ?? [];
43
+ }
44
+ const asyncEntry = routeAssets[`async-${entryName}`];
45
+ if (asyncEntry) matchedRouteManifests.push(asyncEntry);
46
+ const cssChunks = matchedRouteManifests.reduce((chunks, routeManifest)=>{
47
+ const { referenceCssAssets = [] } = routeManifest;
48
+ const _cssChunks = referenceCssAssets.filter((asset)=>asset?.endsWith('.css') && !template.includes(asset));
49
+ return [
50
+ ...chunks,
51
+ ..._cssChunks
52
+ ];
53
+ }, []);
54
+ const { inlineStyles } = config;
55
+ const styles = cssChunks.map((chunk)=>{
56
+ const link = `<link href="${chunk}" rel="stylesheet" />`;
57
+ checkIsInline(chunk, inlineStyles);
58
+ return link;
59
+ });
60
+ return `${styles.join('')}`;
61
+ }
62
+ }
63
+ }
64
+ export { buildShellBeforeTemplate };
@@ -15,7 +15,7 @@ const defaultExtender = {
15
15
  };
16
16
  const createReadableStreamFromElement = async (request, rootElement, options)=>{
17
17
  const { renderToPipeableStream } = await import("react-dom/server");
18
- const { runtimeContext, htmlTemplate, config, ssrConfig, entryName } = options;
18
+ const { runtimeContext, htmlTemplate, config, ssrConfig, entryName, moduleFederationCssAssets } = options;
19
19
  let shellChunkStatus = ShellChunkStatus.START;
20
20
  let renderLevel = RenderLevel.SERVER_RENDER;
21
21
  const forceStream2String = Boolean(process.env.MODERN_JS_STREAM_TO_STRING);
@@ -35,11 +35,14 @@ const createReadableStreamFromElement = async (request, rootElement, options)=>{
35
35
  if (extender.modifyRootElement) processedRootElement = extender.modifyRootElement(processedRootElement);
36
36
  });
37
37
  const chunkVec = [];
38
+ let hasStartedPipe = false;
38
39
  return new Promise((resolve)=>{
39
40
  const { pipe: reactStreamingPipe } = renderToPipeableStream(processedRootElement, {
40
41
  nonce: config.nonce,
41
42
  identifierPrefix: SSR_HYDRATION_ID_PREFIX,
42
43
  [onReady] () {
44
+ if (hasStartedPipe) return;
45
+ hasStartedPipe = true;
43
46
  let styledComponentsStyleTags = '';
44
47
  extenders.forEach((extender)=>{
45
48
  if (extender.getStyleTags) styledComponentsStyleTags += extender.getStyleTags();
@@ -52,6 +55,7 @@ const createReadableStreamFromElement = async (request, rootElement, options)=>{
52
55
  runtimeContext,
53
56
  config,
54
57
  entryName,
58
+ moduleFederationCssAssets,
55
59
  styledComponentsStyleTags
56
60
  }).then(({ shellAfter, shellBefore })=>{
57
61
  const pendingScripts = [];
@@ -109,7 +113,8 @@ const createReadableStreamFromElement = async (request, rootElement, options)=>{
109
113
  renderLevel,
110
114
  runtimeContext,
111
115
  entryName,
112
- config
116
+ config,
117
+ moduleFederationCssAssets
113
118
  }).then(({ shellAfter, shellBefore })=>{
114
119
  const fallbackHtml = `${shellBefore}${shellAfter}`;
115
120
  const readableStream = getReadableStreamFromString(fallbackHtml);
@@ -8,19 +8,21 @@ import { getTemplates } from "./template.mjs";
8
8
  const createReadableStreamFromElement = async (request, rootElement, options)=>{
9
9
  let shellChunkStatus = ShellChunkStatus.START;
10
10
  const chunkVec = [];
11
- const { htmlTemplate, runtimeContext, config, ssrConfig, entryName, rscRoot } = options;
11
+ const { htmlTemplate, runtimeContext, config, ssrConfig, entryName, moduleFederationCssAssets, rscManifest, rscRoot } = options;
12
12
  const { shellBefore, shellAfter } = await getTemplates(htmlTemplate, {
13
13
  renderLevel: RenderLevel.SERVER_RENDER,
14
14
  runtimeContext,
15
15
  ssrConfig,
16
16
  request,
17
17
  config,
18
- entryName
18
+ entryName,
19
+ moduleFederationCssAssets
19
20
  });
20
21
  try {
21
22
  const readableOriginal = await renderSSRStream(rootElement, {
22
23
  request,
23
24
  nonce: config.nonce,
25
+ rscManifest,
24
26
  rscRoot: rscRoot,
25
27
  routes: runtimeContext.routes,
26
28
  onError (error) {
@@ -63,7 +63,7 @@ function createRenderStreaming(createReadableStreamPromise) {
63
63
  const end = time();
64
64
  const { runtimeContext, config, resource } = options;
65
65
  const { onError, onTiming } = options;
66
- const { htmlTemplate, entryName } = resource;
66
+ const { htmlTemplate, entryName, moduleFederationCssAssets } = resource;
67
67
  const ssrConfig = getSSRConfigByEntry(entryName, config.ssr, config.ssrByEntries);
68
68
  const StreamServerRootWrapper = ({ children })=>/*#__PURE__*/ jsxs(Fragment, {
69
69
  children: [
@@ -83,9 +83,11 @@ function createRenderStreaming(createReadableStreamPromise) {
83
83
  runtimeContext,
84
84
  ssrConfig,
85
85
  entryName,
86
+ moduleFederationCssAssets,
86
87
  rscClientManifest: options.rscClientManifest,
87
88
  rscSSRManifest: options.rscSSRManifest,
88
89
  rscServerManifest: options.rscServerManifest,
90
+ rscManifest: options.rscManifest,
89
91
  rscRoot: options.rscRoot,
90
92
  onShellReady () {
91
93
  const cost = end();
@@ -1,12 +1,12 @@
1
1
  import { time } from "@modern-js/runtime-utils/time";
2
2
  import { SSR_HYDRATION_ID_PREFIX } from "@modern-js/utils/universal/constants";
3
3
  import server from "react-dom/server";
4
- import react_helmet from "react-helmet";
5
4
  import { RenderLevel } from "../../constants.mjs";
6
5
  import { getGlobalInternalRuntimeContext } from "../../context/index.mjs";
7
6
  import { wrapRuntimeContextProvider } from "../../react/wrapper.mjs";
8
7
  import { CHUNK_CSS_PLACEHOLDER, CHUNK_JS_PLACEHOLDER, HTML_PLACEHOLDER, SSR_DATA_PLACEHOLDER } from "../constants.mjs";
9
- import { createReplaceHelemt } from "../helmet.mjs";
8
+ import { createReplaceHelemt, getHelmetData } from "../helmet.mjs";
9
+ import { injectBeforeHydrationEntryScript } from "../scriptOrder.mjs";
10
10
  import { buildHtml } from "../shared.mjs";
11
11
  import { SSRErrors, SSRTimings } from "../tracer.mjs";
12
12
  import { getSSRConfigByEntry, safeReplace } from "../utils.mjs";
@@ -19,7 +19,7 @@ const renderString = async (request, serverRoot, options)=>{
19
19
  onTiming
20
20
  };
21
21
  const routerContext = runtimeContext.routerContext;
22
- const { htmlTemplate, entryName, loadableStats, routeManifest } = resource;
22
+ const { htmlTemplate, entryName, loadableStats, routeManifest, moduleFederationCssAssets } = resource;
23
23
  const ssrConfig = getSSRConfigByEntry(entryName, config.ssr, config.ssrByEntries);
24
24
  const chunkSet = {
25
25
  renderLevel: RenderLevel.CLIENT_RENDER,
@@ -32,8 +32,10 @@ const renderString = async (request, serverRoot, options)=>{
32
32
  stats: loadableStats,
33
33
  nonce: config.nonce,
34
34
  routeManifest,
35
+ runtimeContext,
35
36
  template: htmlTemplate,
36
37
  entryName,
38
+ moduleFederationCssAssets,
37
39
  chunkSet,
38
40
  config
39
41
  }),
@@ -57,10 +59,10 @@ const renderString = async (request, serverRoot, options)=>{
57
59
  const rootElement = wrapRuntimeContextProvider(serverRoot, Object.assign(runtimeContext, {
58
60
  ssr: true
59
61
  }));
60
- const html = await generateHtml(rootElement, htmlTemplate, chunkSet, collectors, runtimeContext.ssrContext?.htmlModifiers || [], tracer);
62
+ const html = await generateHtml(rootElement, htmlTemplate, chunkSet, collectors, runtimeContext.ssrContext?.htmlModifiers || [], runtimeContext, entryName, tracer);
61
63
  return html;
62
64
  };
63
- async function generateHtml(App, htmlTemplate, chunkSet, collectors, htmlModifiers, { onError, onTiming }) {
65
+ async function generateHtml(App, htmlTemplate, chunkSet, collectors, htmlModifiers, runtimeContext, entryName, { onError, onTiming }) {
64
66
  let html = '';
65
67
  let helmetData;
66
68
  const finalApp = collectors.reduce((pre, creator)=>creator.collect?.(pre) || pre, App);
@@ -70,7 +72,7 @@ async function generateHtml(App, htmlTemplate, chunkSet, collectors, htmlModifie
70
72
  identifierPrefix: SSR_HYDRATION_ID_PREFIX
71
73
  });
72
74
  chunkSet.renderLevel = RenderLevel.SERVER_RENDER;
73
- helmetData = react_helmet.renderStatic();
75
+ helmetData = getHelmetData(runtimeContext);
74
76
  const cost = end();
75
77
  onTiming(SSRTimings.RENDER_HTML, cost);
76
78
  } catch (e) {
@@ -81,7 +83,7 @@ async function generateHtml(App, htmlTemplate, chunkSet, collectors, htmlModifie
81
83
  const { ssrScripts, cssChunk, jsChunk } = chunkSet;
82
84
  const finalHtml = await buildHtml(htmlTemplate, [
83
85
  createReplaceHtml(html),
84
- createReplaceChunkJs(jsChunk),
86
+ createReplaceChunkJs(jsChunk, entryName),
85
87
  createReplaceChunkCss(cssChunk),
86
88
  createReplaceSSRDataScript(ssrScripts),
87
89
  createReplaceHelemt(helmetData),
@@ -95,8 +97,14 @@ function createReplaceHtml(html) {
95
97
  function createReplaceSSRDataScript(data) {
96
98
  return (template)=>safeReplace(template, SSR_DATA_PLACEHOLDER, data);
97
99
  }
98
- function createReplaceChunkJs(js) {
99
- return (template)=>safeReplace(template, CHUNK_JS_PLACEHOLDER, js);
100
+ function createReplaceChunkJs(js, entryName) {
101
+ return (template)=>{
102
+ if (!js) return safeReplace(template, CHUNK_JS_PLACEHOLDER, '');
103
+ const withoutPlaceholder = safeReplace(template, CHUNK_JS_PLACEHOLDER, '');
104
+ const withEarlyScripts = injectBeforeHydrationEntryScript(withoutPlaceholder, js, entryName);
105
+ if (withEarlyScripts !== withoutPlaceholder) return withEarlyScripts;
106
+ return safeReplace(template, CHUNK_JS_PLACEHOLDER, js);
107
+ };
100
108
  }
101
109
  function createReplaceChunkCss(css) {
102
110
  return (template)=>safeReplace(template, CHUNK_CSS_PLACEHOLDER, css);
@@ -1,10 +1,39 @@
1
1
  import { ChunkExtractor } from "@loadable/server";
2
+ import { getRouterMatchedRouteIds } from "../../../router/runtime/lifecycle.mjs";
3
+ import { createFederatedCssLinks } from "../federatedCss.mjs";
2
4
  import { attributesToString, checkIsNode } from "../utils.mjs";
3
5
  const extname = (uri)=>{
4
6
  if ('string' != typeof uri || !uri.includes('.')) return '';
5
7
  return `.${uri?.split('.').pop()}` || '';
6
8
  };
7
9
  const generateChunks = (chunks, ext)=>chunks.filter((chunk)=>Boolean(chunk.url)).filter((chunk)=>extname(chunk.url).slice(1) === ext);
10
+ const dedupeChunksByUrl = (chunks)=>{
11
+ const seen = new Set();
12
+ return chunks.filter((chunk)=>{
13
+ if (!chunk.url || seen.has(chunk.url)) return false;
14
+ seen.add(chunk.url);
15
+ return true;
16
+ });
17
+ };
18
+ const isAsyncEntryScriptChunk = (chunk, entryName)=>{
19
+ if (!chunk.url?.endsWith('.js')) return false;
20
+ const asyncEntryName = `async-${entryName}`;
21
+ const filename = chunk.filename || chunk.url;
22
+ const basename = filename.split('/').pop() || filename;
23
+ return basename === `${asyncEntryName}.js` || basename.startsWith(`${asyncEntryName}.`) || basename.startsWith(`${asyncEntryName}-`);
24
+ };
25
+ const orderHydrationScriptChunks = ({ asyncEntryChunks, collectedChunks, matchedRouteChunks, entryName })=>{
26
+ const asyncEntryScriptChunks = [];
27
+ const asyncEntryDependencyChunks = [];
28
+ for (const chunk of asyncEntryChunks)if (isAsyncEntryScriptChunk(chunk, entryName)) asyncEntryScriptChunks.push(chunk);
29
+ else asyncEntryDependencyChunks.push(chunk);
30
+ return dedupeChunksByUrl([
31
+ ...asyncEntryDependencyChunks,
32
+ ...collectedChunks,
33
+ ...matchedRouteChunks,
34
+ ...asyncEntryScriptChunks
35
+ ]);
36
+ };
8
37
  const checkIsInline = (chunk, enableInline)=>{
9
38
  if ('production' !== process.env.NODE_ENV) return false;
10
39
  if (enableInline instanceof RegExp) return enableInline.test(chunk.url);
@@ -21,6 +50,20 @@ class LoadableCollector {
21
50
  const { routeManifest, entryName } = this.options;
22
51
  return routeManifest?.routeAssets?.[entryName]?.assets;
23
52
  }
53
+ getMatchedRouteChunks() {
54
+ const { routeManifest, runtimeContext } = this.options;
55
+ const routeAssets = routeManifest?.routeAssets;
56
+ if (!routeAssets) return [];
57
+ const matchedRouteIds = getRouterMatchedRouteIds(runtimeContext) ?? [];
58
+ return matchedRouteIds.flatMap((routeId)=>{
59
+ const routeAsset = routeAssets[routeId];
60
+ return (routeAsset?.assets ?? []).map((asset)=>({
61
+ filename: asset.replace(/^\//, ''),
62
+ path: asset,
63
+ url: asset
64
+ }));
65
+ });
66
+ }
24
67
  collect(comopnent) {
25
68
  const { stats, entryName } = this.options;
26
69
  if (!stats) return comopnent;
@@ -33,20 +76,29 @@ class LoadableCollector {
33
76
  return this.extractor.collectChunks(comopnent);
34
77
  }
35
78
  async effect() {
36
- if (!this.extractor) return;
37
79
  const { extractor, options } = this;
38
80
  const { entryName, config } = options;
39
81
  const asyncChunks = [];
40
- if (config.enableAsyncEntry) try {
82
+ if (extractor && config.enableAsyncEntry) try {
41
83
  asyncChunks.push(...extractor.getChunkAssets([
42
84
  `async-${entryName}`
43
85
  ]));
44
86
  } catch (e) {}
45
- const chunks = [].concat(asyncChunks).concat(extractor.getChunkAssets(extractor.chunks));
46
- const scriptChunks = generateChunks(chunks, 'js');
87
+ const collectedChunks = extractor ? extractor.getChunkAssets(extractor.chunks) : [];
88
+ const matchedRouteChunks = this.getMatchedRouteChunks();
89
+ const orderedScriptChunks = orderHydrationScriptChunks({
90
+ asyncEntryChunks: asyncChunks,
91
+ collectedChunks,
92
+ matchedRouteChunks,
93
+ entryName
94
+ });
95
+ const chunks = [].concat(asyncChunks).concat(collectedChunks).concat(matchedRouteChunks);
96
+ const scriptChunks = generateChunks(orderedScriptChunks, 'js');
47
97
  const styleChunks = generateChunks(chunks, 'css');
48
- this.emitLoadableScripts(extractor);
49
- await this.emitScriptAssets(scriptChunks);
98
+ if (extractor) {
99
+ this.emitLoadableScripts(extractor);
100
+ await this.emitScriptAssets(scriptChunks);
101
+ }
50
102
  await this.emitStyleAssets(styleChunks);
51
103
  }
52
104
  emitLoadableScripts(extractor) {
@@ -81,19 +133,28 @@ class LoadableCollector {
81
133
  chunkSet.jsChunk += scripts.filter((script)=>Boolean(script)).join('');
82
134
  }
83
135
  async emitStyleAssets(chunks) {
84
- const { template, chunkSet, config, entryName } = this.options;
136
+ const { template, chunkSet, config, moduleFederationCssAssets } = this.options;
85
137
  const { inlineStyles } = config;
86
138
  const atrributes = attributesToString(this.generateAttributes());
87
139
  const linkRegExp = /<link .*?href="([^"]+)".*?>/g;
88
140
  const matchs = template.matchAll(linkRegExp);
89
141
  const existedLinks = [];
90
142
  for (const match of matchs)existedLinks.push(match[1]);
91
- const css = await Promise.all(chunks.filter((chunk)=>!existedLinks.includes(chunk.url) && !this.existsAssets?.includes(chunk.path)).map(async (chunk)=>{
143
+ const emittedChunks = chunks.filter((chunk)=>!existedLinks.includes(chunk.url) && !this.existsAssets?.includes(chunk.path));
144
+ const css = await Promise.all(emittedChunks.map(async (chunk)=>{
92
145
  const link = `<link${atrributes} href="${chunk.url}" rel="stylesheet" />`;
93
146
  if (checkIsNode() && checkIsInline(chunk, inlineStyles)) return readAsset(chunk).then((content)=>`<style>${content}</style>`).catch((_)=>link);
94
147
  return link;
95
148
  }));
96
149
  chunkSet.cssChunk += css.filter((css)=>Boolean(css)).join('');
150
+ chunkSet.cssChunk += createFederatedCssLinks(moduleFederationCssAssets, {
151
+ template,
152
+ attributes: this.generateAttributes(),
153
+ existingAssets: [
154
+ ...existedLinks,
155
+ ...emittedChunks.map((chunk)=>chunk.url)
156
+ ]
157
+ });
97
158
  }
98
159
  generateAttributes(extraAtr = {}) {
99
160
  const { config } = this.options;
@@ -109,4 +170,4 @@ class LoadableCollector {
109
170
  this.options = options;
110
171
  }
111
172
  }
112
- export { LoadableCollector };
173
+ export { LoadableCollector, orderHydrationScriptChunks };
@@ -299,7 +299,7 @@ const documentPlugin = ()=>({
299
299
  const { entrypoints, internalDirectory, appDirectory } = api.getAppContext();
300
300
  const documentFilePath = getDocumentByEntryName(entrypoints, entryName, appDirectory);
301
301
  if (!documentFilePath) return null;
302
- return async ({ htmlPlugin })=>{
302
+ return async (templateData)=>{
303
303
  const config = api.getNormalizedConfig();
304
304
  const documentParams = getDocParams({
305
305
  config: config,
@@ -318,6 +318,8 @@ const documentPlugin = ()=>({
318
318
  debug("entry %s's document jsx rendered html: %o", entryName, html);
319
319
  const { partialsByEntrypoint } = api.getAppContext();
320
320
  html = processPartials(html, entryName, partialsByEntrypoint || {});
321
+ const htmlPlugin = templateData.htmlPlugin || templateData.htmlWebpackPlugin || templateData.htmlRspackPlugin;
322
+ if (!htmlPlugin) throw new Error('Failed to get HTML plugin tags from template parameters.');
321
323
  const { scripts, links, metas, titles } = extractHtmlTags(htmlPlugin, templateParameters);
322
324
  return processPlaceholders(html, config, scripts, links, metas, titles);
323
325
  };