@bleedingdev/modern-js-runtime 3.5.0-ultramodern.10 → 3.5.0-ultramodern.101

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 (155) hide show
  1. package/dist/cjs/boundary-debugger/index.js +13 -3
  2. package/dist/cjs/cli/index.js +1 -11
  3. package/dist/cjs/cli/registry.js +18 -0
  4. package/dist/cjs/cli/ssr/index.js +3 -2
  5. package/dist/cjs/cli/ssr/loadable-bundler-plugin.js +8 -4
  6. package/dist/cjs/core/browser/hydrate.js +16 -2
  7. package/dist/cjs/core/browser/index.js +19 -18
  8. package/dist/cjs/core/context/index.js +3 -0
  9. package/dist/cjs/core/context/public.js +49 -0
  10. package/dist/cjs/core/context/runtime.js +6 -8
  11. package/dist/cjs/core/react/wrapper.js +57 -0
  12. package/dist/cjs/core/server/federatedCss.js +7 -3
  13. package/dist/cjs/core/server/requestHandler.js +15 -45
  14. package/dist/cjs/core/server/requestResponse.js +83 -0
  15. package/dist/cjs/core/server/routerCleanup.js +16 -6
  16. package/dist/cjs/core/server/scriptOrder.js +13 -10
  17. package/dist/cjs/core/server/stream/afterTemplate.js +9 -5
  18. package/dist/cjs/core/server/stream/template.js +3 -3
  19. package/dist/cjs/core/server/string/index.js +3 -3
  20. package/dist/cjs/core/server/string/loadable.js +3 -11
  21. package/dist/cjs/document/cli/index.js +5 -2
  22. package/dist/cjs/index.js +7 -6
  23. package/dist/cjs/module-federation/consume-surface.js +199 -0
  24. package/dist/cjs/module-federation/distributed-ssr.js +134 -0
  25. package/dist/cjs/module-federation/index.js +258 -120
  26. package/dist/cjs/module-federation/last-known-good.js +124 -0
  27. package/dist/cjs/module-federation/manifest-recovery-runtime-plugin.js +140 -0
  28. package/dist/cjs/module-federation/surface-resolution-types.js +61 -0
  29. package/dist/cjs/router/cli/code/nestedRoutes.js +3 -0
  30. package/dist/cjs/router/cli/code/templates.js +3 -2
  31. package/dist/cjs/router/cli/constants.js +1 -0
  32. package/dist/cjs/router/cli/nestedRoutesSpec.js +3 -1
  33. package/dist/cjs/router/runtime/hooks.js +7 -6
  34. package/dist/cjs/router/runtime/internal.js +30 -16
  35. package/dist/cjs/router/runtime/plugin.js +6 -7
  36. package/dist/cjs/router/runtime/provider.js +58 -12
  37. package/dist/esm/boundary-debugger/index.mjs +13 -3
  38. package/dist/esm/cli/code.mjs +12 -12
  39. package/dist/esm/cli/index.mjs +2 -12
  40. package/dist/esm/cli/registry.mjs +0 -0
  41. package/dist/esm/cli/ssr/index.mjs +3 -2
  42. package/dist/esm/cli/ssr/loadable-bundler-plugin.mjs +8 -4
  43. package/dist/esm/core/browser/hydrate.mjs +15 -4
  44. package/dist/esm/core/browser/index.mjs +15 -17
  45. package/dist/esm/core/context/index.mjs +1 -1
  46. package/dist/esm/core/context/public.mjs +5 -0
  47. package/dist/esm/core/context/runtime.mjs +4 -6
  48. package/dist/esm/core/react/wrapper.mjs +58 -1
  49. package/dist/esm/core/server/federatedCss.mjs +7 -3
  50. package/dist/esm/core/server/requestHandler.mjs +15 -45
  51. package/dist/esm/core/server/requestResponse.mjs +39 -0
  52. package/dist/esm/core/server/routerCleanup.mjs +11 -4
  53. package/dist/esm/core/server/scriptOrder.mjs +11 -8
  54. package/dist/esm/core/server/stream/afterTemplate.mjs +10 -6
  55. package/dist/esm/core/server/stream/template.mjs +3 -3
  56. package/dist/esm/core/server/string/index.mjs +3 -3
  57. package/dist/esm/core/server/string/loadable.mjs +3 -8
  58. package/dist/esm/document/cli/index.mjs +1 -1
  59. package/dist/esm/exports/loadable.mjs +3 -3
  60. package/dist/esm/index.mjs +2 -1
  61. package/dist/esm/module-federation/consume-surface.mjs +158 -0
  62. package/dist/esm/module-federation/distributed-ssr.mjs +81 -0
  63. package/dist/esm/module-federation/index.mjs +6 -0
  64. package/dist/esm/module-federation/last-known-good.mjs +80 -0
  65. package/dist/esm/module-federation/manifest-recovery-runtime-plugin.mjs +100 -0
  66. package/dist/esm/module-federation/surface-resolution-types.mjs +8 -0
  67. package/dist/esm/router/cli/code/index.mjs +5 -5
  68. package/dist/esm/router/cli/code/nestedRoutes.mjs +3 -0
  69. package/dist/esm/router/cli/code/templates.mjs +3 -2
  70. package/dist/esm/router/cli/constants.mjs +1 -0
  71. package/dist/esm/router/cli/handler.mjs +3 -3
  72. package/dist/esm/router/cli/nestedRoutesSpec.mjs +3 -1
  73. package/dist/esm/router/runtime/hooks.mjs +7 -6
  74. package/dist/esm/router/runtime/internal.mjs +26 -18
  75. package/dist/esm/router/runtime/plugin.mjs +6 -7
  76. package/dist/esm/router/runtime/provider.mjs +56 -13
  77. package/dist/esm-node/boundary-debugger/index.mjs +13 -3
  78. package/dist/esm-node/cli/code.mjs +12 -12
  79. package/dist/esm-node/cli/index.mjs +2 -12
  80. package/dist/esm-node/cli/registry.mjs +1 -0
  81. package/dist/esm-node/cli/ssr/index.mjs +3 -2
  82. package/dist/esm-node/cli/ssr/loadable-bundler-plugin.mjs +8 -4
  83. package/dist/esm-node/core/browser/hydrate.mjs +15 -4
  84. package/dist/esm-node/core/browser/index.mjs +15 -17
  85. package/dist/esm-node/core/context/index.mjs +1 -1
  86. package/dist/esm-node/core/context/public.mjs +6 -0
  87. package/dist/esm-node/core/context/runtime.mjs +4 -6
  88. package/dist/esm-node/core/react/wrapper.mjs +58 -1
  89. package/dist/esm-node/core/server/federatedCss.mjs +7 -3
  90. package/dist/esm-node/core/server/requestHandler.mjs +15 -45
  91. package/dist/esm-node/core/server/requestResponse.mjs +40 -0
  92. package/dist/esm-node/core/server/routerCleanup.mjs +11 -4
  93. package/dist/esm-node/core/server/scriptOrder.mjs +11 -8
  94. package/dist/esm-node/core/server/stream/afterTemplate.mjs +10 -6
  95. package/dist/esm-node/core/server/stream/template.mjs +3 -3
  96. package/dist/esm-node/core/server/string/index.mjs +3 -3
  97. package/dist/esm-node/core/server/string/loadable.mjs +3 -8
  98. package/dist/esm-node/document/cli/index.mjs +1 -1
  99. package/dist/esm-node/exports/loadable.mjs +3 -3
  100. package/dist/esm-node/index.mjs +2 -1
  101. package/dist/esm-node/module-federation/consume-surface.mjs +159 -0
  102. package/dist/esm-node/module-federation/distributed-ssr.mjs +82 -0
  103. package/dist/esm-node/module-federation/index.mjs +6 -0
  104. package/dist/esm-node/module-federation/last-known-good.mjs +81 -0
  105. package/dist/esm-node/module-federation/manifest-recovery-runtime-plugin.mjs +101 -0
  106. package/dist/esm-node/module-federation/surface-resolution-types.mjs +9 -0
  107. package/dist/esm-node/router/cli/code/index.mjs +5 -5
  108. package/dist/esm-node/router/cli/code/nestedRoutes.mjs +3 -0
  109. package/dist/esm-node/router/cli/code/templates.mjs +3 -2
  110. package/dist/esm-node/router/cli/constants.mjs +1 -0
  111. package/dist/esm-node/router/cli/handler.mjs +3 -3
  112. package/dist/esm-node/router/cli/nestedRoutesSpec.mjs +3 -1
  113. package/dist/esm-node/router/runtime/hooks.mjs +7 -6
  114. package/dist/esm-node/router/runtime/internal.mjs +26 -18
  115. package/dist/esm-node/router/runtime/plugin.mjs +6 -7
  116. package/dist/esm-node/router/runtime/provider.mjs +56 -13
  117. package/dist/types/boundary-debugger/index.d.ts +1 -1
  118. package/dist/types/cli/registry.d.ts +2 -0
  119. package/dist/types/common.d.ts +8 -1
  120. package/dist/types/core/browser/hydrate.d.ts +2 -1
  121. package/dist/types/core/browser/index.d.ts +4 -1
  122. package/dist/types/core/context/index.d.ts +26 -10
  123. package/dist/types/core/context/monitors/default.d.ts +10 -2
  124. package/dist/types/core/context/monitors/index.d.ts +1 -1
  125. package/dist/types/core/context/monitors/index.server.d.ts +2 -2
  126. package/dist/types/core/context/public.d.ts +27 -0
  127. package/dist/types/core/context/runtime.d.ts +12 -22
  128. package/dist/types/core/react/index.d.ts +1 -1
  129. package/dist/types/core/server/requestResponse.d.ts +15 -0
  130. package/dist/types/core/server/routerCleanup.d.ts +2 -1
  131. package/dist/types/core/server/scriptOrder.d.ts +1 -1
  132. package/dist/types/core/server/stream/shared.d.ts +2 -2
  133. package/dist/types/core/server/string/loadable.d.ts +0 -2
  134. package/dist/types/document/cli/index.d.ts +1 -0
  135. package/dist/types/exports/head.d.ts +1 -1
  136. package/dist/types/index.d.ts +5 -5
  137. package/dist/types/internal.d.ts +0 -1
  138. package/dist/types/module-federation/consume-surface.d.ts +104 -0
  139. package/dist/types/module-federation/distributed-ssr.d.ts +61 -0
  140. package/dist/types/module-federation/index.d.ts +6 -0
  141. package/dist/types/module-federation/last-known-good.d.ts +72 -0
  142. package/dist/types/module-federation/manifest-recovery-runtime-plugin.d.ts +25 -0
  143. package/dist/types/module-federation/surface-resolution-types.d.ts +23 -0
  144. package/dist/types/router/cli/constants.d.ts +1 -0
  145. package/dist/types/router/runtime/hooks.d.ts +10 -6
  146. package/dist/types/router/runtime/internal.d.ts +13 -3
  147. package/dist/types/router/runtime/plugin.d.ts +1 -1
  148. package/dist/types/router/runtime/plugin.node.d.ts +1 -1
  149. package/dist/types/router/runtime/provider.d.ts +28 -11
  150. package/dist/types/router/runtime/types.d.ts +27 -5
  151. package/package.json +47 -27
  152. package/dist/cjs/exports/tanstack-router.js +0 -83
  153. package/dist/esm/exports/tanstack-router.mjs +0 -30
  154. package/dist/esm-node/exports/tanstack-router.mjs +0 -31
  155. package/dist/types/exports/tanstack-router.d.ts +0 -88
@@ -1,10 +1,10 @@
1
1
  import "node:module";
2
- import { SSR_HYDRATION_ID_PREFIX } from "@modern-js/utils/universal/constants";
3
2
  import { parseCookie } from "cookie";
3
+ import { createRoot } from "react-dom/client";
4
4
  import { getGlobalInternalRuntimeContext } from "../context/index.mjs";
5
5
  import { getInitialContext } from "../context/runtime.mjs";
6
6
  import { wrapRuntimeContextProvider } from "../react/wrapper.mjs";
7
- import { hydrateRoot } from "./hydrate.mjs";
7
+ import { hydrateRoot, hydrateWithReact } from "./hydrate.mjs";
8
8
  const IS_REACT18 = 'true' === process.env.IS_REACT18;
9
9
  const getQuery = ()=>window.location.search.substring(1).split('&').reduce((res, item)=>{
10
10
  const [key, value] = item.split('=');
@@ -48,10 +48,9 @@ function getSSRData() {
48
48
  function isClientArgs(id) {
49
49
  return void 0 === id || 'string' == typeof id || "u" > typeof HTMLElement && id instanceof HTMLElement;
50
50
  }
51
- async function render(App, id) {
51
+ async function renderApp(App, id, hydrateFromSsrData, internalRuntimeContext) {
52
52
  const context = getInitialContext();
53
53
  const runBeforeRender = async (context)=>{
54
- const internalRuntimeContext = getGlobalInternalRuntimeContext();
55
54
  const api = internalRuntimeContext.pluginAPI;
56
55
  api.updateRuntimeContext(context);
57
56
  const hooks = internalRuntimeContext.hooks;
@@ -71,17 +70,23 @@ async function render(App, id) {
71
70
  return renderFunc(App, rootElement);
72
71
  }
73
72
  async function ModernHydrate(App, callback) {
74
- const hydrateFunc = IS_REACT18 ? hydrateWithReact18 : hydrateWithReact17;
75
- return hydrateFunc(App, rootElement, callback);
73
+ if (IS_REACT18) return hydrateWithReact(App, rootElement);
74
+ return hydrateWithReact17(App, rootElement, callback);
76
75
  }
77
- if (window._SSR_DATA) return hydrateRoot(App, context, ModernRender, ModernHydrate);
76
+ if (hydrateFromSsrData && process.env.MODERN_ENABLE_HYDRATION && window._SSR_DATA) return hydrateRoot(App, context, ModernRender, ModernHydrate);
78
77
  return ModernRender(wrapRuntimeContextProvider(App, context));
79
78
  }
80
79
  throw Error('`render` function needs id in browser environment, it needs to be string or element');
81
80
  }
81
+ async function render(App, id) {
82
+ return renderApp(App, id, true, getGlobalInternalRuntimeContext());
83
+ }
84
+ function createNestedAppRenderer() {
85
+ const internalRuntimeContext = getGlobalInternalRuntimeContext();
86
+ return (App, id)=>renderApp(App, id, false, internalRuntimeContext);
87
+ }
82
88
  async function renderWithReact18(App, rootElement) {
83
- const ReactDOM = await import("react-dom/client");
84
- const root = ReactDOM.createRoot(rootElement);
89
+ const root = createRoot(rootElement);
85
90
  root.render(App);
86
91
  return root;
87
92
  }
@@ -90,16 +95,9 @@ async function renderWithReact17(App, rootElement) {
90
95
  ReactDOM.render(App, rootElement);
91
96
  return rootElement;
92
97
  }
93
- async function hydrateWithReact18(App, rootElement) {
94
- const ReactDOM = await import("react-dom/client");
95
- const root = ReactDOM.hydrateRoot(rootElement, App, {
96
- identifierPrefix: SSR_HYDRATION_ID_PREFIX
97
- });
98
- return root;
99
- }
100
98
  async function hydrateWithReact17(App, rootElement, callback) {
101
99
  const ReactDOM = await import("react-dom");
102
100
  const root = ReactDOM.hydrate(App, rootElement, callback);
103
101
  return root;
104
102
  }
105
- export { hydrateWithReact17, hydrateWithReact18, render, renderWithReact17, renderWithReact18 };
103
+ export { createNestedAppRenderer, hydrateWithReact, hydrateWithReact17, render, renderWithReact17, renderWithReact18 };
@@ -44,7 +44,7 @@ function getGlobalBasename() {
44
44
  export { DefaultNotFound } from "../../router/runtime/DefaultNotFound.mjs";
45
45
  export { modifyRoutes, onAfterCreateRouter, onAfterHydrateRouter, onBeforeCreateRouter, onBeforeCreateRoutes, onBeforeHydrateRouter } from "../../router/runtime/hooks.mjs";
46
46
  export { applyRouterRuntimeState, applyRouterServerPrepareResult, cleanupRouterRuntimeState, createRouterRuntimeState, createRouterServerSnapshot, getRouterHydrationScripts, getRouterMatchedRouteIds, getRouterRuntimeState, getRouterServerSnapshot } from "../../router/runtime/lifecycle.mjs";
47
- export { registerRouterProvider, resolveRouterProvider, routerProviderRegistryHooks } from "../../router/runtime/provider.mjs";
47
+ export { createRouterProviderRealm, registerRouterProvider, resolveRouterProvider, routerProviderRegistryHooks } from "../../router/runtime/provider.mjs";
48
48
  export { createRuntimeContextExtension } from "./extensions.mjs";
49
49
  export { InternalRuntimeContext, RuntimeContext, getInitialContext } from "./runtime.mjs";
50
50
  export { getServerPayload, setServerPayload } from "./serverPayload/index.mjs";
@@ -0,0 +1,6 @@
1
+ import "node:module";
2
+ import { createContext, useContext } from "react";
3
+ const RuntimeContext = createContext({});
4
+ const ReactRuntimeContext = RuntimeContext;
5
+ const useRuntimeContext = ()=>useContext(RuntimeContext);
6
+ export { ReactRuntimeContext, RuntimeContext, useRuntimeContext };
@@ -1,9 +1,7 @@
1
1
  import "node:module";
2
- import { ROUTE_MANIFEST } from "@modern-js/utils/universal/constants";
3
- import { createContext, useContext } from "react";
2
+ import { createContext } from "react";
3
+ const ROUTE_MANIFEST = '_MODERNJS_ROUTE_MANIFEST';
4
4
  const InternalRuntimeContext = createContext({});
5
- const RuntimeContext = createContext({});
6
- const ReactRuntimeContext = RuntimeContext;
7
5
  const getInitialContext = (isBrowser = true, routeManifest)=>{
8
6
  const requestContext = {
9
7
  request: {},
@@ -16,5 +14,5 @@ const getInitialContext = (isBrowser = true, routeManifest)=>{
16
14
  context: requestContext
17
15
  };
18
16
  };
19
- const useRuntimeContext = ()=>useContext(RuntimeContext);
20
- export { InternalRuntimeContext, ReactRuntimeContext, RuntimeContext, getInitialContext, useRuntimeContext };
17
+ export { ReactRuntimeContext, RuntimeContext, useRuntimeContext } from "./public.mjs";
18
+ export { InternalRuntimeContext, getInitialContext };
@@ -1,9 +1,45 @@
1
1
  import "node:module";
2
2
  import { jsx } from "react/jsx-runtime";
3
3
  import { HelmetProvider } from "react-helmet-async";
4
- import { InternalRuntimeContext, RuntimeContext } from "../context/index.mjs";
4
+ import { InternalRuntimeContext, RuntimeContext, getGlobalEnableRsc } from "../context/index.mjs";
5
5
  import { stripRuntimeContextExtensions } from "../context/extensions.mjs";
6
6
  import { ensureHelmetContext } from "../context/helmetContext.mjs";
7
+ function toRscSafeRecord(value) {
8
+ if (!value || 'object' != typeof value) return value;
9
+ return Object.fromEntries(Object.entries(value));
10
+ }
11
+ function createRscSafeSsrContext(ssrContext) {
12
+ if (!ssrContext) return ssrContext;
13
+ const { request } = ssrContext;
14
+ return {
15
+ nonce: ssrContext.nonce,
16
+ useJsonScript: ssrContext.useJsonScript,
17
+ htmlModifiers: [],
18
+ baseUrl: ssrContext.baseUrl,
19
+ request: request ? {
20
+ url: request.url,
21
+ userAgent: request.userAgent,
22
+ cookie: request.cookie,
23
+ pathname: request.pathname,
24
+ query: toRscSafeRecord(request.query),
25
+ params: toRscSafeRecord(request.params),
26
+ headers: toRscSafeRecord(request.headers),
27
+ host: request.host,
28
+ referer: request.referer
29
+ } : request,
30
+ mode: ssrContext.mode,
31
+ loaderFailureMode: ssrContext.loaderFailureMode
32
+ };
33
+ }
34
+ function createRscSafeRequestContext(ssrContext) {
35
+ const safeSsrContext = createRscSafeSsrContext(ssrContext);
36
+ return {
37
+ request: safeSsrContext?.request || {},
38
+ response: {
39
+ locals: ssrContext?.response?.locals || {}
40
+ }
41
+ };
42
+ }
7
43
  function wrapRuntimeContextProvider(App, contextValue) {
8
44
  const { isBrowser, initialData, routes, context, routeManifest, routerContext, unstable_getBlockNavState, ssrContext, _internalContext, _internalRouterBaseName, ...rest } = contextValue;
9
45
  const internalContextValue = contextValue;
@@ -16,6 +52,27 @@ function wrapRuntimeContextProvider(App, contextValue) {
16
52
  ...rest
17
53
  };
18
54
  stripRuntimeContextExtensions(runtimeContextValue);
55
+ if (getGlobalEnableRsc() && !isBrowser) {
56
+ const rscSafeRequestContext = createRscSafeRequestContext(ssrContext);
57
+ const rscInternalContextValue = {
58
+ ...internalContextValue,
59
+ context: rscSafeRequestContext,
60
+ requestContext: rscSafeRequestContext,
61
+ ssrContext: createRscSafeSsrContext(ssrContext)
62
+ };
63
+ const rscRuntimeContextValue = {
64
+ ...runtimeContextValue,
65
+ context: rscSafeRequestContext,
66
+ requestContext: rscSafeRequestContext
67
+ };
68
+ return /*#__PURE__*/ jsx(InternalRuntimeContext.Provider, {
69
+ value: rscInternalContextValue,
70
+ children: /*#__PURE__*/ jsx(RuntimeContext.Provider, {
71
+ value: rscRuntimeContextValue,
72
+ children: App
73
+ })
74
+ });
75
+ }
19
76
  return /*#__PURE__*/ jsx(InternalRuntimeContext.Provider, {
20
77
  value: internalContextValue,
21
78
  children: /*#__PURE__*/ jsx(RuntimeContext.Provider, {
@@ -1,13 +1,17 @@
1
1
  import "node:module";
2
2
  import { attributesToString } from "./utils.mjs";
3
+ const escapeHtmlAttribute = (value)=>value.replaceAll('&', '&amp;').replaceAll('"', '&quot;').replaceAll('<', '&lt;').replaceAll('>', '&gt;');
3
4
  const createFederatedCssLinks = (assets, options)=>{
4
5
  if (void 0 === assets || 0 === assets.length) return '';
5
6
  const seen = new Set(options.existingAssets || []);
6
7
  const attributes = attributesToString(options.attributes || {});
7
8
  const links = [];
8
- for (const asset of assets)if (!('' === asset || seen.has(asset) || options.template.includes(asset))) {
9
- seen.add(asset);
10
- links.push(`<link${attributes} href="${asset}" rel="stylesheet" />`);
9
+ for (const asset of assets){
10
+ const href = escapeHtmlAttribute(asset);
11
+ if (!('' === asset || seen.has(asset) || options.template.includes(asset) || options.template.includes(href))) {
12
+ seen.add(asset);
13
+ links.push(`<link${attributes} href="${href}" rel="stylesheet" />`);
14
+ }
11
15
  }
12
16
  return links.join('');
13
17
  };
@@ -3,15 +3,13 @@ import { jsx } from "react/jsx-runtime";
3
3
  import { storage } from "@modern-js/runtime-utils/node";
4
4
  import { getPathname, parseCookie, parseHeaders, parseQuery } from "@modern-js/runtime-utils/universal/request";
5
5
  import react, { Fragment } from "react";
6
- import { getRouterServerSnapshot } from "../../router/runtime/lifecycle.mjs";
7
- import { handleRSCRedirect } from "../../router/runtime/rsc-router.mjs";
8
6
  import { getGlobalInternalRuntimeContext, getGlobalRSCRoot } from "../context/index.mjs";
9
7
  import { getInitialContext } from "../context/runtime.mjs";
10
8
  import { getServerPayload } from "../context/serverPayload/index.mjs";
11
9
  import { createRoot } from "../react/index.mjs";
12
10
  import { CHUNK_CSS_PLACEHOLDER } from "./constants.mjs";
13
- import { withRouterCleanup } from "./routerCleanup.mjs";
14
- import { SSRErrors } from "./tracer.mjs";
11
+ import { applyRouterSnapshotResult, createLoaderRedirectResponse, finalizeRenderResponse } from "./requestResponse.mjs";
12
+ import { createRouterCleanup, finishWithRouterCleanup, runWithRouterCleanupOnError } from "./routerCleanup.mjs";
15
13
  import { getSSRConfigByEntry, getSSRMode } from "./utils.mjs";
16
14
  async function handleRSCRequest(request, Root, context, options, handleRequest) {
17
15
  const serverPayload = getServerPayload();
@@ -31,29 +29,6 @@ async function handleRSCRequest(request, Root, context, options, handleRequest)
31
29
  runtimeContext: context
32
30
  });
33
31
  }
34
- const isRedirectStatus = (status)=>status >= 300 && status <= 399;
35
- const processRedirect = (headers, status, ctx)=>{
36
- if (ctx.enableRsc && ctx.isRSCNavigation) return handleRSCRedirect(headers, ctx.basename, status);
37
- return new Response(null, {
38
- status,
39
- headers
40
- });
41
- };
42
- const applyRouterSnapshotResult = (context, onError)=>{
43
- const routerServerSnapshot = getRouterServerSnapshot(context);
44
- const routerStatusCode = routerServerSnapshot?.statusCode ?? context.routerContext?.statusCode;
45
- if (routerStatusCode && 200 !== routerStatusCode) context.ssrContext?.response.status(routerStatusCode);
46
- const errors = Object.values(routerServerSnapshot?.errors || context.routerContext?.errors || {});
47
- if (errors.length > 0) onError(errors[0], SSRErrors.LOADER_ERROR);
48
- };
49
- const createLoaderRedirectResponse = (beforeRenderResult, redirectCtx)=>{
50
- if (!beforeRenderResult || !isRedirectStatus(beforeRenderResult.status)) return;
51
- if (beforeRenderResult.headers.has('X-Modernjs-Redirect')) return beforeRenderResult;
52
- const redirectUrl = beforeRenderResult.headers.get('Location') || '/';
53
- return processRedirect(new Headers({
54
- Location: redirectUrl
55
- }), beforeRenderResult.status, redirectCtx);
56
- };
57
32
  const renderRequest = async (request, Root, context, options, handleRequest, enableRsc)=>{
58
33
  if (enableRsc) return handleRSCRequest(request, Root, context, options, handleRequest);
59
34
  return handleRequest(request, Root, {
@@ -61,17 +36,6 @@ const renderRequest = async (request, Root, context, options, handleRequest, ena
61
36
  runtimeContext: context
62
37
  });
63
38
  };
64
- const finalizeRenderResponse = (response, responseProxy, redirectCtx, routerCleanup)=>{
65
- if (-1 !== responseProxy.status && isRedirectStatus(responseProxy.status) && responseProxy.headers.Location) return processRedirect(new Headers(responseProxy.headers), responseProxy.status, redirectCtx);
66
- Object.entries(responseProxy.headers).forEach(([key, value])=>{
67
- response.headers.set(key, value);
68
- });
69
- if (-1 !== responseProxy.status) return routerCleanup.deferUntilBodyDone(new Response(response.body, {
70
- status: responseProxy.status,
71
- headers: response.headers
72
- }));
73
- return routerCleanup.deferUntilBodyDone(response);
74
- };
75
39
  function createSSRContext(request, options) {
76
40
  const { config, loaderContext, onError, onTiming, locals, resource, params, responseProxy, reporter } = options;
77
41
  const { nonce, useJsonScript } = config;
@@ -167,20 +131,26 @@ const createRequestHandler = async (handleRequest, createRequestOptions)=>{
167
131
  isRSCNavigation: 'true' === request.headers.get('x-rsc-tree'),
168
132
  basename: ssrContext.baseUrl || '/'
169
133
  };
170
- return withRouterCleanup(context, options.onError, async (routerCleanup)=>{
171
- const beforeRenderResult = await runBeforeRender(context);
134
+ const routerCleanup = createRouterCleanup(context, options.onError);
135
+ const beforeRenderResult = await runWithRouterCleanupOnError(routerCleanup, ()=>runBeforeRender(context));
136
+ await runWithRouterCleanupOnError(routerCleanup, ()=>{
172
137
  applyRouterSnapshotResult(context, options.onError);
173
- if ("u" > typeof Response) {
174
- const redirectResponse = createLoaderRedirectResponse(beforeRenderResult, redirectCtx);
175
- if (redirectResponse) return redirectResponse;
138
+ });
139
+ if ("u" > typeof Response) {
140
+ const redirectResponse = await runWithRouterCleanupOnError(routerCleanup, ()=>createLoaderRedirectResponse(beforeRenderResult, redirectCtx));
141
+ if (redirectResponse) {
142
+ await routerCleanup.run();
143
+ return redirectResponse;
176
144
  }
145
+ }
146
+ await runWithRouterCleanupOnError(routerCleanup, ()=>{
177
147
  if (!createRequestOptions?.enableRsc) {
178
148
  const { htmlTemplate } = options.resource;
179
149
  options.resource.htmlTemplate = htmlTemplate.replace('</head>', `${CHUNK_CSS_PLACEHOLDER}</head>`);
180
150
  }
181
- const response = await renderRequest(request, Root, context, options, handleRequest, !!createRequestOptions?.enableRsc);
182
- return finalizeRenderResponse(response, responseProxy, redirectCtx, routerCleanup);
183
151
  });
152
+ const response = await runWithRouterCleanupOnError(routerCleanup, ()=>renderRequest(request, Root, context, options, handleRequest, !!createRequestOptions?.enableRsc));
153
+ return finishWithRouterCleanup(routerCleanup, ()=>finalizeRenderResponse(response, responseProxy, redirectCtx, routerCleanup));
184
154
  });
185
155
  };
186
156
  return requestHandler;
@@ -0,0 +1,40 @@
1
+ import "node:module";
2
+ import { getRouterServerSnapshot } from "../../router/runtime/lifecycle.mjs";
3
+ import { handleRSCRedirect } from "../../router/runtime/rsc-router.mjs";
4
+ import { SSRErrors } from "./tracer.mjs";
5
+ const isRedirectStatus = (status)=>status >= 300 && status <= 399;
6
+ const isNullBodyStatus = (status)=>204 === status || 205 === status || 304 === status;
7
+ const processRedirect = (headers, status, ctx)=>{
8
+ if (ctx.enableRsc && ctx.isRSCNavigation) return handleRSCRedirect(headers, ctx.basename, status);
9
+ return new Response(null, {
10
+ status,
11
+ headers
12
+ });
13
+ };
14
+ const applyRouterSnapshotResult = (context, onError)=>{
15
+ const routerServerSnapshot = getRouterServerSnapshot(context);
16
+ const routerStatusCode = routerServerSnapshot?.statusCode ?? context.routerContext?.statusCode;
17
+ if (routerStatusCode && 200 !== routerStatusCode) context.ssrContext?.response.status(routerStatusCode);
18
+ const errors = Object.values(routerServerSnapshot?.errors || context.routerContext?.errors || {});
19
+ if (errors.length > 0) onError(errors[0], SSRErrors.LOADER_ERROR);
20
+ };
21
+ const createLoaderRedirectResponse = (beforeRenderResult, redirectCtx)=>{
22
+ if (!beforeRenderResult || !isRedirectStatus(beforeRenderResult.status)) return;
23
+ if (beforeRenderResult.headers.has('X-Modernjs-Redirect')) return beforeRenderResult;
24
+ const redirectUrl = beforeRenderResult.headers.get('Location') || '/';
25
+ return processRedirect(new Headers({
26
+ Location: redirectUrl
27
+ }), beforeRenderResult.status, redirectCtx);
28
+ };
29
+ const finalizeRenderResponse = (response, responseProxy, redirectCtx, routerCleanup)=>{
30
+ if (-1 !== responseProxy.status && isRedirectStatus(responseProxy.status) && responseProxy.headers.Location) return processRedirect(new Headers(responseProxy.headers), responseProxy.status, redirectCtx);
31
+ Object.entries(responseProxy.headers).forEach(([key, value])=>{
32
+ response.headers.set(key, value);
33
+ });
34
+ if (-1 !== responseProxy.status) return routerCleanup.deferUntilBodyDone(new Response(isNullBodyStatus(responseProxy.status) ? null : response.body, {
35
+ status: responseProxy.status,
36
+ headers: response.headers
37
+ }));
38
+ return routerCleanup.deferUntilBodyDone(response);
39
+ };
40
+ export { applyRouterSnapshotResult, createLoaderRedirectResponse, finalizeRenderResponse };
@@ -1,10 +1,17 @@
1
1
  import "node:module";
2
2
  import { getRouterRuntimeState } from "../../router/runtime/lifecycle.mjs";
3
3
  const ROUTER_CLEANUP_ERROR = 'An error occurs during router runtime cleanup';
4
- async function withRouterCleanup(runtimeContext, onError, callback) {
5
- const routerCleanup = createRouterCleanup(runtimeContext, onError);
4
+ async function runWithRouterCleanupOnError(routerCleanup, callback) {
6
5
  try {
7
- return await callback(routerCleanup);
6
+ return await callback();
7
+ } catch (error) {
8
+ await routerCleanup.run();
9
+ throw error;
10
+ }
11
+ }
12
+ async function finishWithRouterCleanup(routerCleanup, callback) {
13
+ try {
14
+ return await callback();
8
15
  } finally{
9
16
  if (!routerCleanup.deferred) await routerCleanup.run();
10
17
  }
@@ -64,4 +71,4 @@ function createRouterCleanup(runtimeContext, onError) {
64
71
  deferUntilBodyDone
65
72
  };
66
73
  }
67
- export { ROUTER_CLEANUP_ERROR, createRouterCleanup, withRouterCleanup };
74
+ export { ROUTER_CLEANUP_ERROR, createRouterCleanup, finishWithRouterCleanup, runWithRouterCleanupOnError };
@@ -43,6 +43,10 @@ function getMatchedRouteAssets(runtimeContext, routeManifest) {
43
43
  const matchedRouteIds = getRouterMatchedRouteIds(runtimeContext) ?? [];
44
44
  return matchedRouteIds.flatMap((routeId)=>routeAssets[routeId]?.assets ?? []);
45
45
  }
46
+ function getMatchedRouteChunks(runtimeContext, routeManifest, routeAssetToChunk) {
47
+ if (!routeManifest) return [];
48
+ return getMatchedRouteAssets(runtimeContext, routeManifest).map(routeAssetToChunk);
49
+ }
46
50
  const orderHydrationScriptChunks = ({ asyncEntryChunks, collectedChunks, matchedRouteChunks, entryName })=>{
47
51
  const asyncEntryScriptChunks = [];
48
52
  const asyncEntryDependencyChunks = [];
@@ -73,13 +77,12 @@ function createRouteHydrationScriptTags(runtimeContext, entryName, options = {})
73
77
  const { nonce, template } = options;
74
78
  const routeAssets = getRouteAssets(runtimeContext);
75
79
  if (void 0 === routeAssets) return '';
76
- const matchedRouteIds = getRouterMatchedRouteIds(runtimeContext) ?? [];
77
- const assetEntries = [
78
- ...matchedRouteIds.map((routeId)=>routeAssets[routeId]),
79
- routeAssets[`async-${entryName}`]
80
- ].filter((entry)=>void 0 !== entry);
81
- const jsAssets = Array.from(new Set(assetEntries.flatMap((entry)=>(entry.assets ?? []).filter((asset)=>asset.endsWith('.js')))));
80
+ const existingScriptSrcs = void 0 === template ? new Set() : new Set(getScriptTags(template).map(({ src })=>src));
81
+ const jsAssets = Array.from(new Set([
82
+ ...getMatchedRouteAssets(runtimeContext),
83
+ ...routeAssets[`async-${entryName}`]?.assets ?? []
84
+ ].filter((asset)=>asset.endsWith('.js'))));
82
85
  const nonceAttr = void 0 === nonce || '' === nonce ? '' : ` nonce="${nonce}"`;
83
- return jsAssets.filter((asset)=>template?.includes(asset) !== true).map((asset)=>`<script src=${asset}${nonceAttr}></script>`).join(' ');
86
+ return jsAssets.filter((asset)=>!existingScriptSrcs.has(asset)).map((asset)=>`<script src=${asset}${nonceAttr}></script>`).join(' ');
84
87
  }
85
- export { createRouteHydrationScriptTags, getMatchedRouteAssets, injectBeforeHydrationEntryScript, orderHydrationScriptChunks, replaceChunkJsPlaceholder };
88
+ export { createRouteHydrationScriptTags, getMatchedRouteChunks, injectBeforeHydrationEntryScript, orderHydrationScriptChunks, replaceChunkJsPlaceholder };
@@ -5,19 +5,20 @@ import { SSR_DATA_JSON_ID } from "../../constants.mjs";
5
5
  import { SSR_DATA_PLACEHOLDER } from "../constants.mjs";
6
6
  import { createRouteHydrationScriptTags, replaceChunkJsPlaceholder } from "../scriptOrder.mjs";
7
7
  import { buildHtml } from "../shared.mjs";
8
- import { attributesToString, safeReplace } from "../utils.mjs";
8
+ import { attributesToString } from "../utils.mjs";
9
9
  function buildShellAfterTemplate(afterAppTemplate, options) {
10
10
  const { request, config, ssrConfig, runtimeContext, renderLevel, entryName } = options;
11
11
  const callbacks = [
12
+ (template)=>injectJs(template, entryName, config.nonce),
12
13
  createReplaceSSRData({
13
14
  request,
14
15
  ssrConfig,
15
16
  nonce: config.nonce,
16
17
  useJsonScript: config.useJsonScript,
17
18
  runtimeContext,
18
- renderLevel
19
- }),
20
- (template)=>injectJs(template, entryName, config.nonce)
19
+ renderLevel,
20
+ entryName
21
+ })
21
22
  ];
22
23
  async function injectJs(template, entryName, nonce) {
23
24
  const jsChunkStr = createRouteHydrationScriptTags(runtimeContext, entryName, {
@@ -30,7 +31,7 @@ function buildShellAfterTemplate(afterAppTemplate, options) {
30
31
  return buildHtml(afterAppTemplate, callbacks);
31
32
  }
32
33
  function createReplaceSSRData(options) {
33
- const { runtimeContext, nonce, renderLevel, useJsonScript, ssrConfig } = options;
34
+ const { runtimeContext, nonce, renderLevel, useJsonScript, ssrConfig, entryName } = options;
34
35
  const { request, reporter } = runtimeContext.ssrContext;
35
36
  const headers = 'object' == typeof ssrConfig && ssrConfig.unsafeHeaders ? Object.fromEntries(Object.entries(request.headers).filter(([key, _])=>ssrConfig.unsafeHeaders?.map((header)=>header.toLowerCase())?.includes(key.toLowerCase()))) : void 0;
36
37
  const ssrData = {
@@ -61,6 +62,9 @@ function createReplaceSSRData(options) {
61
62
  const ssrDataScript = useJsonScript ? `<script type="application/json" id="${SSR_DATA_JSON_ID}">${serializeSSRData}</script>` : `<script${attrsStr}>window._SSR_DATA = ${serializeSSRData}</script>`;
62
63
  const hydrationScripts = getRouterHydrationScripts(runtimeContext);
63
64
  const ssrScripts = hydrationScripts.length ? `${ssrDataScript}\n${hydrationScripts.join('\n')}` : ssrDataScript;
64
- return (template)=>safeReplace(template, SSR_DATA_PLACEHOLDER, ssrScripts);
65
+ return (template)=>{
66
+ if (!template.includes(SSR_DATA_PLACEHOLDER)) return template;
67
+ return replaceChunkJsPlaceholder(template, ssrScripts, entryName, SSR_DATA_PLACEHOLDER);
68
+ };
65
69
  }
66
70
  export { buildShellAfterTemplate };
@@ -3,12 +3,12 @@ import { buildShellAfterTemplate } from "./afterTemplate.mjs";
3
3
  import { buildShellBeforeTemplate } from "./beforeTemplate.mjs";
4
4
  const HTML_SEPARATOR = '<!--<?- html ?>-->';
5
5
  const getTemplates = async (htmlTemplate, options)=>{
6
- const [beforeAppTemplate = '', afterAppHtmlTemplate = ''] = htmlTemplate.split(HTML_SEPARATOR) || [];
6
+ const builtTemplate = await buildShellAfterTemplate(htmlTemplate, options);
7
+ const [beforeAppTemplate = '', afterAppHtmlTemplate = ''] = builtTemplate.split(HTML_SEPARATOR) || [];
7
8
  const builtBeforeTemplate = await buildShellBeforeTemplate(beforeAppTemplate, options);
8
- const builtAfterTemplate = await buildShellAfterTemplate(afterAppHtmlTemplate, options);
9
9
  return {
10
10
  shellBefore: builtBeforeTemplate,
11
- shellAfter: builtAfterTemplate
11
+ shellAfter: afterAppHtmlTemplate
12
12
  };
13
13
  };
14
14
  export { getTemplates };
@@ -86,7 +86,7 @@ async function generateHtml(App, htmlTemplate, chunkSet, collectors, htmlModifie
86
86
  createReplaceHtml(html),
87
87
  createReplaceChunkJs(jsChunk, entryName),
88
88
  createReplaceChunkCss(cssChunk),
89
- createReplaceSSRDataScript(ssrScripts),
89
+ createReplaceSSRDataScript(ssrScripts, entryName),
90
90
  createReplaceHelemt(helmetData),
91
91
  ...htmlModifiers
92
92
  ]);
@@ -95,8 +95,8 @@ async function generateHtml(App, htmlTemplate, chunkSet, collectors, htmlModifie
95
95
  function createReplaceHtml(html) {
96
96
  return (template)=>safeReplace(template, HTML_PLACEHOLDER, html);
97
97
  }
98
- function createReplaceSSRDataScript(data) {
99
- return (template)=>safeReplace(template, SSR_DATA_PLACEHOLDER, data);
98
+ function createReplaceSSRDataScript(data, entryName) {
99
+ return (template)=>replaceChunkJsPlaceholder(template, data, entryName, SSR_DATA_PLACEHOLDER);
100
100
  }
101
101
  function createReplaceChunkJs(js, entryName) {
102
102
  return (template)=>replaceChunkJsPlaceholder(template, js, entryName);
@@ -1,7 +1,7 @@
1
1
  import "node:module";
2
2
  import { ChunkExtractor } from "@loadable/server";
3
3
  import { createFederatedCssLinks } from "../federatedCss.mjs";
4
- import { getMatchedRouteAssets, orderHydrationScriptChunks } from "../scriptOrder.mjs";
4
+ import { getMatchedRouteChunks, orderHydrationScriptChunks } from "../scriptOrder.mjs";
5
5
  import { attributesToString, checkIsNode, hasStylesheetLink } from "../utils.mjs";
6
6
  import { fileURLToPath as __rspack_fileURLToPath } from "node:url";
7
7
  import { dirname as __rspack_dirname } from "node:path";
@@ -32,11 +32,6 @@ const readAsset = async (chunk)=>{
32
32
  return fs.readFile(filepath, 'utf-8');
33
33
  };
34
34
  class LoadableCollector {
35
- getMatchedRouteChunks() {
36
- const { routeManifest, runtimeContext } = this.options;
37
- if (!routeManifest) return [];
38
- return getMatchedRouteAssets(runtimeContext, routeManifest).map(routeAssetToChunk);
39
- }
40
35
  collect(comopnent) {
41
36
  const { stats, entryName } = this.options;
42
37
  if (!stats) return comopnent;
@@ -58,7 +53,7 @@ class LoadableCollector {
58
53
  ]));
59
54
  } catch (e) {}
60
55
  const collectedChunks = extractor ? extractor.getChunkAssets(extractor.chunks) : [];
61
- const matchedRouteChunks = this.getMatchedRouteChunks();
56
+ const matchedRouteChunks = getMatchedRouteChunks(options.runtimeContext, options.routeManifest, routeAssetToChunk);
62
57
  const orderedScriptChunks = orderHydrationScriptChunks({
63
58
  asyncEntryChunks: asyncChunks,
64
59
  collectedChunks,
@@ -136,4 +131,4 @@ class LoadableCollector {
136
131
  this.options = options;
137
132
  }
138
133
  }
139
- export { LoadableCollector, orderHydrationScriptChunks };
134
+ export { LoadableCollector };
@@ -349,4 +349,4 @@ const documentPlugin = ()=>({
349
349
  });
350
350
  const cli = documentPlugin;
351
351
  export default cli;
352
- export { documentPlugin, getDocumentByEntryName };
352
+ export { documentPlugin, getDocumentByEntryName, processScriptPlaceholders };
@@ -1,5 +1,5 @@
1
1
  import "node:module";
2
- import * as __rspack_external__loadable_component_0aaae075 from "@loadable/component";
2
+ import * as __rspack_external__loadable_component_ee3b4254 from "@loadable/component";
3
3
  export * from "@loadable/component";
4
4
  function asLoadableNamespace(value) {
5
5
  return 'object' == typeof value && null !== value ? value : {};
@@ -16,8 +16,8 @@ function resolveLoadable(module) {
16
16
  if ('function' != typeof loadable) throw new TypeError('Modern.js runtime loadable export must resolve to a function');
17
17
  return loadable;
18
18
  }
19
- const loadable_loadable = resolveLoadable(__rspack_external__loadable_component_0aaae075);
20
- const loadableNamespace = asLoadableNamespace(__rspack_external__loadable_component_0aaae075);
19
+ const loadable_loadable = resolveLoadable(__rspack_external__loadable_component_ee3b4254);
20
+ const loadableNamespace = asLoadableNamespace(__rspack_external__loadable_component_ee3b4254);
21
21
  const loadableDefaultNamespace = asLoadableNamespace(loadableNamespace.default);
22
22
  const callableLoadableNamespace = asLoadableNamespace(loadable_loadable);
23
23
  const lazy = loadableNamespace.lazy ?? loadableDefaultNamespace.lazy ?? callableLoadableNamespace.lazy;
@@ -1,6 +1,7 @@
1
1
  import "node:module";
2
2
  export { isBrowser } from "./common.mjs";
3
- export { RuntimeContext, defineRuntimeConfig, useRuntimeContext } from "./core/index.mjs";
3
+ export { defineRuntimeConfig } from "./core/config.mjs";
4
4
  export { getMonitors } from "./core/context/monitors/index.mjs";
5
+ export { RuntimeContext, useRuntimeContext } from "./core/context/public.mjs";
5
6
  export { getRequest } from "./core/context/request/index.mjs";
6
7
  export { redirect, setHeaders, setStatus } from "./core/context/response/index.mjs";