@bleedingdev/modern-js-runtime 3.9.0-ultramodern.1 → 3.9.0-ultramodern.11

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 (166) 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/core/browser/hydrate.js +6 -1
  4. package/dist/cjs/core/context/index.js +4 -43
  5. package/dist/cjs/core/context/public.js +4 -7
  6. package/dist/cjs/core/context/runtime.js +17 -5
  7. package/dist/cjs/core/react/wrapper.js +22 -65
  8. package/dist/cjs/core/server/helmet.js +5 -4
  9. package/dist/cjs/core/server/requestResponse.js +4 -4
  10. package/dist/cjs/core/server/routerCleanup.js +2 -2
  11. package/dist/cjs/core/server/shared.js +171 -4
  12. package/dist/cjs/core/server/stream/afterTemplate.js +21 -16
  13. package/dist/cjs/core/server/stream/beforeTemplate.js +34 -25
  14. package/dist/cjs/core/server/stream/beforeTemplate.worker.js +28 -21
  15. package/dist/cjs/core/server/stream/createReadableStream.js +208 -123
  16. package/dist/cjs/core/server/stream/createReadableStream.worker.js +159 -90
  17. package/dist/cjs/core/server/stream/deferredScript.js +3 -3
  18. package/dist/cjs/core/server/stream/shared.js +2 -2
  19. package/dist/cjs/core/server/string/index.js +100 -64
  20. package/dist/cjs/core/server/string/loadable.js +34 -19
  21. package/dist/cjs/core/server/string/ssrData.js +5 -12
  22. package/dist/cjs/core/server/utils.js +1 -2
  23. package/dist/cjs/exports/head.js +7 -14
  24. package/dist/cjs/router/runtime/PrefetchLink.js +67 -123
  25. package/dist/cjs/router/runtime/hooks.js +13 -2
  26. package/dist/cjs/router/runtime/internal.js +7 -45
  27. package/dist/cjs/router/runtime/plugin.js +2 -8
  28. package/dist/cjs/router/runtime/plugin.node.js +2 -30
  29. package/dist/cjs/router/runtime/redirect.js +1 -1
  30. package/dist/esm/cli/code.mjs +3 -1
  31. package/dist/esm/cli/ssr/index.mjs +3 -72
  32. package/dist/esm/core/browser/hydrate.mjs +7 -2
  33. package/dist/esm/core/context/index.mjs +2 -5
  34. package/dist/esm/core/context/public.mjs +1 -5
  35. package/dist/esm/core/context/runtime.mjs +13 -4
  36. package/dist/esm/core/react/wrapper.mjs +21 -67
  37. package/dist/esm/core/server/helmet.mjs +5 -4
  38. package/dist/esm/core/server/requestResponse.mjs +3 -3
  39. package/dist/esm/core/server/routerCleanup.mjs +1 -1
  40. package/dist/esm/core/server/shared.mjs +153 -1
  41. package/dist/esm/core/server/stream/afterTemplate.mjs +23 -18
  42. package/dist/esm/core/server/stream/beforeTemplate.mjs +37 -28
  43. package/dist/esm/core/server/stream/beforeTemplate.worker.mjs +31 -24
  44. package/dist/esm/core/server/stream/createReadableStream.mjs +207 -122
  45. package/dist/esm/core/server/stream/createReadableStream.worker.mjs +149 -90
  46. package/dist/esm/core/server/stream/deferredScript.mjs +3 -3
  47. package/dist/esm/core/server/stream/shared.mjs +2 -2
  48. package/dist/esm/core/server/string/index.mjs +104 -68
  49. package/dist/esm/core/server/string/loadable.mjs +34 -19
  50. package/dist/esm/core/server/string/ssrData.mjs +5 -12
  51. package/dist/esm/core/server/utils.mjs +1 -2
  52. package/dist/esm/exports/head.mjs +7 -14
  53. package/dist/esm/router/runtime/PrefetchLink.mjs +67 -123
  54. package/dist/esm/router/runtime/hooks.mjs +9 -1
  55. package/dist/esm/router/runtime/internal.mjs +2 -33
  56. package/dist/esm/router/runtime/plugin.mjs +1 -7
  57. package/dist/esm/router/runtime/plugin.node.mjs +1 -29
  58. package/dist/esm/router/runtime/redirect.mjs +1 -1
  59. package/dist/esm-node/cli/code.mjs +3 -1
  60. package/dist/esm-node/cli/ssr/index.mjs +3 -72
  61. package/dist/esm-node/core/browser/hydrate.mjs +7 -2
  62. package/dist/esm-node/core/context/index.mjs +2 -5
  63. package/dist/esm-node/core/context/public.mjs +1 -5
  64. package/dist/esm-node/core/context/runtime.mjs +13 -4
  65. package/dist/esm-node/core/react/wrapper.mjs +21 -67
  66. package/dist/esm-node/core/server/helmet.mjs +5 -4
  67. package/dist/esm-node/core/server/requestResponse.mjs +3 -3
  68. package/dist/esm-node/core/server/routerCleanup.mjs +1 -1
  69. package/dist/esm-node/core/server/shared.mjs +153 -1
  70. package/dist/esm-node/core/server/stream/afterTemplate.mjs +23 -18
  71. package/dist/esm-node/core/server/stream/beforeTemplate.mjs +37 -28
  72. package/dist/esm-node/core/server/stream/beforeTemplate.worker.mjs +31 -24
  73. package/dist/esm-node/core/server/stream/createReadableStream.mjs +207 -122
  74. package/dist/esm-node/core/server/stream/createReadableStream.worker.mjs +149 -90
  75. package/dist/esm-node/core/server/stream/deferredScript.mjs +3 -3
  76. package/dist/esm-node/core/server/stream/shared.mjs +2 -2
  77. package/dist/esm-node/core/server/string/index.mjs +104 -68
  78. package/dist/esm-node/core/server/string/loadable.mjs +34 -19
  79. package/dist/esm-node/core/server/string/ssrData.mjs +5 -12
  80. package/dist/esm-node/core/server/utils.mjs +1 -2
  81. package/dist/esm-node/exports/head.mjs +7 -14
  82. package/dist/esm-node/router/runtime/PrefetchLink.mjs +67 -123
  83. package/dist/esm-node/router/runtime/hooks.mjs +9 -1
  84. package/dist/esm-node/router/runtime/internal.mjs +2 -33
  85. package/dist/esm-node/router/runtime/plugin.mjs +1 -7
  86. package/dist/esm-node/router/runtime/plugin.node.mjs +1 -29
  87. package/dist/esm-node/router/runtime/redirect.mjs +1 -1
  88. package/dist/types/cli/ssr/index.d.ts +0 -3
  89. package/dist/types/core/context/index.d.ts +4 -6
  90. package/dist/types/core/context/public.d.ts +1 -23
  91. package/dist/types/core/context/runtime.d.ts +26 -2
  92. package/dist/types/core/react/wrapper.d.ts +6 -0
  93. package/dist/types/core/server/helmet.d.ts +4 -5
  94. package/dist/types/core/server/requestHandler.d.ts +2 -2
  95. package/dist/types/core/server/requestResponse.d.ts +1 -1
  96. package/dist/types/core/server/routerCleanup.d.ts +1 -1
  97. package/dist/types/core/server/shared.d.ts +24 -1
  98. package/dist/types/core/server/stream/afterTemplate.d.ts +2 -1
  99. package/dist/types/core/server/stream/beforeTemplate.d.ts +4 -1
  100. package/dist/types/core/server/stream/beforeTemplate.worker.d.ts +4 -1
  101. package/dist/types/core/server/stream/shared.d.ts +2 -2
  102. package/dist/types/core/server/string/loadable.d.ts +6 -3
  103. package/dist/types/core/server/string/ssrData.d.ts +2 -1
  104. package/dist/types/core/server/string/types.d.ts +1 -5
  105. package/dist/types/core/server/tracer.d.ts +1 -1
  106. package/dist/types/core/server/utils.d.ts +1 -1
  107. package/dist/types/core/types.d.ts +1 -2
  108. package/dist/types/exports/head.d.ts +2 -2
  109. package/dist/types/router/runtime/PrefetchLink.d.ts +27 -2
  110. package/dist/types/router/runtime/hooks.d.ts +19 -2
  111. package/dist/types/router/runtime/internal.d.ts +4 -21
  112. package/dist/types/router/runtime/types.d.ts +2 -43
  113. package/package.json +18 -46
  114. package/rstest.config.mts +32 -2
  115. package/dist/cjs/boundary-debugger/index.js +0 -317
  116. package/dist/cjs/core/context/extensions.js +0 -74
  117. package/dist/cjs/core/context/helmetContext.js +0 -54
  118. package/dist/cjs/core/server/federatedCss.js +0 -58
  119. package/dist/cjs/core/server/scriptOrder.js +0 -140
  120. package/dist/cjs/module-federation/consume-surface.js +0 -199
  121. package/dist/cjs/module-federation/distributed-ssr.js +0 -135
  122. package/dist/cjs/module-federation/index.js +0 -316
  123. package/dist/cjs/module-federation/last-known-good.js +0 -157
  124. package/dist/cjs/module-federation/manifest-recovery-runtime-plugin.js +0 -129
  125. package/dist/cjs/module-federation/surface-resolution-types.js +0 -61
  126. package/dist/cjs/router/runtime/lifecycle.js +0 -167
  127. package/dist/cjs/router/runtime/provider.js +0 -153
  128. package/dist/esm/boundary-debugger/index.mjs +0 -277
  129. package/dist/esm/core/context/extensions.mjs +0 -33
  130. package/dist/esm/core/context/helmetContext.mjs +0 -13
  131. package/dist/esm/core/server/federatedCss.mjs +0 -20
  132. package/dist/esm/core/server/scriptOrder.mjs +0 -90
  133. package/dist/esm/module-federation/consume-surface.mjs +0 -158
  134. package/dist/esm/module-federation/distributed-ssr.mjs +0 -82
  135. package/dist/esm/module-federation/index.mjs +0 -115
  136. package/dist/esm/module-federation/last-known-good.mjs +0 -113
  137. package/dist/esm/module-federation/manifest-recovery-runtime-plugin.mjs +0 -89
  138. package/dist/esm/module-federation/surface-resolution-types.mjs +0 -8
  139. package/dist/esm/router/runtime/lifecycle.mjs +0 -105
  140. package/dist/esm/router/runtime/provider.mjs +0 -100
  141. package/dist/esm-node/boundary-debugger/index.mjs +0 -278
  142. package/dist/esm-node/core/context/extensions.mjs +0 -34
  143. package/dist/esm-node/core/context/helmetContext.mjs +0 -14
  144. package/dist/esm-node/core/server/federatedCss.mjs +0 -21
  145. package/dist/esm-node/core/server/scriptOrder.mjs +0 -91
  146. package/dist/esm-node/module-federation/consume-surface.mjs +0 -159
  147. package/dist/esm-node/module-federation/distributed-ssr.mjs +0 -83
  148. package/dist/esm-node/module-federation/index.mjs +0 -116
  149. package/dist/esm-node/module-federation/last-known-good.mjs +0 -114
  150. package/dist/esm-node/module-federation/manifest-recovery-runtime-plugin.mjs +0 -90
  151. package/dist/esm-node/module-federation/surface-resolution-types.mjs +0 -9
  152. package/dist/esm-node/router/runtime/lifecycle.mjs +0 -106
  153. package/dist/esm-node/router/runtime/provider.mjs +0 -101
  154. package/dist/types/boundary-debugger/index.d.ts +0 -28
  155. package/dist/types/core/context/extensions.d.ts +0 -35
  156. package/dist/types/core/context/helmetContext.d.ts +0 -10
  157. package/dist/types/core/server/federatedCss.d.ts +0 -5
  158. package/dist/types/core/server/scriptOrder.d.ts +0 -25
  159. package/dist/types/module-federation/consume-surface.d.ts +0 -104
  160. package/dist/types/module-federation/distributed-ssr.d.ts +0 -61
  161. package/dist/types/module-federation/index.d.ts +0 -71
  162. package/dist/types/module-federation/last-known-good.d.ts +0 -52
  163. package/dist/types/module-federation/manifest-recovery-runtime-plugin.d.ts +0 -25
  164. package/dist/types/module-federation/surface-resolution-types.d.ts +0 -23
  165. package/dist/types/router/runtime/lifecycle.d.ts +0 -27
  166. package/dist/types/router/runtime/provider.d.ts +0 -78
@@ -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, moduleFederationCssAssets } = resource;
66
+ const { htmlTemplate, entryName } = resource;
67
67
  const ssrConfig = getSSRConfigByEntry(entryName, config.ssr, config.ssrByEntries);
68
68
  const StreamServerRootWrapper = ({ children })=>/*#__PURE__*/ jsxs(Fragment, {
69
69
  children: [
@@ -83,7 +83,7 @@ function createRenderStreaming(createReadableStreamPromise) {
83
83
  runtimeContext,
84
84
  ssrConfig,
85
85
  entryName,
86
- moduleFederationCssAssets,
86
+ resource,
87
87
  rscClientManifest: options.rscClientManifest,
88
88
  rscSSRManifest: options.rscSSRManifest,
89
89
  rscServerManifest: options.rscServerManifest,
@@ -2,17 +2,15 @@ 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
4
  import { RenderLevel } from "../../constants.mjs";
5
- import { getGlobalInternalRuntimeContext } from "../../context/index.mjs";
6
- import { wrapRuntimeContextProvider } from "../../react/wrapper.mjs";
7
- import { CHUNK_CSS_PLACEHOLDER, HTML_PLACEHOLDER, SSR_DATA_PLACEHOLDER } from "../constants.mjs";
5
+ import { getGlobalEnableRsc, getGlobalInternalRuntimeContext } from "../../context/index.mjs";
6
+ import { wrapRuntimeComponentResolver, wrapRuntimeContextProvider } from "../../react/wrapper.mjs";
7
+ import { CHUNK_CSS_PLACEHOLDER, CHUNK_JS_PLACEHOLDER, HTML_PLACEHOLDER, SSR_DATA_PLACEHOLDER } from "../constants.mjs";
8
8
  import { createReplaceHelemt, getHelmetData } from "../helmet.mjs";
9
- import { replaceChunkJsPlaceholder } from "../scriptOrder.mjs";
10
- import { buildHtml } from "../shared.mjs";
9
+ import { buildHtml, createSSRRenderLifecycle, replaceSSRTemplateChunk } from "../shared.mjs";
11
10
  import { SSRErrors, SSRTimings } from "../tracer.mjs";
12
11
  import { getSSRConfigByEntry, safeReplace } from "../utils.mjs";
13
12
  import { LoadableCollector } from "./loadable.mjs";
14
13
  import { SSRDataCollector } from "./ssrData.mjs";
15
- import * as __rspack_external__modern_js_runtime_extensions_ce611631 from "@modern-js/runtime-extensions";
16
14
  const renderString = async (request, serverRoot, options)=>{
17
15
  const { resource, runtimeContext, config, onError, onTiming } = options;
18
16
  const tracer = {
@@ -20,7 +18,7 @@ const renderString = async (request, serverRoot, options)=>{
20
18
  onTiming
21
19
  };
22
20
  const routerContext = runtimeContext.routerContext;
23
- const { htmlTemplate, entryName, loadableStats, routeManifest, moduleFederationCssAssets } = resource;
21
+ const { htmlTemplate, entryName, loadableStats, routeManifest } = resource;
24
22
  const ssrConfig = getSSRConfigByEntry(entryName, config.ssr, config.ssrByEntries);
25
23
  const chunkSet = {
26
24
  renderLevel: RenderLevel.CLIENT_RENDER,
@@ -28,83 +26,121 @@ const renderString = async (request, serverRoot, options)=>{
28
26
  jsChunk: '',
29
27
  cssChunk: ''
30
28
  };
31
- const collectors = [
32
- new LoadableCollector({
33
- stats: loadableStats,
34
- nonce: config.nonce,
35
- routeManifest,
36
- runtimeContext,
37
- template: htmlTemplate,
38
- entryName,
39
- moduleFederationCssAssets,
40
- chunkSet,
41
- config
42
- }),
43
- new SSRDataCollector({
44
- runtimeContext,
45
- request,
46
- ssrConfig,
47
- ssrContext: runtimeContext.ssrContext,
48
- chunkSet,
49
- routerContext,
50
- nonce: config.nonce,
51
- useJsonScript: config.useJsonScript
52
- })
53
- ];
29
+ const collectors = [];
30
+ const lifecycle = createSSRRenderLifecycle(collectors);
31
+ const loadableCollector = new LoadableCollector({
32
+ stats: loadableStats,
33
+ nonce: config.nonce,
34
+ routeManifest,
35
+ template: htmlTemplate,
36
+ entryName,
37
+ chunkSet,
38
+ config,
39
+ lifecycle
40
+ });
41
+ collectors.push(loadableCollector, new SSRDataCollector({
42
+ runtimeContext,
43
+ request,
44
+ ssrConfig,
45
+ ssrContext: runtimeContext.ssrContext,
46
+ chunkSet,
47
+ routerContext,
48
+ nonce: config.nonce,
49
+ useJsonScript: config.useJsonScript,
50
+ lifecycle
51
+ }));
54
52
  const internalRuntimeContext = getGlobalInternalRuntimeContext();
55
53
  const hooks = internalRuntimeContext.hooks;
56
54
  const extraCollectors = hooks.extendStringSSRCollectors.call({
57
- chunkSet
55
+ chunkSet,
56
+ render: {
57
+ runtimeContext,
58
+ request,
59
+ resource,
60
+ config,
61
+ platform: 'node',
62
+ mode: 'string',
63
+ isRsc: true === getGlobalEnableRsc()
64
+ }
58
65
  });
59
66
  for (const c of extraCollectors)if (c) collectors.unshift(c);
60
- const rootElement = wrapRuntimeContextProvider(serverRoot, Object.assign(runtimeContext, {
67
+ let rootElement = wrapRuntimeContextProvider(serverRoot, Object.assign(runtimeContext, {
61
68
  ssr: true
62
69
  }));
63
- const html = await generateHtml(rootElement, htmlTemplate, chunkSet, collectors, runtimeContext.ssrContext?.htmlModifiers || [], runtimeContext, entryName, tracer);
70
+ if (true === getGlobalEnableRsc() && false === runtimeContext.isBrowser) rootElement = wrapRuntimeComponentResolver(rootElement, hooks);
71
+ const html = await generateHtml(rootElement, htmlTemplate, chunkSet, collectors, runtimeContext.ssrContext?.htmlModifiers || [], tracer, request.signal, lifecycle, loadableCollector.stylesheetInfo);
64
72
  return html;
65
73
  };
66
- async function generateHtml(App, htmlTemplate, chunkSet, collectors, htmlModifiers, runtimeContext, entryName, { onError, onTiming }) {
74
+ async function generateHtml(App, htmlTemplate, chunkSet, collectors, htmlModifiers, { onError, onTiming }, signal, lifecycle, stylesheetInfo) {
67
75
  let html = '';
68
76
  let helmetData;
69
- const finalApp = collectors.reduce((pre, creator)=>creator.collect?.(pre) || pre, App);
70
- __rspack_external__modern_js_runtime_extensions_ce611631.beginHeadRender(runtimeContext);
71
77
  try {
72
- const end = time();
73
- html = server.renderToString(finalApp, {
74
- identifierPrefix: SSR_HYDRATION_ID_PREFIX
78
+ signal.throwIfAborted();
79
+ try {
80
+ const finalApp = collectors.reduce((pre, creator)=>creator.collect?.(pre) || pre, App);
81
+ lifecycle.beforeReact();
82
+ const end = time();
83
+ html = server.renderToString(finalApp, {
84
+ identifierPrefix: SSR_HYDRATION_ID_PREFIX
85
+ });
86
+ html = lifecycle.completedBody(html, 'complete');
87
+ chunkSet.renderLevel = RenderLevel.SERVER_RENDER;
88
+ helmetData = getHelmetData(collectors);
89
+ const cost = end();
90
+ onTiming(SSRTimings.RENDER_HTML, cost);
91
+ } catch (error) {
92
+ lifecycle.finish({
93
+ status: 'fallback',
94
+ error
95
+ });
96
+ html = '';
97
+ chunkSet.renderLevel = RenderLevel.CLIENT_RENDER;
98
+ onError(error, SSRErrors.RENDER_HTML);
99
+ }
100
+ await Promise.all(collectors.map((component)=>component.effect()));
101
+ signal.throwIfAborted();
102
+ const { ssrScripts, cssChunk, jsChunk } = chunkSet;
103
+ const finalHtml = await buildHtml(htmlTemplate, [
104
+ createReplaceHtml(html),
105
+ (template)=>replaceSSRTemplateChunk({
106
+ name: "scripts",
107
+ template,
108
+ placeholder: CHUNK_JS_PLACEHOLDER,
109
+ content: jsChunk
110
+ }, lifecycle),
111
+ (template)=>replaceSSRTemplateChunk({
112
+ name: 'styles',
113
+ template,
114
+ placeholder: CHUNK_CSS_PLACEHOLDER,
115
+ content: cssChunk,
116
+ ...stylesheetInfo
117
+ }, lifecycle),
118
+ (template)=>replaceSSRTemplateChunk({
119
+ name: 'data',
120
+ template,
121
+ placeholder: SSR_DATA_PLACEHOLDER,
122
+ content: ssrScripts
123
+ }, lifecycle),
124
+ createReplaceHelemt(helmetData),
125
+ ...htmlModifiers
126
+ ]);
127
+ signal.throwIfAborted();
128
+ lifecycle.finish({
129
+ status: 'complete'
130
+ });
131
+ return finalHtml;
132
+ } catch (error) {
133
+ lifecycle.finish(signal.aborted ? {
134
+ status: 'cancelled',
135
+ reason: signal.reason
136
+ } : {
137
+ status: 'error',
138
+ error
75
139
  });
76
- html = __rspack_external__modern_js_runtime_extensions_ce611631.completeHeadRender(runtimeContext, html);
77
- chunkSet.renderLevel = RenderLevel.SERVER_RENDER;
78
- helmetData = getHelmetData(runtimeContext);
79
- const cost = end();
80
- onTiming(SSRTimings.RENDER_HTML, cost);
81
- } catch (e) {
82
- __rspack_external__modern_js_runtime_extensions_ce611631.abortHeadRender(runtimeContext);
83
- chunkSet.renderLevel = RenderLevel.CLIENT_RENDER;
84
- onError(e, SSRErrors.RENDER_HTML);
140
+ throw error;
85
141
  }
86
- await Promise.all(collectors.map((component)=>component.effect()));
87
- const { ssrScripts, cssChunk, jsChunk } = chunkSet;
88
- const finalHtml = await buildHtml(htmlTemplate, [
89
- createReplaceHtml(html),
90
- createReplaceChunkJs(jsChunk, entryName),
91
- createReplaceChunkCss(cssChunk),
92
- createReplaceSSRDataScript(ssrScripts, entryName),
93
- createReplaceHelemt(helmetData),
94
- ...htmlModifiers
95
- ]);
96
- return finalHtml;
97
142
  }
98
143
  function createReplaceHtml(html) {
99
144
  return (template)=>safeReplace(template, HTML_PLACEHOLDER, html);
100
145
  }
101
- function createReplaceSSRDataScript(data, entryName) {
102
- return (template)=>replaceChunkJsPlaceholder(template, data, entryName, SSR_DATA_PLACEHOLDER);
103
- }
104
- function createReplaceChunkJs(js, entryName) {
105
- return (template)=>replaceChunkJsPlaceholder(template, js, entryName);
106
- }
107
- function createReplaceChunkCss(css) {
108
- return (template)=>safeReplace(template, CHUNK_CSS_PLACEHOLDER, css);
109
- }
110
146
  export { renderString };
@@ -1,13 +1,11 @@
1
1
  import { ChunkExtractor } from "@loadable/server";
2
- import { createFederatedCssLinks } from "../federatedCss.mjs";
3
- import { getMatchedRouteChunks, orderHydrationScriptChunks } from "../scriptOrder.mjs";
4
2
  import { attributesToString, checkIsNode, hasStylesheetLink } from "../utils.mjs";
5
3
  const extname = (uri)=>{
6
4
  if ('string' != typeof uri || !uri.includes('.')) return '';
7
5
  return `.${uri?.split('.').pop()}` || '';
8
6
  };
9
7
  const generateChunks = (chunks, ext)=>chunks.filter((chunk)=>Boolean(chunk.url)).filter((chunk)=>extname(chunk.url).slice(1) === ext);
10
- const routeAssetToChunk = (asset)=>({
8
+ const assetToChunk = (asset)=>({
11
9
  chunk: asset,
12
10
  filename: asset.replace(/^\//, ''),
13
11
  linkType: 'preload',
@@ -53,16 +51,32 @@ class LoadableCollector {
53
51
  ]));
54
52
  } catch (e) {}
55
53
  const collectedChunks = extractor ? extractor.getChunkAssets(extractor.chunks) : [];
56
- const matchedRouteChunks = getMatchedRouteChunks(options.runtimeContext, options.routeManifest, routeAssetToChunk);
57
- const orderedScriptChunks = orderHydrationScriptChunks({
58
- asyncEntryChunks: asyncChunks,
59
- collectedChunks,
60
- matchedRouteChunks,
61
- entryName
62
- });
63
- const chunks = [].concat(asyncChunks).concat(collectedChunks).concat(matchedRouteChunks);
64
- const scriptChunks = generateChunks(orderedScriptChunks, 'js');
65
- const styleChunks = generateChunks(chunks, 'css');
54
+ const groups = [
55
+ {
56
+ name: 'async-entry',
57
+ assets: asyncChunks
58
+ },
59
+ {
60
+ name: 'loadable',
61
+ assets: collectedChunks
62
+ }
63
+ ];
64
+ const nativeChunks = [
65
+ ...asyncChunks,
66
+ ...collectedChunks
67
+ ];
68
+ const prepare = (kind)=>options.lifecycle?.transformAssets(groups, {
69
+ kind,
70
+ source: 'loadable',
71
+ template: options.template,
72
+ createAsset: assetToChunk
73
+ }) ?? nativeChunks;
74
+ const scriptChunks = generateChunks([
75
+ ...prepare("script")
76
+ ], 'js');
77
+ const styleChunks = generateChunks([
78
+ ...prepare('style')
79
+ ], 'css');
66
80
  if (extractor) {
67
81
  this.emitLoadableScripts(extractor);
68
82
  await this.emitScriptAssets(scriptChunks);
@@ -101,7 +115,7 @@ class LoadableCollector {
101
115
  chunkSet.jsChunk += scripts.filter((script)=>Boolean(script)).join('');
102
116
  }
103
117
  async emitStyleAssets(chunks) {
104
- const { template, chunkSet, config, moduleFederationCssAssets } = this.options;
118
+ const { template, chunkSet, config } = this.options;
105
119
  const { inlineStyles } = config;
106
120
  const atrributes = attributesToString(this.generateAttributes());
107
121
  const emittedAssetUrls = new Set();
@@ -116,11 +130,8 @@ class LoadableCollector {
116
130
  return link;
117
131
  }));
118
132
  chunkSet.cssChunk += css.filter((css)=>Boolean(css)).join('');
119
- chunkSet.cssChunk += createFederatedCssLinks(moduleFederationCssAssets, {
120
- template,
121
- attributes: this.generateAttributes(),
122
- existingAssets: emittedChunks.map((chunk)=>chunk.url)
123
- });
133
+ this.stylesheetInfo.emittedAssets = emittedChunks.map((chunk)=>chunk.url);
134
+ this.stylesheetInfo.attributes = this.generateAttributes();
124
135
  }
125
136
  generateAttributes(extraAtr = {}) {
126
137
  const { config } = this.options;
@@ -133,6 +144,10 @@ class LoadableCollector {
133
144
  };
134
145
  }
135
146
  constructor(options){
147
+ this.stylesheetInfo = {
148
+ emittedAssets: [],
149
+ attributes: {}
150
+ };
136
151
  this.options = options;
137
152
  }
138
153
  }
@@ -1,5 +1,4 @@
1
1
  import { serializeJson } from "@modern-js/runtime-utils/node";
2
- import { getRouterHydrationScripts, getRouterServerSnapshot } from "../../../router/runtime/lifecycle.mjs";
3
2
  import { ROUTER_DATA_JSON_ID, SSR_DATA_JSON_ID } from "../../constants.mjs";
4
3
  import { attributesToString, serializeErrors } from "../utils.mjs";
5
4
  function _check_private_redeclaration(obj, privateCollection) {
@@ -88,20 +87,15 @@ function getSSRData() {
88
87
  };
89
88
  }
90
89
  function getRouterData() {
91
- const { routerContext, runtimeContext } = _class_private_field_get(this, _options);
92
- const snapshotRouterData = getRouterServerSnapshot(runtimeContext)?.routerData;
93
- if (snapshotRouterData) return {
94
- loaderData: snapshotRouterData.loaderData,
95
- errors: serializeErrors(snapshotRouterData.errors || null)
96
- };
97
- return routerContext ? {
98
- loaderData: routerContext.loaderData,
99
- errors: serializeErrors(routerContext.errors)
90
+ const { routerContext, lifecycle } = _class_private_field_get(this, _options);
91
+ const data = lifecycle?.getRouterData() ?? routerContext;
92
+ return data ? {
93
+ loaderData: data.loaderData,
94
+ errors: serializeErrors(data.errors || null)
100
95
  } : void 0;
101
96
  }
102
97
  function getSSRDataScripts(ssrData, routerData) {
103
98
  const { nonce, useJsonScript = false } = _class_private_field_get(this, _options);
104
- const hydrationScripts = getRouterHydrationScripts(_class_private_field_get(this, _options).runtimeContext);
105
99
  const serializeSSRData = serializeJson(ssrData);
106
100
  const attrsStr = attributesToString({
107
101
  nonce
@@ -111,7 +105,6 @@ function getSSRDataScripts(ssrData, routerData) {
111
105
  const serializedRouterData = serializeJson(routerData);
112
106
  ssrDataScripts += useJsonScript ? `\n<script type="application/json" id="${ROUTER_DATA_JSON_ID}">${serializedRouterData}</script>` : `\n<script${attrsStr}>window._ROUTER_DATA = ${serializedRouterData}</script>`;
113
107
  }
114
- if (hydrationScripts.length) ssrDataScripts += `\n${hydrationScripts.join('\n')}`;
115
108
  return ssrDataScripts;
116
109
  }
117
110
  export { SSRDataCollector };
@@ -1,7 +1,6 @@
1
- import { escapeHtmlAttribute, isSafeHtmlAttributeName } from "@modern-js/runtime-extensions";
2
1
  import { isRouteErrorResponse } from "../../router/runtime/routerHelper.mjs";
3
2
  function attributesToString(attributes) {
4
- return Object.entries(attributes).reduce((str, [key, value])=>void 0 !== value && isSafeHtmlAttributeName(key) ? `${str} ${key}="${escapeHtmlAttribute(value)}"` : str, '');
3
+ return Object.entries(attributes).reduce((str, [key, value])=>void 0 !== value && /^[^\u0000-\u0020"'<>/=]+$/u.test(key) ? `${str} ${key}="${String(value).replaceAll('&', '&amp;').replaceAll('"', '&quot;').replaceAll('<', '&lt;').replaceAll('>', '&gt;')}"` : str, '');
5
4
  }
6
5
  function safeReplace(source, searchValue, replaceValue) {
7
6
  return source.replace(searchValue, ()=>replaceValue);
@@ -1,21 +1,14 @@
1
1
  "use client";
2
2
  import react from "react";
3
3
  import { Helmet, HelmetData, HelmetProvider } from "react-helmet-async";
4
- import { InternalRuntimeContext } from "../core/context/index.mjs";
5
- import { ensureHelmetContext } from "../core/context/helmetContext.mjs";
6
- import * as __rspack_external__modern_js_runtime_extensions_ce611631 from "@modern-js/runtime-extensions";
7
- const collectServerHelmet = (runtimeContext, props)=>{
8
- const helmetContext = ensureHelmetContext(runtimeContext);
9
- const createRecord = ()=>__rspack_external__modern_js_runtime_extensions_ce611631.createHelmetRecord(react, props);
10
- const deriveState = (records)=>__rspack_external__modern_js_runtime_extensions_ce611631.deriveHelmetServerState(react, records);
11
- const marker = __rspack_external__modern_js_runtime_extensions_ce611631.collectHeadState(runtimeContext, createRecord, deriveState, helmetContext);
12
- if (void 0 !== marker) return marker;
13
- helmetContext.helmet = __rspack_external__modern_js_runtime_extensions_ce611631.collectImmediateHelmetState(react, helmetContext, createRecord());
14
- };
4
+ import { RuntimeComponentResolverContext } from "../core/context/runtime.mjs";
15
5
  const head_Helmet = (props)=>{
16
- const runtimeContext = react.useContext(InternalRuntimeContext);
17
- if (null !== runtimeContext && false === runtimeContext.isBrowser) return __rspack_external__modern_js_runtime_extensions_ce611631.renderHeadMarker(react, collectServerHelmet(runtimeContext, props));
18
- return react.createElement(Helmet, props);
6
+ const resolveComponent = react.useContext(RuntimeComponentResolverContext);
7
+ const Component = resolveComponent?.(Helmet, {
8
+ name: 'head.Helmet'
9
+ }) ?? Helmet;
10
+ if (Component === head_Helmet) throw new Error('A component resolver cannot resolve head.Helmet to itself.');
11
+ return react.createElement(Component, props);
19
12
  };
20
13
  const head = {
21
14
  Helmet: head_Helmet,
@@ -1,6 +1,5 @@
1
1
  "use client";
2
2
  import { Fragment, jsx, jsxs } from "react/jsx-runtime";
3
- import { getNavigationWarmupCacheKey } from "@modern-js/runtime-extensions";
4
3
  import { Link as router_Link, NavLink, matchRoutes, useHref, useMatches, useResolvedPath } from "@modern-js/runtime-utils/router";
5
4
  import react, { useContext, useMemo } from "react";
6
5
  import { InternalRuntimeContext } from "../../core/context/index.mjs";
@@ -20,62 +19,6 @@ function composeEventHandlers(theirHandler, ourHandler) {
20
19
  };
21
20
  }
22
21
  const ABSOLUTE_URL_REGEX = /^(?:[a-z][a-z0-9+.-]*:|\/\/)/i;
23
- const DEFAULT_PREFETCH_BEHAVIOR = 'render';
24
- const INTENT_DELAY = 100;
25
- const VIEWPORT_ROOT_MARGIN = '200px';
26
- const MAX_CONCURRENT_WARMUPS = 4;
27
- const WARMUP_TTL = 30000;
28
- const SLOW_EFFECTIVE_TYPES = new Set([
29
- 'slow-2g',
30
- '2g'
31
- ]);
32
- const warmupCache = new Map();
33
- const warmupQueue = [];
34
- let activeWarmups = 0;
35
- const getWarmupTimestamp = ()=>performance.now();
36
- const getConnection = ()=>{
37
- const nav = globalThis.navigator;
38
- return nav?.connection || nav?.mozConnection || nav?.webkitConnection;
39
- };
40
- const shouldWarmupOnCurrentNetwork = ()=>{
41
- const connection = getConnection();
42
- if (connection?.saveData) return false;
43
- if ('string' == typeof connection?.effectiveType && SLOW_EFFECTIVE_TYPES.has(connection.effectiveType)) return false;
44
- return true;
45
- };
46
- const pruneWarmupCache = (now = getWarmupTimestamp())=>{
47
- for (const [key, timestamp] of warmupCache)if (now - timestamp > WARMUP_TTL) warmupCache.delete(key);
48
- };
49
- const runNextWarmup = ()=>{
50
- while(activeWarmups < MAX_CONCURRENT_WARMUPS && warmupQueue.length > 0){
51
- const task = warmupQueue.shift();
52
- if (task.cancelled) continue;
53
- activeWarmups += 1;
54
- task.run().catch(()=>{
55
- warmupCache.delete(task.key);
56
- }).finally(()=>{
57
- activeWarmups -= 1;
58
- runNextWarmup();
59
- });
60
- }
61
- };
62
- const scheduleWarmup = (key, run)=>{
63
- if (!shouldWarmupOnCurrentNetwork()) return ()=>{};
64
- pruneWarmupCache();
65
- if (warmupCache.has(key)) return ()=>{};
66
- warmupCache.set(key, getWarmupTimestamp());
67
- const task = {
68
- key,
69
- run,
70
- cancelled: false
71
- };
72
- warmupQueue.push(task);
73
- runNextWarmup();
74
- return ()=>{
75
- task.cancelled = true;
76
- if (warmupQueue.includes(task)) warmupCache.delete(task.key);
77
- };
78
- };
79
22
  const setRef = (ref, value)=>{
80
23
  if (!ref) return;
81
24
  if ('function' == typeof ref) return void ref(value);
@@ -83,70 +26,65 @@ const setRef = (ref, value)=>{
83
26
  ref.current = value;
84
27
  } catch {}
85
28
  };
86
- const isDataWarmupEnabled = (route)=>{
87
- const handle = route.handle;
88
- return handle?.navigationWarmup?.data !== false;
89
- };
90
- function usePrefetchBehavior(prefetch, preload, theirElementProps) {
91
- const [maybeWarmup, setMaybeWarmup] = react.useState(false);
92
- const [shouldPrefetch, setShouldPrefetch] = react.useState(false);
93
- const [shouldPreload, setShouldPreload] = react.useState(false);
94
- const [viewportElement, setViewportElement] = react.useState(null);
29
+ function usePrefetchBehavior(prefetch, preload, theirElementProps, policy) {
30
+ const [maybePrefetch, setMaybePrefetch] = react.useState(false);
31
+ const [state, setState] = react.useState({
32
+ code: false,
33
+ data: false
34
+ });
35
+ const [element, setElement] = react.useState(null);
36
+ const observerRef = react.useRef(void 0);
95
37
  const { onFocus, onBlur, onMouseEnter, onMouseLeave, onTouchStart } = theirElementProps;
96
38
  react.useEffect(()=>{
97
- if ('render' === prefetch) setShouldPrefetch(true);
98
- if ('render' === preload) setShouldPreload(true);
39
+ if (!policy) return void setState({
40
+ code: 'render' === prefetch,
41
+ data: 'render' === prefetch
42
+ });
43
+ const observer = policy.observe({
44
+ element,
45
+ prefetch,
46
+ preload,
47
+ notify: (next)=>setState((previous)=>previous.code === next.code && previous.data === next.data ? previous : next)
48
+ });
49
+ observerRef.current = observer;
50
+ return ()=>{
51
+ observerRef.current = void 0;
52
+ observer.dispose();
53
+ };
99
54
  }, [
55
+ policy,
100
56
  prefetch,
101
- preload
57
+ preload,
58
+ element
59
+ ]);
60
+ react.useEffect(()=>{
61
+ if (policy || !maybePrefetch) return;
62
+ const timer = setTimeout(()=>setState({
63
+ code: true,
64
+ data: true
65
+ }), 100);
66
+ return ()=>clearTimeout(timer);
67
+ }, [
68
+ policy,
69
+ maybePrefetch
102
70
  ]);
103
71
  const setIntent = ()=>{
104
- if ('intent' === prefetch || 'intent' === preload) setMaybeWarmup(true);
72
+ if (policy) observerRef.current?.onIntent();
73
+ else if ('intent' === prefetch) setMaybePrefetch(true);
105
74
  };
106
75
  const cancelIntent = ()=>{
107
- if ('intent' === prefetch || 'intent' === preload) {
108
- setMaybeWarmup(false);
109
- setShouldPrefetch(false);
110
- setShouldPreload(false);
76
+ if (policy) observerRef.current?.onCancel();
77
+ else if ('intent' === prefetch) {
78
+ setMaybePrefetch(false);
79
+ setState({
80
+ code: false,
81
+ data: false
82
+ });
111
83
  }
112
84
  };
113
- react.useEffect(()=>{
114
- if (maybeWarmup) {
115
- const id = setTimeout(()=>{
116
- if ('intent' === prefetch) setShouldPrefetch(true);
117
- if ('intent' === preload) setShouldPreload(true);
118
- }, INTENT_DELAY);
119
- return ()=>{
120
- clearTimeout(id);
121
- };
122
- }
123
- }, [
124
- maybeWarmup,
125
- prefetch,
126
- preload
127
- ]);
128
- react.useEffect(()=>{
129
- if (!viewportElement || 'viewport' !== prefetch && 'viewport' !== preload || "u" < typeof IntersectionObserver) return;
130
- const observer = new IntersectionObserver((entries)=>{
131
- if (!entries.some((entry)=>entry.isIntersecting)) return;
132
- if ('viewport' === prefetch) setShouldPrefetch(true);
133
- if ('viewport' === preload) setShouldPreload(true);
134
- observer.disconnect();
135
- }, {
136
- rootMargin: VIEWPORT_ROOT_MARGIN
137
- });
138
- observer.observe(viewportElement);
139
- return ()=>{
140
- observer.disconnect();
141
- };
142
- }, [
143
- prefetch,
144
- preload,
145
- viewportElement
146
- ]);
147
85
  return [
148
- shouldPrefetch,
149
- shouldPreload,
86
+ state.data,
87
+ state.code,
150
88
  {
151
89
  onFocus: composeEventHandlers(onFocus, setIntent),
152
90
  onBlur: composeEventHandlers(onBlur, cancelIntent),
@@ -154,7 +92,7 @@ function usePrefetchBehavior(prefetch, preload, theirElementProps) {
154
92
  onMouseLeave: composeEventHandlers(onMouseLeave, cancelIntent),
155
93
  onTouchStart: composeEventHandlers(onTouchStart, setIntent)
156
94
  },
157
- setViewportElement
95
+ setElement
158
96
  ];
159
97
  }
160
98
  async function loadRouteModule(route, routeAssets, chunkLoader) {
@@ -195,7 +133,8 @@ const PrefetchPageLinks = ({ path, includeData })=>{
195
133
  const context = useContext(InternalRuntimeContext);
196
134
  const { routeManifest, routes } = context;
197
135
  const { routeAssets } = routeManifest || {};
198
- const allowNetworkWarmup = shouldWarmupOnCurrentNetwork();
136
+ const policy = context.linkPrefetchPolicy;
137
+ const allowNetworkWarmup = policy?.canWarmup() ?? true;
199
138
  const matches = useMemo(()=>Array.isArray(routes) ? matchRoutes(routes, pathname) : [], [
200
139
  pathname,
201
140
  routes
@@ -215,7 +154,16 @@ const PrefetchPageLinks = ({ path, includeData })=>{
215
154
  const routeAsset = routeId ? routeAssets[routeId] : void 0;
216
155
  const chunkIds = routeAsset?.chunkIds;
217
156
  if (!routeId || !Array.isArray(chunkIds) || 0 === chunkIds.length) return ()=>{};
218
- return scheduleWarmup(getNavigationWarmupCacheKey(context, chunkLoader, getWebpackPublicPath(), `route-module:${routeId}:${chunkIds.join(',')}`), ()=>loadRouteModule(match.route, routeAssets, chunkLoader));
157
+ const run = ()=>loadRouteModule(match.route, routeAssets, chunkLoader);
158
+ if (policy) return policy.schedule({
159
+ runtimeContext: context,
160
+ chunkLoader,
161
+ publicPath: getWebpackPublicPath(),
162
+ key: `route-module:${routeId}:${chunkIds.join(',')}`,
163
+ run
164
+ });
165
+ run().catch(()=>{});
166
+ return ()=>{};
219
167
  });
220
168
  return ()=>{
221
169
  cancellations.forEach((cancel)=>cancel());
@@ -224,6 +172,7 @@ const PrefetchPageLinks = ({ path, includeData })=>{
224
172
  allowNetworkWarmup,
225
173
  chunkLoader,
226
174
  context,
175
+ policy,
227
176
  routeAssetGeneration
228
177
  ]);
229
178
  if (!allowNetworkWarmup || !includeData || !window._SSR_DATA) return null;
@@ -235,10 +184,11 @@ const PrefetchPageLinks = ({ path, includeData })=>{
235
184
  };
236
185
  const PrefetchDataLinks = ({ matches, path, routeManifest })=>{
237
186
  const { pathname, search, hash } = path;
187
+ const policy = useContext(InternalRuntimeContext).linkPrefetchPolicy;
238
188
  const currentMatches = useMatches();
239
189
  const basename = useHref('/');
240
190
  const dataHrefs = useMemo(()=>matches?.filter((match, index)=>{
241
- if (!isDataWarmupEnabled(match.route) || !match.route.loader || 'function' != typeof match.route.loader || 0 === match.route.loader.length) return false;
191
+ if (policy?.allowData(match.route) === false || !match.route.loader || 'function' != typeof match.route.loader || 0 === match.route.loader.length) return false;
242
192
  if (match.route.shouldRevalidate) {
243
193
  const currentUrl = new URL(location.pathname + location.search + location.hash, window.origin);
244
194
  const nextUrl = new URL(pathname + search + hash, window.origin);
@@ -265,16 +215,10 @@ const PrefetchDataLinks = ({ matches, path, routeManifest })=>{
265
215
  children: dataHrefs
266
216
  });
267
217
  };
268
- const normalizePreloadBehavior = (preload, prefetch)=>{
269
- if (false === preload || 'none' === preload) return 'none';
270
- if (void 0 !== preload) return preload;
271
- if ('none' === prefetch) return 'none';
272
- return prefetch;
273
- };
274
- const createPrefetchLink = (Link)=>/*#__PURE__*/ react.forwardRef(({ to, prefetch = DEFAULT_PREFETCH_BEHAVIOR, preload, ...props }, forwardedRef)=>{
218
+ const createPrefetchLink = (Link)=>/*#__PURE__*/ react.forwardRef(({ to, prefetch, preload, ...props }, forwardedRef)=>{
275
219
  const isAbsolute = 'string' == typeof to && ABSOLUTE_URL_REGEX.test(to);
276
- const resolvedPreload = normalizePreloadBehavior(preload, prefetch);
277
- const [shouldPrefetch, shouldPreload, prefetchHandlers, setViewportElement] = usePrefetchBehavior(prefetch, resolvedPreload, props);
220
+ const policy = useContext(InternalRuntimeContext).linkPrefetchPolicy;
221
+ const [shouldPrefetch, shouldPreload, prefetchHandlers, setViewportElement] = usePrefetchBehavior(prefetch, preload, props, policy);
278
222
  const setAnchorRef = react.useCallback((element)=>{
279
223
  setViewportElement(element);
280
224
  setRef(forwardedRef, element);