@bleedingdev/modern-js-runtime 3.5.0-ultramodern.98 → 3.8.1-ultramodern.1

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 (86) hide show
  1. package/dist/cjs/cli/index.js +1 -11
  2. package/dist/cjs/cli/ssr/index.js +1 -0
  3. package/dist/cjs/core/browser/hydrate.js +31 -27
  4. package/dist/cjs/core/browser/index.js +4 -15
  5. package/dist/cjs/core/react/wrapper.js +23 -28
  6. package/dist/cjs/core/server/requestResponse.js +5 -5
  7. package/dist/cjs/core/server/scriptOrder.js +1 -1
  8. package/dist/cjs/core/server/stream/beforeTemplate.worker.js +1 -10
  9. package/dist/cjs/core/server/string/index.js +3 -3
  10. package/dist/cjs/core/server/utils.js +3 -3
  11. package/dist/cjs/document/cli/index.js +5 -2
  12. package/dist/cjs/module-federation/distributed-ssr.js +13 -12
  13. package/dist/cjs/module-federation/last-known-good.js +1 -1
  14. package/dist/cjs/module-federation/manifest-recovery-runtime-plugin.js +27 -38
  15. package/dist/cjs/router/cli/code/index.js +16 -9
  16. package/dist/cjs/router/cli/code/templates.js +36 -27
  17. package/dist/cjs/router/cli/handler.js +7 -1
  18. package/dist/cjs/router/runtime/plugin.js +22 -17
  19. package/dist/cjs/router/runtime/plugin.node.js +11 -3
  20. package/dist/cjs/router/runtime/provider.js +2 -2
  21. package/dist/cjs/router/runtime/redirect.js +51 -0
  22. package/dist/cjs/router/runtime/routerHelper.js +4 -0
  23. package/dist/cjs/router/runtime/rsc-router.js +2 -13
  24. package/dist/cjs/router/runtime/utils.js +3 -2
  25. package/dist/esm/cli/index.mjs +2 -12
  26. package/dist/esm/cli/ssr/index.mjs +1 -0
  27. package/dist/esm/core/browser/hydrate.mjs +30 -22
  28. package/dist/esm/core/browser/index.mjs +5 -13
  29. package/dist/esm/core/react/wrapper.mjs +23 -28
  30. package/dist/esm/core/server/requestResponse.mjs +4 -4
  31. package/dist/esm/core/server/scriptOrder.mjs +1 -1
  32. package/dist/esm/core/server/stream/beforeTemplate.worker.mjs +1 -10
  33. package/dist/esm/core/server/string/index.mjs +3 -3
  34. package/dist/esm/core/server/utils.mjs +1 -1
  35. package/dist/esm/document/cli/index.mjs +1 -1
  36. package/dist/esm/module-federation/distributed-ssr.mjs +13 -12
  37. package/dist/esm/module-federation/last-known-good.mjs +1 -1
  38. package/dist/esm/module-federation/manifest-recovery-runtime-plugin.mjs +22 -33
  39. package/dist/esm/router/cli/code/index.mjs +16 -9
  40. package/dist/esm/router/cli/code/templates.mjs +36 -27
  41. package/dist/esm/router/cli/handler.mjs +7 -1
  42. package/dist/esm/router/runtime/plugin.mjs +24 -19
  43. package/dist/esm/router/runtime/plugin.node.mjs +12 -4
  44. package/dist/esm/router/runtime/provider.mjs +2 -2
  45. package/dist/esm/router/runtime/redirect.mjs +13 -0
  46. package/dist/esm/router/runtime/routerHelper.mjs +2 -1
  47. package/dist/esm/router/runtime/rsc-router.mjs +2 -13
  48. package/dist/esm/router/runtime/utils.mjs +2 -1
  49. package/dist/esm-node/cli/index.mjs +2 -12
  50. package/dist/esm-node/cli/ssr/index.mjs +1 -0
  51. package/dist/esm-node/core/browser/hydrate.mjs +30 -22
  52. package/dist/esm-node/core/browser/index.mjs +5 -13
  53. package/dist/esm-node/core/react/wrapper.mjs +23 -28
  54. package/dist/esm-node/core/server/requestResponse.mjs +4 -4
  55. package/dist/esm-node/core/server/scriptOrder.mjs +1 -1
  56. package/dist/esm-node/core/server/stream/beforeTemplate.worker.mjs +1 -10
  57. package/dist/esm-node/core/server/string/index.mjs +3 -3
  58. package/dist/esm-node/core/server/utils.mjs +1 -1
  59. package/dist/esm-node/document/cli/index.mjs +1 -1
  60. package/dist/esm-node/module-federation/distributed-ssr.mjs +13 -12
  61. package/dist/esm-node/module-federation/last-known-good.mjs +1 -1
  62. package/dist/esm-node/module-federation/manifest-recovery-runtime-plugin.mjs +22 -33
  63. package/dist/esm-node/router/cli/code/index.mjs +16 -9
  64. package/dist/esm-node/router/cli/code/templates.mjs +36 -27
  65. package/dist/esm-node/router/cli/handler.mjs +7 -1
  66. package/dist/esm-node/router/runtime/plugin.mjs +24 -19
  67. package/dist/esm-node/router/runtime/plugin.node.mjs +12 -4
  68. package/dist/esm-node/router/runtime/provider.mjs +2 -2
  69. package/dist/esm-node/router/runtime/redirect.mjs +14 -0
  70. package/dist/esm-node/router/runtime/routerHelper.mjs +2 -1
  71. package/dist/esm-node/router/runtime/rsc-router.mjs +2 -13
  72. package/dist/esm-node/router/runtime/utils.mjs +2 -1
  73. package/dist/types/core/browser/hydrate.d.ts +0 -1
  74. package/dist/types/core/browser/index.d.ts +0 -1
  75. package/dist/types/core/server/utils.d.ts +1 -1
  76. package/dist/types/document/cli/index.d.ts +1 -0
  77. package/dist/types/module-federation/distributed-ssr.d.ts +3 -3
  78. package/dist/types/module-federation/manifest-recovery-runtime-plugin.d.ts +1 -1
  79. package/dist/types/router/cli/code/index.d.ts +6 -1
  80. package/dist/types/router/cli/code/templates.d.ts +8 -3
  81. package/dist/types/router/cli/handler.d.ts +4 -0
  82. package/dist/types/router/runtime/redirect.d.ts +1 -0
  83. package/dist/types/router/runtime/routerHelper.d.ts +7 -0
  84. package/dist/types/router/runtime/rsc-router.d.ts +1 -2
  85. package/package.json +15 -14
  86. package/rstest.config.mts +2 -0
@@ -1,5 +1,5 @@
1
- import { SSR_HYDRATION_ID_PREFIX } from "@modern-js/utils/universal/constants";
2
1
  import { parseCookie } from "cookie";
2
+ import { createRoot } from "react-dom/client";
3
3
  import { getGlobalInternalRuntimeContext } from "../context/index.mjs";
4
4
  import { getInitialContext } from "../context/runtime.mjs";
5
5
  import { wrapRuntimeContextProvider } from "../react/wrapper.mjs";
@@ -69,8 +69,8 @@ async function renderApp(App, id, hydrateFromSsrData, internalRuntimeContext) {
69
69
  return renderFunc(App, rootElement);
70
70
  }
71
71
  async function ModernHydrate(App, callback) {
72
- const hydrateFunc = IS_REACT18 ? hydrateWithReact18 : hydrateWithReact17;
73
- return hydrateFunc(App, rootElement, callback);
72
+ if (IS_REACT18) return hydrateWithReact(App, rootElement);
73
+ return hydrateWithReact17(App, rootElement, callback);
74
74
  }
75
75
  if (hydrateFromSsrData && process.env.MODERN_ENABLE_HYDRATION && window._SSR_DATA) return hydrateRoot(App, context, ModernRender, ModernHydrate);
76
76
  return ModernRender(wrapRuntimeContextProvider(App, context));
@@ -85,8 +85,7 @@ function createNestedAppRenderer() {
85
85
  return (App, id)=>renderApp(App, id, false, internalRuntimeContext);
86
86
  }
87
87
  async function renderWithReact18(App, rootElement) {
88
- const ReactDOM = await import("react-dom/client");
89
- const root = ReactDOM.createRoot(rootElement);
88
+ const root = createRoot(rootElement);
90
89
  root.render(App);
91
90
  return root;
92
91
  }
@@ -95,16 +94,9 @@ async function renderWithReact17(App, rootElement) {
95
94
  ReactDOM.render(App, rootElement);
96
95
  return rootElement;
97
96
  }
98
- async function hydrateWithReact18(App, rootElement) {
99
- const ReactDOM = await import("react-dom/client");
100
- const root = ReactDOM.hydrateRoot(rootElement, App, {
101
- identifierPrefix: SSR_HYDRATION_ID_PREFIX
102
- });
103
- return root;
104
- }
105
97
  async function hydrateWithReact17(App, rootElement, callback) {
106
98
  const ReactDOM = await import("react-dom");
107
99
  const root = ReactDOM.hydrate(App, rootElement, callback);
108
100
  return root;
109
101
  }
110
- export { createNestedAppRenderer, hydrateWithReact, hydrateWithReact17, hydrateWithReact18, render, renderWithReact17, renderWithReact18 };
102
+ export { createNestedAppRenderer, hydrateWithReact, hydrateWithReact17, render, renderWithReact17, renderWithReact18 };
@@ -3,39 +3,34 @@ import { HelmetProvider } from "react-helmet-async";
3
3
  import { InternalRuntimeContext, RuntimeContext, getGlobalEnableRsc } from "../context/index.mjs";
4
4
  import { stripRuntimeContextExtensions } from "../context/extensions.mjs";
5
5
  import { ensureHelmetContext } from "../context/helmetContext.mjs";
6
- function toRscSafeRecord(value) {
7
- if (!value || 'object' != typeof value) return value;
8
- return Object.fromEntries(Object.entries(value));
9
- }
10
- function createRscSafeSsrContext(ssrContext) {
11
- if (!ssrContext) return ssrContext;
12
- const { request } = ssrContext;
6
+ function createRscSafeRequestContext(ssrContext) {
7
+ if (void 0 === ssrContext) return {
8
+ request: {},
9
+ response: {
10
+ locals: {}
11
+ }
12
+ };
13
+ const { request, response } = ssrContext;
13
14
  return {
14
- nonce: ssrContext.nonce,
15
- useJsonScript: ssrContext.useJsonScript,
16
- htmlModifiers: [],
17
- baseUrl: ssrContext.baseUrl,
18
- request: request ? {
15
+ request: {
19
16
  url: request.url,
20
17
  userAgent: request.userAgent,
21
18
  cookie: request.cookie,
22
19
  pathname: request.pathname,
23
- query: toRscSafeRecord(request.query),
24
- params: toRscSafeRecord(request.params),
25
- headers: toRscSafeRecord(request.headers),
20
+ query: {
21
+ ...request.query
22
+ },
23
+ params: {
24
+ ...request.params
25
+ },
26
+ headers: {
27
+ ...request.headers
28
+ },
26
29
  host: request.host,
27
30
  referer: request.referer
28
- } : request,
29
- mode: ssrContext.mode,
30
- loaderFailureMode: ssrContext.loaderFailureMode
31
- };
32
- }
33
- function createRscSafeRequestContext(ssrContext) {
34
- const safeSsrContext = createRscSafeSsrContext(ssrContext);
35
- return {
36
- request: safeSsrContext?.request || {},
31
+ },
37
32
  response: {
38
- locals: ssrContext?.response?.locals || {}
33
+ locals: response.locals ?? {}
39
34
  }
40
35
  };
41
36
  }
@@ -51,14 +46,14 @@ function wrapRuntimeContextProvider(App, contextValue) {
51
46
  ...rest
52
47
  };
53
48
  stripRuntimeContextExtensions(runtimeContextValue);
54
- if (getGlobalEnableRsc() && !isBrowser) {
49
+ if (true === getGlobalEnableRsc() && false === isBrowser) {
55
50
  const rscSafeRequestContext = createRscSafeRequestContext(ssrContext);
56
51
  const rscInternalContextValue = {
57
52
  ...internalContextValue,
58
53
  context: rscSafeRequestContext,
59
- requestContext: rscSafeRequestContext,
60
- ssrContext: createRscSafeSsrContext(ssrContext)
54
+ requestContext: rscSafeRequestContext
61
55
  };
56
+ delete rscInternalContextValue.ssrContext;
62
57
  const rscRuntimeContextValue = {
63
58
  ...runtimeContextValue,
64
59
  context: rscSafeRequestContext,
@@ -1,5 +1,5 @@
1
1
  import { getRouterServerSnapshot } from "../../router/runtime/lifecycle.mjs";
2
- import { handleRSCRedirect } from "../../router/runtime/rsc-router.mjs";
2
+ import { handleRSCRedirect } from "../../router/runtime/redirect.mjs";
3
3
  import { SSRErrors } from "./tracer.mjs";
4
4
  const isRedirectStatus = (status)=>status >= 300 && status <= 399;
5
5
  const isNullBodyStatus = (status)=>204 === status || 205 === status || 304 === status;
@@ -13,12 +13,12 @@ const processRedirect = (headers, status, ctx)=>{
13
13
  const applyRouterSnapshotResult = (context, onError)=>{
14
14
  const routerServerSnapshot = getRouterServerSnapshot(context);
15
15
  const routerStatusCode = routerServerSnapshot?.statusCode ?? context.routerContext?.statusCode;
16
- if (routerStatusCode && 200 !== routerStatusCode) context.ssrContext?.response.status(routerStatusCode);
16
+ if (void 0 !== routerStatusCode && 0 !== routerStatusCode && !Number.isNaN(routerStatusCode) && 200 !== routerStatusCode) context.ssrContext?.response.status(routerStatusCode);
17
17
  const errors = Object.values(routerServerSnapshot?.errors || context.routerContext?.errors || {});
18
18
  if (errors.length > 0) onError(errors[0], SSRErrors.LOADER_ERROR);
19
19
  };
20
20
  const createLoaderRedirectResponse = (beforeRenderResult, redirectCtx)=>{
21
- if (!beforeRenderResult || !isRedirectStatus(beforeRenderResult.status)) return;
21
+ if (void 0 === beforeRenderResult || !isRedirectStatus(beforeRenderResult.status)) return;
22
22
  if (beforeRenderResult.headers.has('X-Modernjs-Redirect')) return beforeRenderResult;
23
23
  const redirectUrl = beforeRenderResult.headers.get('Location') || '/';
24
24
  return processRedirect(new Headers({
@@ -26,7 +26,7 @@ const createLoaderRedirectResponse = (beforeRenderResult, redirectCtx)=>{
26
26
  }), beforeRenderResult.status, redirectCtx);
27
27
  };
28
28
  const finalizeRenderResponse = (response, responseProxy, redirectCtx, routerCleanup)=>{
29
- if (-1 !== responseProxy.status && isRedirectStatus(responseProxy.status) && responseProxy.headers.Location) return processRedirect(new Headers(responseProxy.headers), responseProxy.status, redirectCtx);
29
+ if (-1 !== responseProxy.status && isRedirectStatus(responseProxy.status) && void 0 !== responseProxy.headers.Location && '' !== responseProxy.headers.Location) return processRedirect(new Headers(responseProxy.headers), responseProxy.status, redirectCtx);
30
30
  Object.entries(responseProxy.headers).forEach(([key, value])=>{
31
31
  response.headers.set(key, value);
32
32
  });
@@ -43,7 +43,7 @@ function getMatchedRouteAssets(runtimeContext, routeManifest) {
43
43
  return matchedRouteIds.flatMap((routeId)=>routeAssets[routeId]?.assets ?? []);
44
44
  }
45
45
  function getMatchedRouteChunks(runtimeContext, routeManifest, routeAssetToChunk) {
46
- if (!routeManifest) return [];
46
+ if (void 0 === routeManifest) return [];
47
47
  return getMatchedRouteAssets(runtimeContext, routeManifest).map(routeAssetToChunk);
48
48
  }
49
49
  const orderHydrationScriptChunks = ({ asyncEntryChunks, collectedChunks, matchedRouteChunks, entryName })=>{
@@ -1,4 +1,3 @@
1
- import { matchRoutes } from "@modern-js/runtime-utils/router";
2
1
  import { getRouterMatchedRouteIds } from "../../../router/runtime/lifecycle.mjs";
3
2
  import { CHUNK_CSS_PLACEHOLDER } from "../constants.mjs";
4
3
  import { createFederatedCssLinks } from "../federatedCss.mjs";
@@ -27,20 +26,12 @@ async function buildShellBeforeTemplate(beforeAppTemplate, options) {
27
26
  });
28
27
  return safeReplace(template, CHUNK_CSS_PLACEHOLDER, css);
29
28
  async function getCssChunks() {
30
- const { routeManifest, routerContext, routes } = runtimeContext;
29
+ const { routeManifest } = runtimeContext;
31
30
  const routeAssets = routeManifest?.routeAssets;
32
31
  if (!routeAssets) return '';
33
32
  let matchedRouteManifests = [];
34
33
  const matchedRouteIds = getRouterMatchedRouteIds(runtimeContext);
35
34
  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
35
  const asyncEntry = routeAssets[`async-${entryName}`];
45
36
  if (asyncEntry) matchedRouteManifests.push(asyncEntry);
46
37
  const cssChunks = matchedRouteManifests.reduce((chunks, routeManifest)=>{
@@ -85,7 +85,7 @@ async function generateHtml(App, htmlTemplate, chunkSet, collectors, htmlModifie
85
85
  createReplaceHtml(html),
86
86
  createReplaceChunkJs(jsChunk, entryName),
87
87
  createReplaceChunkCss(cssChunk),
88
- createReplaceSSRDataScript(ssrScripts),
88
+ createReplaceSSRDataScript(ssrScripts, entryName),
89
89
  createReplaceHelemt(helmetData),
90
90
  ...htmlModifiers
91
91
  ]);
@@ -94,8 +94,8 @@ async function generateHtml(App, htmlTemplate, chunkSet, collectors, htmlModifie
94
94
  function createReplaceHtml(html) {
95
95
  return (template)=>safeReplace(template, HTML_PLACEHOLDER, html);
96
96
  }
97
- function createReplaceSSRDataScript(data) {
98
- return (template)=>safeReplace(template, SSR_DATA_PLACEHOLDER, data);
97
+ function createReplaceSSRDataScript(data, entryName) {
98
+ return (template)=>replaceChunkJsPlaceholder(template, data, entryName, SSR_DATA_PLACEHOLDER);
99
99
  }
100
100
  function createReplaceChunkJs(js, entryName) {
101
101
  return (template)=>replaceChunkJsPlaceholder(template, js, entryName);
@@ -1,4 +1,4 @@
1
- import { isRouteErrorResponse } from "@modern-js/runtime-utils/router";
1
+ import { isRouteErrorResponse } from "../../router/runtime/routerHelper.mjs";
2
2
  function attributesToString(attributes) {
3
3
  return Object.entries(attributes).reduce((str, [key, value])=>void 0 === value ? str : `${str} ${key}="${value}"`, '');
4
4
  }
@@ -347,4 +347,4 @@ const documentPlugin = ()=>({
347
347
  });
348
348
  const cli = documentPlugin;
349
349
  export default cli;
350
- export { documentPlugin, getDocumentByEntryName };
350
+ export { documentPlugin, getDocumentByEntryName, processScriptPlaceholders };
@@ -7,24 +7,24 @@ function distributedSsrFragmentKey(remote, expose) {
7
7
  }
8
8
  function getDistributedSsrFragmentContext(response) {
9
9
  const locals = response?.locals;
10
- if (!locals || 'object' != typeof locals) return;
11
- const context = locals[DISTRIBUTED_SSR_FRAGMENTS_LOCALS_KEY];
12
- if (!context || 'object' != typeof context) return;
10
+ if ('object' != typeof locals || null === locals) return;
11
+ const context = DISTRIBUTED_SSR_FRAGMENTS_LOCALS_KEY in locals ? locals[DISTRIBUTED_SSR_FRAGMENTS_LOCALS_KEY] : void 0;
12
+ if ('object' != typeof context || null === context) return;
13
13
  return context;
14
14
  }
15
15
  function useDistributedSsrFragmentProps({ boundaryId, expose }) {
16
16
  const runtimeContext = useRuntimeContext();
17
17
  const locals = runtimeContext.requestContext?.response?.locals;
18
- const request = locals && 'object' == typeof locals ? locals[DISTRIBUTED_SSR_FRAGMENT_REQUEST_LOCALS_KEY] : void 0;
19
- if (!request || 'object' != typeof request || request.boundaryId !== boundaryId || request.expose !== expose) throw new Error(`Distributed SSR fragment request contract mismatch for ${boundaryId} ${expose}.`);
20
- const props = request.props;
21
- if (!props || 'object' != typeof props || Array.isArray(props)) throw new Error(`Distributed SSR fragment request props must be an object for ${boundaryId} ${expose}.`);
18
+ const request = 'object' == typeof locals && null !== locals && DISTRIBUTED_SSR_FRAGMENT_REQUEST_LOCALS_KEY in locals ? locals[DISTRIBUTED_SSR_FRAGMENT_REQUEST_LOCALS_KEY] : void 0;
19
+ if ('object' != typeof request || null === request || !('boundaryId' in request) || request.boundaryId !== boundaryId || !('expose' in request) || request.expose !== expose) throw new Error(`Distributed SSR fragment request contract mismatch for ${boundaryId} ${expose}.`);
20
+ const props = 'props' in request ? request.props : void 0;
21
+ if ('object' != typeof props || null === props || Array.isArray(props)) throw new Error(`Distributed SSR fragment request props must be an object for ${boundaryId} ${expose}.`);
22
22
  return props;
23
23
  }
24
24
  function isThenable(value) {
25
- return 'function' == typeof value.then;
25
+ return void 0 !== value && 'then' in value && 'function' == typeof value.then;
26
26
  }
27
- function DistributedSsrBoundary({ children, expose, fallback, fragmentProps = {}, remote }) {
27
+ function DistributedSsrBoundary({ children, expose, fallback, fragmentProps, remote }) {
28
28
  const runtimeContext = useRuntimeContext();
29
29
  const key = distributedSsrFragmentKey(remote, expose);
30
30
  const attributes = {
@@ -35,12 +35,13 @@ function DistributedSsrBoundary({ children, expose, fallback, fragmentProps = {}
35
35
  children: children
36
36
  });
37
37
  const fragmentContext = getDistributedSsrFragmentContext(runtimeContext.requestContext?.response);
38
- if (!fragmentContext) return /*#__PURE__*/ jsx("div", {
38
+ if (void 0 === fragmentContext) return /*#__PURE__*/ jsx("div", {
39
39
  ...attributes,
40
40
  children: children
41
41
  });
42
- const fragmentOrPromise = fragmentContext.resolve?.(remote, expose, fragmentProps) ?? fragmentContext.fragments?.[key];
43
- if (fragmentOrPromise && isThenable(fragmentOrPromise)) throw fragmentOrPromise;
42
+ const resolverFragmentProps = void 0 === fragmentProps ? {} : Object.fromEntries(Object.entries(fragmentProps));
43
+ const fragmentOrPromise = fragmentContext.resolve?.(remote, expose, resolverFragmentProps) ?? fragmentContext.fragments?.[key];
44
+ if (isThenable(fragmentOrPromise)) throw fragmentOrPromise;
44
45
  const fragment = fragmentOrPromise;
45
46
  if (fragment?.status === 'ready') return /*#__PURE__*/ jsx("div", {
46
47
  ...attributes,
@@ -33,7 +33,7 @@ function staleRecordResult(ref, env, ageMs, maxStaleMs) {
33
33
  }
34
34
  function createLastKnownGoodProvider(options) {
35
35
  const storage = options.storage ?? createInMemoryLkgStorage();
36
- const now = options.now ?? (()=>Date.now());
36
+ const now = options.now ?? (()=>Math.floor(performance.timeOrigin + performance.now()));
37
37
  const maxStaleMs = options.freshness?.maxStaleMs;
38
38
  async function serveFromCache(ref, env, fallback) {
39
39
  const key = deliveryUnitResolutionKey(ref.unitId, env);
@@ -1,3 +1,4 @@
1
+ import { wait } from "@modern-js/utils/universal";
1
2
  const DEFAULT_ATTEMPTS = 3;
2
3
  const DEFAULT_RETRY_DELAY_MS = 100;
3
4
  const DEFAULT_TIMEOUT_MS = 1000;
@@ -43,7 +44,7 @@ const isRetryableError = (error)=>{
43
44
  return error instanceof TypeError || /(?:fetch failed|network|ECONNREFUSED|ECONNRESET|ETIMEDOUT|EAI_AGAIN)/i.test(message);
44
45
  };
45
46
  const isHttpManifestUrl = (id)=>{
46
- if (!id) return false;
47
+ if (void 0 === id || 0 === id.length) return false;
47
48
  try {
48
49
  const url = new URL(id);
49
50
  return ('http:' === url.protocol || 'https:' === url.protocol) && url.pathname.endsWith('.json');
@@ -51,47 +52,35 @@ const isHttpManifestUrl = (id)=>{
51
52
  return false;
52
53
  }
53
54
  };
54
- const defaultWait = (milliseconds)=>new Promise((resolve)=>{
55
- setTimeout(resolve, milliseconds);
55
+ const defaultWait = (milliseconds)=>wait(milliseconds).then(()=>void 0);
56
+ const fetchWithTimeout = (fetchImpl, url, timeoutMs)=>fetchImpl(url, {
57
+ signal: AbortSignal.timeout(timeoutMs)
56
58
  });
57
- const fetchWithTimeout = async (fetchImpl, url, timeoutMs)=>{
58
- const controller = new AbortController();
59
- const timeout = setTimeout(()=>controller.abort(), timeoutMs);
60
- try {
61
- return await fetchImpl(url, {
62
- signal: controller.signal
63
- });
64
- } finally{
65
- clearTimeout(timeout);
66
- }
67
- };
68
59
  const createModuleFederationManifestRecoveryPlugin = (options = {})=>{
69
60
  const attempts = clampInteger(options.attempts, DEFAULT_ATTEMPTS, 1, MAX_ATTEMPTS);
70
61
  const retryDelayMs = clampInteger(options.retryDelayMs, DEFAULT_RETRY_DELAY_MS, 0, MAX_RETRY_DELAY_MS);
71
62
  const timeoutMs = clampInteger(options.timeoutMs, DEFAULT_TIMEOUT_MS, 1, MAX_TIMEOUT_MS);
72
63
  const fetchImpl = options.fetchImpl ?? globalThis.fetch;
73
64
  const waitImpl = options.waitImpl ?? defaultWait;
65
+ const recoverManifest = (url, attempt)=>{
66
+ const fetchManifest = ()=>Promise.resolve().then(()=>fetchWithTimeout(fetchImpl, url, timeoutMs)).then((response)=>{
67
+ if (!response.ok) {
68
+ if (!RETRYABLE_HTTP_STATUSES.has(response.status) || attempt === attempts - 1) return;
69
+ return recoverManifest(url, attempt + 1);
70
+ }
71
+ return Promise.resolve().then(()=>response.json()).then((manifest)=>manifest, ()=>void 0);
72
+ }, (error)=>{
73
+ if (!isRetryableError(error) || attempt === attempts - 1) return;
74
+ return recoverManifest(url, attempt + 1);
75
+ });
76
+ if (attempt > 0 && retryDelayMs > 0) return waitImpl(retryDelayMs).then(fetchManifest);
77
+ return fetchManifest();
78
+ };
74
79
  return {
75
80
  name: 'modern-js-manifest-recovery-plugin',
76
- async errorLoadRemote (args) {
77
- if ('afterResolve' !== args.lifecycle || !isHttpManifestUrl(args.id) || !isRetryableError(args.error) || 'function' != typeof fetchImpl) return;
78
- for(let attempt = 0; attempt < attempts; attempt++){
79
- if (attempt > 0 && retryDelayMs > 0) await waitImpl(retryDelayMs);
80
- try {
81
- const response = await fetchWithTimeout(fetchImpl, args.id, timeoutMs);
82
- if (!response.ok) {
83
- if (!RETRYABLE_HTTP_STATUSES.has(response.status) || attempt === attempts - 1) return;
84
- continue;
85
- }
86
- try {
87
- return await response.json();
88
- } catch {
89
- break;
90
- }
91
- } catch (error) {
92
- if (!isRetryableError(error) || attempt === attempts - 1) break;
93
- }
94
- }
81
+ errorLoadRemote (args) {
82
+ if ('afterResolve' !== args.lifecycle || !isHttpManifestUrl(args.id) || !isRetryableError(args.error) || 'function' != typeof fetchImpl) return Promise.resolve(void 0);
83
+ return recoverManifest(args.id, 0);
95
84
  }
96
85
  };
97
86
  };
@@ -39,8 +39,9 @@ async function generateRoutesForEntry(entrypoint, appContext) {
39
39
  }
40
40
  return routes;
41
41
  }
42
- const generateCode = async (appContext, config, entrypoints, api)=>{
42
+ const generateCode = async (appContext, config, entrypoints, api, options = {})=>{
43
43
  const { internalDirectory, srcDirectory, internalSrcAlias, packageName } = appContext;
44
+ const includeRouteServerLoadersInSsrEntry = false !== options.includeRouteServerLoadersInSsrEntry || !isUseRsc(config);
44
45
  const hooks = api.getHooks();
45
46
  const generatedRoutesByEntry = {};
46
47
  const eagerRouteComponentFilesByEntry = new Map();
@@ -98,6 +99,7 @@ const generateCode = async (appContext, config, entrypoints, api)=>{
98
99
  internalDirectory,
99
100
  splitRouteChunks: config?.output?.splitRouteChunks,
100
101
  isRscClientBundle: isUseRsc(config),
102
+ hydrateRscClientRoutes: options.hydrateRscClientRoutes,
101
103
  srcDirectory,
102
104
  internalSrcAlias: appContext.internalSrcAlias
103
105
  })
@@ -105,12 +107,14 @@ const generateCode = async (appContext, config, entrypoints, api)=>{
105
107
  if (entrypoint.nestedRoutesEntry && (isUseSSRBundle(config) || isUseRsc(config))) {
106
108
  const routesServerFile = getServerLoadersFile(internalDirectory, entryName);
107
109
  const filtedRoutesForServer = filterRoutesForServer(routes);
108
- const routesForServerLoaderMatches = filterRoutesLoader(routes);
109
- const code = __rspack_external__templates_mjs_ab577925.routesForServer({
110
- routesForServerLoaderMatches
111
- });
112
- await fs.ensureFile(routesServerFile);
113
- await fs.writeFile(routesServerFile, code);
110
+ if (includeRouteServerLoadersInSsrEntry) {
111
+ const routesForServerLoaderMatches = filterRoutesLoader(routes);
112
+ const code = __rspack_external__templates_mjs_ab577925.routesForServer({
113
+ routesForServerLoaderMatches
114
+ });
115
+ await fs.ensureFile(routesServerFile);
116
+ await fs.writeFile(routesServerFile, code);
117
+ } else await fs.remove(routesServerFile);
114
118
  const serverRoutesCode = await __rspack_external__templates_mjs_ab577925.fileSystemRoutes({
115
119
  metaName,
116
120
  routes: filtedRoutesForServer,
@@ -120,12 +124,15 @@ const generateCode = async (appContext, config, entrypoints, api)=>{
120
124
  internalDirectory,
121
125
  splitRouteChunks: config?.output?.splitRouteChunks,
122
126
  isRscClientBundle: false,
127
+ isolateRouteDataInRscLayer: isUseRsc(config) && options.isolateRouteDataInRscLayer,
123
128
  srcDirectory,
124
129
  internalSrcAlias: appContext.internalSrcAlias
125
130
  });
126
- await fs.outputFile(path.resolve(internalDirectory, `./${entryName}/routes.server.js`), serverRoutesCode, 'utf8');
131
+ await fs.outputFile(path.resolve(internalDirectory, `./${entryName}/${options.serverRoutesFileName || 'routes.server.js'}`), serverRoutesCode, 'utf8');
127
132
  }
128
- const serverLoaderCombined = __rspack_external__templates_mjs_ab577925.ssrLoaderCombinedModule(entrypoints, entrypoint, config, appContext);
133
+ const serverLoaderCombined = __rspack_external__templates_mjs_ab577925.ssrLoaderCombinedModule(entrypoints, entrypoint, config, appContext, {
134
+ includeRouteServerLoaders: includeRouteServerLoadersInSsrEntry
135
+ });
129
136
  if (serverLoaderCombined) {
130
137
  const serverLoaderFile = getServerCombinedModuleFile(internalDirectory, entryName);
131
138
  await fs.outputFile(serverLoaderFile, serverLoaderCombined);
@@ -89,7 +89,7 @@ async function hasUseClientDirective(componentPath, srcDirectory, internalSrcAli
89
89
  await fh?.close();
90
90
  }
91
91
  }
92
- const fileSystemRoutes = async ({ metaName, routes, ssrMode, nestedRoutesEntry, entryName, internalDirectory, splitRouteChunks = true, isRscClientBundle = false, srcDirectory, internalSrcAlias })=>{
92
+ const fileSystemRoutes = async ({ metaName, routes, ssrMode, nestedRoutesEntry, entryName, internalDirectory, splitRouteChunks = true, isRscClientBundle = false, hydrateRscClientRoutes = false, isolateRouteDataInRscLayer = false, srcDirectory, internalSrcAlias })=>{
93
93
  const components = [];
94
94
  const loadings = [];
95
95
  const errors = [];
@@ -161,7 +161,6 @@ const fileSystemRoutes = async ({ metaName, routes, ssrMode, nestedRoutesEntry,
161
161
  componentPath: route._component,
162
162
  routeId: route.id
163
163
  });
164
- rootLayoutCode = `import RootLayout from '${route._component}'`;
165
164
  component = 'RootLayout';
166
165
  } else if (splitRouteChunks) {
167
166
  lazyImport = createLazyImport({
@@ -182,8 +181,9 @@ const fileSystemRoutes = async ({ metaName, routes, ssrMode, nestedRoutesEntry,
182
181
  component = `component_${components.length - 1}`;
183
182
  }
184
183
  const isClientComponent = 'nested' === route.type && Boolean(route._component) && Boolean(srcDirectory) && Boolean(internalSrcAlias) && await hasUseClientDirective(route._component, srcDirectory, internalSrcAlias);
185
- const shouldHydrateRscRoute = isRscClientBundle && !isClientComponent && !route.loader && !route.data;
184
+ const shouldHydrateRscRoute = hydrateRscClientRoutes && isRscClientBundle && !isClientComponent && ('nested' !== route.type || !route.loader && !route.data);
186
185
  const shouldIncludeClientBundle = !isRscClientBundle || isClientComponent || shouldHydrateRscRoute;
186
+ if ('nested' === route.type && route.isRoot && route._component && shouldIncludeClientBundle) rootLayoutCode = `import RootLayout from '${route._component}'`;
187
187
  const finalRoute = {
188
188
  ...route,
189
189
  loading,
@@ -244,32 +244,30 @@ const fileSystemRoutes = async ({ metaName, routes, ssrMode, nestedRoutesEntry,
244
244
  const importComponentsCode = components.map((component, index)=>`import component_${index} from '${component}';\n`).join('');
245
245
  const importErrorComponentsCode = errors.map((error, index)=>`import error_${index} from '${error}';\n`).join('');
246
246
  let importLoadersCode = '';
247
- for (const [key, loaderInfo] of Object.entries(loadersMap))if (loaderInfo.inline) {
247
+ const isolatedRouteDataDirectory = path.join(internalDirectory, entryName, '__rsc_route_data__');
248
+ await fs.remove(isolatedRouteDataDirectory);
249
+ if (isolateRouteDataInRscLayer) await fs.ensureDir(isolatedRouteDataDirectory);
250
+ for (const [key, loaderInfo] of Object.entries(loadersMap)){
248
251
  const { route } = loaderInfo;
249
- if (route.action) importLoadersCode += `import { loader as ${key}, action as action_${loaderInfo.loaderId} } from "${slash(loaderInfo.filePath)}${getDataLoaderPath({
252
+ const loaderRequest = `${slash(loaderInfo.filePath)}${getDataLoaderPath({
250
253
  loaderId: key,
251
254
  clientData: loaderInfo.clientData,
252
- action: route.action,
255
+ action: route.action || false,
253
256
  inline: loaderInfo.inline,
254
257
  routeId: loaderInfo.routeId,
255
258
  inValidSSRRoute: loaderInfo.inValidSSRRoute
256
- })}";\n`;
257
- else importLoadersCode += `import { loader as ${key} } from "${slash(loaderInfo.filePath)}${getDataLoaderPath({
258
- loaderId: key,
259
- clientData: loaderInfo.clientData,
260
- action: false,
261
- inline: loaderInfo.inline,
262
- routeId: route.id,
263
- inValidSSRRoute: loaderInfo.inValidSSRRoute
264
- })}";\n`;
265
- } else importLoadersCode += `import ${key} from "${slash(loaderInfo.filePath)}${getDataLoaderPath({
266
- loaderId: key,
267
- clientData: loaderInfo.clientData,
268
- action: false,
269
- inline: loaderInfo.inline,
270
- routeId: loaderInfo.routeId,
271
- inValidSSRRoute: loaderInfo.inValidSSRRoute
272
- })}";\n`;
259
+ })}`;
260
+ let loaderImport = loaderRequest;
261
+ if (isolateRouteDataInRscLayer) {
262
+ const isolatedLoaderFile = path.join(isolatedRouteDataDirectory, `${key}.js`);
263
+ const isolatedLoaderCode = loaderInfo.inline ? route.action ? `export { loader, action } from ${JSON.stringify(loaderRequest)};` : `export { loader } from ${JSON.stringify(loaderRequest)};` : `export { default } from ${JSON.stringify(loaderRequest)};`;
264
+ await fs.outputFile(isolatedLoaderFile, isolatedLoaderCode, 'utf8');
265
+ loaderImport = `./__rsc_route_data__/${key}.js`;
266
+ }
267
+ if (loaderInfo.inline) if (route.action) importLoadersCode += `import { loader as ${key}, action as action_${loaderInfo.loaderId} } from "${loaderImport}";\n`;
268
+ else importLoadersCode += `import { loader as ${key} } from "${loaderImport}";\n`;
269
+ else importLoadersCode += `import ${key} from "${loaderImport}";\n`;
270
+ }
273
271
  let importConfigsCode = '';
274
272
  for (const [key, configPath] of Object.entries(configsMap))importConfigsCode += `import * as ${key} from "${slash(configPath)}";\n`;
275
273
  await fs.ensureFile(loadersMapFile);
@@ -295,7 +293,7 @@ const fileSystemRoutes = async ({ metaName, routes, ssrMode, nestedRoutesEntry,
295
293
  ${routeComponentsCode}
296
294
  `;
297
295
  };
298
- function ssrLoaderCombinedModule(entrypoints, entrypoint, config, appContext) {
296
+ function ssrLoaderCombinedModule(entrypoints, entrypoint, config, appContext, options = {}) {
299
297
  const { entryName, isMainEntry } = entrypoint;
300
298
  const { packageName } = appContext;
301
299
  const ssr = getEntryOptions(entryName, isMainEntry, config.server.ssr, config.server.ssrByEntries, packageName);
@@ -303,6 +301,17 @@ function ssrLoaderCombinedModule(entrypoints, entrypoint, config, appContext) {
303
301
  if (entrypoint.nestedRoutesEntry && (ssr || ssg)) {
304
302
  const serverLoaderRuntime = require.resolve('@modern-js/plugin-data-loader/runtime');
305
303
  const serverLoadersFile = './route-server-loaders.js';
304
+ const includeRouteServerLoaders = false !== options.includeRouteServerLoaders;
305
+ if (!includeRouteServerLoaders) {
306
+ if (!config.source.enableAsyncEntry) return `export * from "${slash(serverLoaderRuntime)}"`;
307
+ return `
308
+ async function loadModules() {
309
+ return import("${slash(serverLoaderRuntime)}");
310
+ }
311
+
312
+ export { loadModules };
313
+ `;
314
+ }
306
315
  const combinedModule = `export * from "${slash(serverLoaderRuntime)}"; export * from "${serverLoadersFile}"`;
307
316
  if (!config.source.enableAsyncEntry) return combinedModule;
308
317
  return `
@@ -323,7 +332,7 @@ function ssrLoaderCombinedModule(entrypoints, entrypoint, config, appContext) {
323
332
  }
324
333
  return null;
325
334
  }
326
- const runtimeGlobalContext = async ({ entryName, metaName, srcDirectory, nestedRoutesEntry, internalSrcAlias, globalApp, rscType = false, basename })=>{
335
+ const runtimeGlobalContext = async ({ entryName, metaName, srcDirectory, nestedRoutesEntry, internalSrcAlias, globalApp, rscType = false, routesImportPath = './routes', basename })=>{
327
336
  const imports = [
328
337
  `import { setGlobalContext } from '@${metaName}/runtime/context';`
329
338
  ];
@@ -354,7 +363,7 @@ const runtimeGlobalContext = async ({ entryName, metaName, srcDirectory, nestedR
354
363
  const enableRsc = Boolean(rscType);
355
364
  if (isClient) return `${imports.join('\n')}
356
365
 
357
- import { routes } from './routes';
366
+ import { routes } from '${routesImportPath}';
358
367
 
359
368
  const entryName = '${entryName}';
360
369
  const basename = '${basename || '/'}';
@@ -370,7 +379,7 @@ const runtimeGlobalContext = async ({ entryName, metaName, srcDirectory, nestedR
370
379
  `;
371
380
  return `${imports.join('\n')}
372
381
 
373
- import { routes } from './routes';
382
+ import { routes } from '${routesImportPath}';
374
383
 
375
384
  const entryName = '${entryName}';
376
385
  const basename = '${basename || '/'}';
@@ -20,7 +20,12 @@ async function handleGeneratorEntryCode(api, entrypoints, options = {}) {
20
20
  const { generatorRegisterCode, generateCode, generatorServerRegisterCode } = await import("./code/index.mjs");
21
21
  originEntrypointsByKey.set(entrypointsKey, cloneDeep(entrypoints));
22
22
  const enableRsc = resolvedConfig?.server?.rsc;
23
- const routesByEntry = await generateCode(appContext, resolvedConfig, entrypoints, api);
23
+ const routesByEntry = await generateCode(appContext, resolvedConfig, entrypoints, api, {
24
+ hydrateRscClientRoutes: normalizedOptions.hydrateRscClientRoutes,
25
+ includeRouteServerLoadersInSsrEntry: normalizedOptions.includeRouteServerLoadersInSsrEntry,
26
+ isolateRouteDataInRscLayer: normalizedOptions.isolateRouteDataInRscLayer,
27
+ serverRoutesFileName: normalizedOptions.serverRoutesFileName
28
+ });
24
29
  await Promise.all(entrypoints.map(async (entrypoint)=>{
25
30
  if (entrypoint.nestedRoutesEntry || entrypoint.pageRoutesEntry) {
26
31
  const route = appContext.serverRoutes.find((r)=>r.entryName === entrypoint.entryName);
@@ -43,6 +48,7 @@ async function handleGeneratorEntryCode(api, entrypoints, options = {}) {
43
48
  internalSrcAlias: appContext.internalSrcAlias,
44
49
  globalApp: entrypoint.fileSystemRoutes?.globalApp,
45
50
  rscType: 'server',
51
+ routesImportPath: normalizedOptions.serverRoutesFileName ? `./${normalizedOptions.serverRoutesFileName.replace(/\.js$/, '')}` : void 0,
46
52
  basename
47
53
  }));
48
54
  }