@bleedingdev/modern-js-runtime 3.5.0-ultramodern.5 → 3.5.0-ultramodern.75

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 (145) hide show
  1. package/dist/cjs/boundary-debugger/index.js +13 -3
  2. package/dist/cjs/cli/registry.js +18 -0
  3. package/dist/cjs/cli/ssr/index.js +3 -2
  4. package/dist/cjs/cli/ssr/loadable-bundler-plugin.js +8 -4
  5. package/dist/cjs/core/browser/hydrate.js +16 -2
  6. package/dist/cjs/core/browser/index.js +15 -3
  7. package/dist/cjs/core/context/index.js +3 -0
  8. package/dist/cjs/core/context/public.js +49 -0
  9. package/dist/cjs/core/context/runtime.js +6 -8
  10. package/dist/cjs/core/react/wrapper.js +57 -0
  11. package/dist/cjs/core/server/federatedCss.js +7 -3
  12. package/dist/cjs/core/server/requestHandler.js +15 -45
  13. package/dist/cjs/core/server/requestResponse.js +83 -0
  14. package/dist/cjs/core/server/routerCleanup.js +16 -6
  15. package/dist/cjs/core/server/scriptOrder.js +13 -10
  16. package/dist/cjs/core/server/stream/afterTemplate.js +9 -5
  17. package/dist/cjs/core/server/stream/template.js +3 -3
  18. package/dist/cjs/core/server/string/loadable.js +3 -11
  19. package/dist/cjs/index.js +7 -6
  20. package/dist/cjs/module-federation/consume-surface.js +199 -0
  21. package/dist/cjs/module-federation/distributed-ssr.js +134 -0
  22. package/dist/cjs/module-federation/index.js +258 -120
  23. package/dist/cjs/module-federation/last-known-good.js +124 -0
  24. package/dist/cjs/module-federation/manifest-recovery-runtime-plugin.js +140 -0
  25. package/dist/cjs/module-federation/surface-resolution-types.js +61 -0
  26. package/dist/cjs/router/cli/code/nestedRoutes.js +3 -0
  27. package/dist/cjs/router/cli/code/templates.js +3 -2
  28. package/dist/cjs/router/cli/constants.js +1 -0
  29. package/dist/cjs/router/cli/nestedRoutesSpec.js +3 -1
  30. package/dist/cjs/router/runtime/hooks.js +7 -6
  31. package/dist/cjs/router/runtime/internal.js +30 -16
  32. package/dist/cjs/router/runtime/plugin.js +6 -7
  33. package/dist/cjs/router/runtime/provider.js +58 -12
  34. package/dist/esm/boundary-debugger/index.mjs +13 -3
  35. package/dist/esm/cli/code.mjs +12 -12
  36. package/dist/esm/cli/registry.mjs +0 -0
  37. package/dist/esm/cli/ssr/index.mjs +3 -2
  38. package/dist/esm/cli/ssr/loadable-bundler-plugin.mjs +8 -4
  39. package/dist/esm/core/browser/hydrate.mjs +15 -4
  40. package/dist/esm/core/browser/index.mjs +11 -5
  41. package/dist/esm/core/context/index.mjs +1 -1
  42. package/dist/esm/core/context/public.mjs +5 -0
  43. package/dist/esm/core/context/runtime.mjs +4 -6
  44. package/dist/esm/core/react/wrapper.mjs +58 -1
  45. package/dist/esm/core/server/federatedCss.mjs +7 -3
  46. package/dist/esm/core/server/requestHandler.mjs +15 -45
  47. package/dist/esm/core/server/requestResponse.mjs +39 -0
  48. package/dist/esm/core/server/routerCleanup.mjs +11 -4
  49. package/dist/esm/core/server/scriptOrder.mjs +11 -8
  50. package/dist/esm/core/server/stream/afterTemplate.mjs +10 -6
  51. package/dist/esm/core/server/stream/template.mjs +3 -3
  52. package/dist/esm/core/server/string/loadable.mjs +3 -8
  53. package/dist/esm/exports/loadable.mjs +3 -3
  54. package/dist/esm/index.mjs +2 -1
  55. package/dist/esm/module-federation/consume-surface.mjs +158 -0
  56. package/dist/esm/module-federation/distributed-ssr.mjs +81 -0
  57. package/dist/esm/module-federation/index.mjs +6 -0
  58. package/dist/esm/module-federation/last-known-good.mjs +80 -0
  59. package/dist/esm/module-federation/manifest-recovery-runtime-plugin.mjs +100 -0
  60. package/dist/esm/module-federation/surface-resolution-types.mjs +8 -0
  61. package/dist/esm/router/cli/code/index.mjs +5 -5
  62. package/dist/esm/router/cli/code/nestedRoutes.mjs +3 -0
  63. package/dist/esm/router/cli/code/templates.mjs +3 -2
  64. package/dist/esm/router/cli/constants.mjs +1 -0
  65. package/dist/esm/router/cli/handler.mjs +3 -3
  66. package/dist/esm/router/cli/nestedRoutesSpec.mjs +3 -1
  67. package/dist/esm/router/runtime/hooks.mjs +7 -6
  68. package/dist/esm/router/runtime/internal.mjs +26 -18
  69. package/dist/esm/router/runtime/plugin.mjs +6 -7
  70. package/dist/esm/router/runtime/provider.mjs +56 -13
  71. package/dist/esm-node/boundary-debugger/index.mjs +13 -3
  72. package/dist/esm-node/cli/code.mjs +12 -12
  73. package/dist/esm-node/cli/registry.mjs +1 -0
  74. package/dist/esm-node/cli/ssr/index.mjs +3 -2
  75. package/dist/esm-node/cli/ssr/loadable-bundler-plugin.mjs +8 -4
  76. package/dist/esm-node/core/browser/hydrate.mjs +15 -4
  77. package/dist/esm-node/core/browser/index.mjs +11 -5
  78. package/dist/esm-node/core/context/index.mjs +1 -1
  79. package/dist/esm-node/core/context/public.mjs +6 -0
  80. package/dist/esm-node/core/context/runtime.mjs +4 -6
  81. package/dist/esm-node/core/react/wrapper.mjs +58 -1
  82. package/dist/esm-node/core/server/federatedCss.mjs +7 -3
  83. package/dist/esm-node/core/server/requestHandler.mjs +15 -45
  84. package/dist/esm-node/core/server/requestResponse.mjs +40 -0
  85. package/dist/esm-node/core/server/routerCleanup.mjs +11 -4
  86. package/dist/esm-node/core/server/scriptOrder.mjs +11 -8
  87. package/dist/esm-node/core/server/stream/afterTemplate.mjs +10 -6
  88. package/dist/esm-node/core/server/stream/template.mjs +3 -3
  89. package/dist/esm-node/core/server/string/loadable.mjs +3 -8
  90. package/dist/esm-node/exports/loadable.mjs +3 -3
  91. package/dist/esm-node/index.mjs +2 -1
  92. package/dist/esm-node/module-federation/consume-surface.mjs +159 -0
  93. package/dist/esm-node/module-federation/distributed-ssr.mjs +82 -0
  94. package/dist/esm-node/module-federation/index.mjs +6 -0
  95. package/dist/esm-node/module-federation/last-known-good.mjs +81 -0
  96. package/dist/esm-node/module-federation/manifest-recovery-runtime-plugin.mjs +101 -0
  97. package/dist/esm-node/module-federation/surface-resolution-types.mjs +9 -0
  98. package/dist/esm-node/router/cli/code/index.mjs +5 -5
  99. package/dist/esm-node/router/cli/code/nestedRoutes.mjs +3 -0
  100. package/dist/esm-node/router/cli/code/templates.mjs +3 -2
  101. package/dist/esm-node/router/cli/constants.mjs +1 -0
  102. package/dist/esm-node/router/cli/handler.mjs +3 -3
  103. package/dist/esm-node/router/cli/nestedRoutesSpec.mjs +3 -1
  104. package/dist/esm-node/router/runtime/hooks.mjs +7 -6
  105. package/dist/esm-node/router/runtime/internal.mjs +26 -18
  106. package/dist/esm-node/router/runtime/plugin.mjs +6 -7
  107. package/dist/esm-node/router/runtime/provider.mjs +56 -13
  108. package/dist/types/boundary-debugger/index.d.ts +1 -1
  109. package/dist/types/cli/registry.d.ts +2 -0
  110. package/dist/types/common.d.ts +8 -1
  111. package/dist/types/core/browser/hydrate.d.ts +2 -1
  112. package/dist/types/core/browser/index.d.ts +4 -0
  113. package/dist/types/core/context/index.d.ts +26 -10
  114. package/dist/types/core/context/monitors/default.d.ts +10 -2
  115. package/dist/types/core/context/monitors/index.d.ts +1 -1
  116. package/dist/types/core/context/monitors/index.server.d.ts +2 -2
  117. package/dist/types/core/context/public.d.ts +27 -0
  118. package/dist/types/core/context/runtime.d.ts +12 -22
  119. package/dist/types/core/react/index.d.ts +1 -1
  120. package/dist/types/core/server/requestResponse.d.ts +15 -0
  121. package/dist/types/core/server/routerCleanup.d.ts +2 -1
  122. package/dist/types/core/server/scriptOrder.d.ts +1 -1
  123. package/dist/types/core/server/stream/shared.d.ts +2 -2
  124. package/dist/types/core/server/string/loadable.d.ts +0 -2
  125. package/dist/types/exports/head.d.ts +1 -1
  126. package/dist/types/index.d.ts +5 -5
  127. package/dist/types/internal.d.ts +0 -1
  128. package/dist/types/module-federation/consume-surface.d.ts +104 -0
  129. package/dist/types/module-federation/distributed-ssr.d.ts +61 -0
  130. package/dist/types/module-federation/index.d.ts +6 -0
  131. package/dist/types/module-federation/last-known-good.d.ts +72 -0
  132. package/dist/types/module-federation/manifest-recovery-runtime-plugin.d.ts +25 -0
  133. package/dist/types/module-federation/surface-resolution-types.d.ts +23 -0
  134. package/dist/types/router/cli/constants.d.ts +1 -0
  135. package/dist/types/router/runtime/hooks.d.ts +10 -6
  136. package/dist/types/router/runtime/internal.d.ts +13 -3
  137. package/dist/types/router/runtime/plugin.d.ts +1 -1
  138. package/dist/types/router/runtime/plugin.node.d.ts +1 -1
  139. package/dist/types/router/runtime/provider.d.ts +28 -11
  140. package/dist/types/router/runtime/types.d.ts +27 -5
  141. package/package.json +46 -27
  142. package/dist/cjs/exports/tanstack-router.js +0 -83
  143. package/dist/esm/exports/tanstack-router.mjs +0 -30
  144. package/dist/esm-node/exports/tanstack-router.mjs +0 -31
  145. package/dist/types/exports/tanstack-router.d.ts +0 -88
@@ -2,8 +2,8 @@ import { formatImportPath, fs } from "@modern-js/utils";
2
2
  import path from "path";
3
3
  import { ENTRY_BOOTSTRAP_FILE_NAME, ENTRY_POINT_FILE_NAME, ENTRY_POINT_REGISTER_FILE_NAME, ENTRY_POINT_RUNTIME_GLOBAL_CONTEXT_FILE_NAME, ENTRY_POINT_RUNTIME_REGISTER_FILE_NAME, ENTRY_SERVER_BOOTSTRAP_FILE_NAME, INDEX_FILE_NAME, SERVER_ENTRY_POINT_FILE_NAME } from "./constants.mjs";
4
4
  import { resolveSSRMode } from "./ssr/mode.mjs";
5
- import * as __rspack_external__template_mjs_d6ab8956 from "./template.mjs";
6
- import * as __rspack_external__template_server_mjs_38d6edb1 from "./template.server.mjs";
5
+ import * as __rspack_external__template_mjs_d1604447 from "./template.mjs";
6
+ import * as __rspack_external__template_server_mjs_f98cfe58 from "./template.server.mjs";
7
7
  const normalizePreEntry = (preEntry)=>{
8
8
  if (!preEntry) return [];
9
9
  if (Array.isArray(preEntry)) return preEntry.filter((v)=>'string' == typeof v && v.length > 0);
@@ -35,7 +35,7 @@ const generateCode = async (entrypoints, appContext, config, hooks)=>{
35
35
  nestedRoutesEntry
36
36
  });
37
37
  let indexCode = '';
38
- indexCode = ssrMode || !config.server.rsc || customEntry ? __rspack_external__template_mjs_d6ab8956.index({
38
+ indexCode = ssrMode || !config.server.rsc || customEntry ? __rspack_external__template_mjs_d1604447.index({
39
39
  srcDirectory,
40
40
  internalSrcAlias,
41
41
  metaName,
@@ -45,7 +45,7 @@ const generateCode = async (entrypoints, appContext, config, hooks)=>{
45
45
  mountId,
46
46
  enableRsc: config.server.rsc,
47
47
  isNestedRouter: !!entrypoint.nestedRoutesEntry
48
- }) : __rspack_external__template_mjs_d6ab8956.entryForCSRWithRSC({
48
+ }) : __rspack_external__template_mjs_d1604447.entryForCSRWithRSC({
49
49
  metaName,
50
50
  entryName,
51
51
  mountId,
@@ -76,7 +76,7 @@ const generateCode = async (entrypoints, appContext, config, hooks)=>{
76
76
  if (ssrMode) await fs.outputFile(bootstrapServerFile, `export const requestHandler = import('./${SERVER_ENTRY_POINT_FILE_NAME}').then((m) => m.requestHandler)`, 'utf8');
77
77
  }
78
78
  if (ssrMode) {
79
- const indexServerCode = __rspack_external__template_server_mjs_38d6edb1.serverIndex({
79
+ const indexServerCode = __rspack_external__template_server_mjs_f98cfe58.serverIndex({
80
80
  entry,
81
81
  entryName,
82
82
  internalSrcAlias,
@@ -90,16 +90,16 @@ const generateCode = async (entrypoints, appContext, config, hooks)=>{
90
90
  await fs.outputFile(indexServerFile, indexServerCode, 'utf8');
91
91
  } else if (config.server.rsc) {
92
92
  const indexServerFile = path.resolve(internalDirectory, `./${entryName}/${SERVER_ENTRY_POINT_FILE_NAME}`);
93
- const indexServerCode = __rspack_external__template_server_mjs_38d6edb1.entryForCSRWithRSC({
93
+ const indexServerCode = __rspack_external__template_server_mjs_f98cfe58.entryForCSRWithRSC({
94
94
  entryName,
95
95
  metaName
96
96
  });
97
97
  await fs.outputFile(indexServerFile, indexServerCode, 'utf8');
98
98
  }
99
- const registerCode = __rspack_external__template_mjs_d6ab8956.register();
99
+ const registerCode = __rspack_external__template_mjs_d1604447.register();
100
100
  const registerFile = path.resolve(internalDirectory, `./${entryName}/${ENTRY_POINT_REGISTER_FILE_NAME}`);
101
101
  await fs.outputFile(registerFile, registerCode, 'utf8');
102
- const registerRuntimeCode = __rspack_external__template_mjs_d6ab8956.runtimeRegister({
102
+ const registerRuntimeCode = __rspack_external__template_mjs_d1604447.runtimeRegister({
103
103
  entryName,
104
104
  srcDirectory,
105
105
  internalSrcAlias,
@@ -113,7 +113,7 @@ const generateCode = async (entrypoints, appContext, config, hooks)=>{
113
113
  if (!config.server.rsc || entrypoint.nestedRoutesEntry) {
114
114
  const route = serverRoutes.find((r)=>r.entryName === entryName);
115
115
  const basename = route?.urlPath || '/';
116
- contextCode = __rspack_external__template_mjs_d6ab8956.runtimeGlobalContext({
116
+ contextCode = __rspack_external__template_mjs_d1604447.runtimeGlobalContext({
117
117
  entryName,
118
118
  srcDirectory,
119
119
  internalSrcAlias,
@@ -124,18 +124,18 @@ const generateCode = async (entrypoints, appContext, config, hooks)=>{
124
124
  });
125
125
  } else {
126
126
  const AppProxyPath = path.join(internalDirectory, entryName, './AppProxy.jsx');
127
- const appProxyCode = __rspack_external__template_mjs_d6ab8956.AppProxyForRSC({
127
+ const appProxyCode = __rspack_external__template_mjs_d1604447.AppProxyForRSC({
128
128
  srcDirectory,
129
129
  internalSrcAlias,
130
130
  entry,
131
131
  customEntry
132
132
  });
133
133
  await fs.outputFile(AppProxyPath, appProxyCode);
134
- contextCode = __rspack_external__template_mjs_d6ab8956.runtimeGlobalContextForRSCClient({
134
+ contextCode = __rspack_external__template_mjs_d1604447.runtimeGlobalContextForRSCClient({
135
135
  metaName,
136
136
  customEntry
137
137
  });
138
- const contextServerCode = __rspack_external__template_mjs_d6ab8956.runtimeGlobalContextForRSCServer({
138
+ const contextServerCode = __rspack_external__template_mjs_d1604447.runtimeGlobalContextForRSCServer({
139
139
  metaName
140
140
  });
141
141
  const contextFile = path.resolve(internalDirectory, `./${entryName}/${ENTRY_POINT_RUNTIME_GLOBAL_CONTEXT_FILE_NAME}.server.js`);
File without changes
@@ -84,14 +84,13 @@ const ssrBuilderPlugin = (modernAPI, outputModule, exportLoadablePath)=>({
84
84
  const hasServerRendering = hasServerRenderingConfig(userConfig);
85
85
  const hasModuleFederationRuntimeMarker = hasServerRendering && shouldUseModuleFederationNodeOutput(config);
86
86
  const hasExplicitMfSsrFlag = isModuleFederationAppSSREnabled(userConfig);
87
- const isCloudflareWorkerSSR = 'workerSSR' === name && userConfig.deploy?.target === 'cloudflare';
88
87
  const requireExplicitMfSsrFlag = 'true' === process.env.MODERN_MF_APP_SSR_REQUIRE_EXPLICIT;
89
88
  if (hasServerRendering && hasModuleFederationRuntimeMarker && !hasExplicitMfSsrFlag) {
90
89
  const warningMessage = '[modernjs][mf-ssr] Module Federation SSR was auto-detected from runtime markers. Set server.ssr.moduleFederationAppSSR=true explicitly in host and remotes to avoid heuristic drift.';
91
90
  if (requireExplicitMfSsrFlag) throw new Error(`${warningMessage} (enforced by MODERN_MF_APP_SSR_REQUIRE_EXPLICIT=true)`);
92
91
  console.warn(warningMessage);
93
92
  }
94
- const isModuleFederationAppSSR = hasServerRendering && hasExplicitMfSsrFlag && !isCloudflareWorkerSSR;
93
+ const isModuleFederationAppSSR = hasServerRendering && hasExplicitMfSsrFlag;
95
94
  const ssrEnv = userConfig.deploy?.worker?.ssr || userConfig.server?.rsc ? 'edge' : 'node';
96
95
  const appContext = modernAPI.getAppContext();
97
96
  const { appDirectory, entrypoints } = appContext;
@@ -105,6 +104,8 @@ const ssrBuilderPlugin = (modernAPI, outputModule, exportLoadablePath)=>({
105
104
  define: {
106
105
  'process.env.MODERN_TARGET': isServerEnvironment ? JSON.stringify('node') : JSON.stringify('browser'),
107
106
  'process.env.MODERN_SSR_ENV': JSON.stringify(ssrEnv),
107
+ 'process.env.MODERN_ENABLE_HYDRATION': JSON.stringify(isUseSSRBundle(userConfig)),
108
+ 'process.env.MODERN_ENABLE_RSC': JSON.stringify(Boolean(userConfig.server?.rsc)),
108
109
  'process.env.MODERN_MF_APP_SSR': JSON.stringify(isModuleFederationAppSSR)
109
110
  }
110
111
  },
@@ -1,6 +1,7 @@
1
1
  import { fs } from "@modern-js/utils";
2
2
  import path_0 from "path";
3
3
  const normalizeChunkId = (id)=>'string' == typeof id && /^\d+$/.test(id) ? Number(id) : id;
4
+ const DEFAULT_CHUNK_LOADING_GLOBAL = '__LOADABLE_LOADED_CHUNKS__';
4
5
  const normalizeChunkGroup = (group)=>({
5
6
  ...group,
6
7
  chunks: (group.chunks || []).map(normalizeChunkId)
@@ -8,7 +9,11 @@ const normalizeChunkGroup = (group)=>({
8
9
  class LoadablePlugin {
9
10
  apply(compiler) {
10
11
  this.compiler = compiler;
11
- compiler.options.output.chunkLoadingGlobal = this.opts.chunkLoadingGlobal;
12
+ const chunkLoadingGlobal = this.opts.chunkLoadingGlobal ?? compiler.options.output.chunkLoadingGlobal ?? DEFAULT_CHUNK_LOADING_GLOBAL;
13
+ compiler.options.output.chunkLoadingGlobal = chunkLoadingGlobal;
14
+ new compiler.webpack.DefinePlugin({
15
+ 'process.env.MODERN_CHUNK_LOADING_GLOBAL': JSON.stringify(chunkLoadingGlobal)
16
+ }).apply(compiler);
12
17
  if (this.opts.outputAsset || this.opts.writeToDisk) compiler.hooks.make.tap(LoadablePlugin.name, (compilation)=>{
13
18
  compilation.hooks.processAssets.tap({
14
19
  name: LoadablePlugin.name,
@@ -68,10 +73,9 @@ class LoadablePlugin {
68
73
  const outputFile = path_0.resolve(outputFolder || '', this.opts.filename);
69
74
  fs.outputFileSync(outputFile, manifest);
70
75
  }
71
- constructor({ filename = 'loadable-stats.json', path, writeToDisk, outputAsset = true, chunkLoadingGlobal = '__LOADABLE_LOADED_CHUNKS__' } = {
76
+ constructor({ filename = 'loadable-stats.json', path, writeToDisk, outputAsset = true, chunkLoadingGlobal } = {
72
77
  filename: 'loadable-stats.json',
73
- outputAsset: true,
74
- chunkLoadingGlobal: '__LOADABLE_LOADED_CHUNKS__'
78
+ outputAsset: true
75
79
  }){
76
80
  this.opts = {
77
81
  filename,
@@ -1,10 +1,21 @@
1
1
  import { jsx } from "react/jsx-runtime";
2
2
  import { loadableReady } from "@loadable/component";
3
+ import { SSR_HYDRATION_ID_PREFIX } from "@modern-js/utils/universal/constants";
4
+ import { hydrateRoot } from "react-dom/client";
3
5
  import { RenderLevel } from "../constants.mjs";
4
6
  import { wrapRuntimeContextProvider } from "../react/wrapper.mjs";
5
7
  import { WithCallback } from "./withCallback.mjs";
6
8
  const isReact18 = ()=>'true' === process.env.IS_REACT18;
7
- function hydrateRoot(App, context, ModernRender, ModernHydrate) {
9
+ const runtimeProcess = Reflect.get(globalThis, 'process');
10
+ const loadableReadyOptions = {
11
+ chunkLoadingGlobal: runtimeProcess?.env?.MODERN_CHUNK_LOADING_GLOBAL || '__LOADABLE_LOADED_CHUNKS__'
12
+ };
13
+ async function hydrateWithReact(App, rootElement) {
14
+ return hydrateRoot(rootElement, App, {
15
+ identifierPrefix: SSR_HYDRATION_ID_PREFIX
16
+ });
17
+ }
18
+ function hydrate_hydrateRoot(App, context, ModernRender, ModernHydrate) {
8
19
  const hydrateContext = {
9
20
  ...context,
10
21
  get routes () {
@@ -40,14 +51,14 @@ function hydrateRoot(App, context, ModernRender, ModernHydrate) {
40
51
  ModernHydrate(wrapRuntimeContextProvider(/*#__PURE__*/ jsx(SSRApp, {}), hydrateContext)).then((root)=>{
41
52
  resolve(root);
42
53
  });
43
- }) : loadableReady(()=>{
54
+ }, loadableReadyOptions) : loadableReady(()=>{
44
55
  ModernHydrate(wrapRuntimeContextProvider(App, hydrateContext), callback).then((root)=>{
45
56
  resolve(root);
46
57
  });
47
- });
58
+ }, loadableReadyOptions);
48
59
  });
49
60
  console.warn(`unknow render level: ${renderLevel}, execute render()`);
50
61
  return ModernRender(wrapRuntimeContextProvider(App, context));
51
62
  }
52
63
  }
53
- export { hydrateRoot, isReact18 };
64
+ export { hydrateWithReact, hydrate_hydrateRoot as hydrateRoot, isReact18 };
@@ -3,7 +3,7 @@ import { parseCookie } from "cookie";
3
3
  import { getGlobalInternalRuntimeContext } from "../context/index.mjs";
4
4
  import { getInitialContext } from "../context/runtime.mjs";
5
5
  import { wrapRuntimeContextProvider } from "../react/wrapper.mjs";
6
- import { hydrateRoot } from "./hydrate.mjs";
6
+ import { hydrateRoot, hydrateWithReact } from "./hydrate.mjs";
7
7
  const IS_REACT18 = 'true' === process.env.IS_REACT18;
8
8
  const getQuery = ()=>window.location.search.substring(1).split('&').reduce((res, item)=>{
9
9
  const [key, value] = item.split('=');
@@ -47,10 +47,9 @@ function getSSRData() {
47
47
  function isClientArgs(id) {
48
48
  return void 0 === id || 'string' == typeof id || "u" > typeof HTMLElement && id instanceof HTMLElement;
49
49
  }
50
- async function render(App, id) {
50
+ async function renderApp(App, id, hydrateFromSsrData, internalRuntimeContext) {
51
51
  const context = getInitialContext();
52
52
  const runBeforeRender = async (context)=>{
53
- const internalRuntimeContext = getGlobalInternalRuntimeContext();
54
53
  const api = internalRuntimeContext.pluginAPI;
55
54
  api.updateRuntimeContext(context);
56
55
  const hooks = internalRuntimeContext.hooks;
@@ -73,11 +72,18 @@ async function render(App, id) {
73
72
  const hydrateFunc = IS_REACT18 ? hydrateWithReact18 : hydrateWithReact17;
74
73
  return hydrateFunc(App, rootElement, callback);
75
74
  }
76
- if (window._SSR_DATA) return hydrateRoot(App, context, ModernRender, ModernHydrate);
75
+ if (hydrateFromSsrData && process.env.MODERN_ENABLE_HYDRATION && window._SSR_DATA) return hydrateRoot(App, context, ModernRender, ModernHydrate);
77
76
  return ModernRender(wrapRuntimeContextProvider(App, context));
78
77
  }
79
78
  throw Error('`render` function needs id in browser environment, it needs to be string or element');
80
79
  }
80
+ async function render(App, id) {
81
+ return renderApp(App, id, true, getGlobalInternalRuntimeContext());
82
+ }
83
+ function createNestedAppRenderer() {
84
+ const internalRuntimeContext = getGlobalInternalRuntimeContext();
85
+ return (App, id)=>renderApp(App, id, false, internalRuntimeContext);
86
+ }
81
87
  async function renderWithReact18(App, rootElement) {
82
88
  const ReactDOM = await import("react-dom/client");
83
89
  const root = ReactDOM.createRoot(rootElement);
@@ -101,4 +107,4 @@ async function hydrateWithReact17(App, rootElement, callback) {
101
107
  const root = ReactDOM.hydrate(App, rootElement, callback);
102
108
  return root;
103
109
  }
104
- export { hydrateWithReact17, hydrateWithReact18, render, renderWithReact17, renderWithReact18 };
110
+ export { createNestedAppRenderer, hydrateWithReact, hydrateWithReact17, hydrateWithReact18, render, renderWithReact17, renderWithReact18 };
@@ -43,7 +43,7 @@ function getGlobalBasename() {
43
43
  export { DefaultNotFound } from "../../router/runtime/DefaultNotFound.mjs";
44
44
  export { modifyRoutes, onAfterCreateRouter, onAfterHydrateRouter, onBeforeCreateRouter, onBeforeCreateRoutes, onBeforeHydrateRouter } from "../../router/runtime/hooks.mjs";
45
45
  export { applyRouterRuntimeState, applyRouterServerPrepareResult, cleanupRouterRuntimeState, createRouterRuntimeState, createRouterServerSnapshot, getRouterHydrationScripts, getRouterMatchedRouteIds, getRouterRuntimeState, getRouterServerSnapshot } from "../../router/runtime/lifecycle.mjs";
46
- export { registerRouterProvider, resolveRouterProvider, routerProviderRegistryHooks } from "../../router/runtime/provider.mjs";
46
+ export { createRouterProviderRealm, registerRouterProvider, resolveRouterProvider, routerProviderRegistryHooks } from "../../router/runtime/provider.mjs";
47
47
  export { createRuntimeContextExtension } from "./extensions.mjs";
48
48
  export { InternalRuntimeContext, RuntimeContext, getInitialContext } from "./runtime.mjs";
49
49
  export { getServerPayload, setServerPayload } from "./serverPayload/index.mjs";
@@ -0,0 +1,5 @@
1
+ import { createContext, useContext } from "react";
2
+ const RuntimeContext = createContext({});
3
+ const ReactRuntimeContext = RuntimeContext;
4
+ const useRuntimeContext = ()=>useContext(RuntimeContext);
5
+ export { ReactRuntimeContext, RuntimeContext, useRuntimeContext };
@@ -1,8 +1,6 @@
1
- import { ROUTE_MANIFEST } from "@modern-js/utils/universal/constants";
2
- import { createContext, useContext } from "react";
1
+ import { createContext } from "react";
2
+ const ROUTE_MANIFEST = '_MODERNJS_ROUTE_MANIFEST';
3
3
  const InternalRuntimeContext = createContext({});
4
- const RuntimeContext = createContext({});
5
- const ReactRuntimeContext = RuntimeContext;
6
4
  const getInitialContext = (isBrowser = true, routeManifest)=>{
7
5
  const requestContext = {
8
6
  request: {},
@@ -15,5 +13,5 @@ const getInitialContext = (isBrowser = true, routeManifest)=>{
15
13
  context: requestContext
16
14
  };
17
15
  };
18
- const useRuntimeContext = ()=>useContext(RuntimeContext);
19
- export { InternalRuntimeContext, ReactRuntimeContext, RuntimeContext, getInitialContext, useRuntimeContext };
16
+ export { ReactRuntimeContext, RuntimeContext, useRuntimeContext } from "./public.mjs";
17
+ export { InternalRuntimeContext, getInitialContext };
@@ -1,8 +1,44 @@
1
1
  import { jsx } from "react/jsx-runtime";
2
2
  import { HelmetProvider } from "react-helmet-async";
3
- import { InternalRuntimeContext, RuntimeContext } from "../context/index.mjs";
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;
13
+ return {
14
+ nonce: ssrContext.nonce,
15
+ useJsonScript: ssrContext.useJsonScript,
16
+ htmlModifiers: [],
17
+ baseUrl: ssrContext.baseUrl,
18
+ request: request ? {
19
+ url: request.url,
20
+ userAgent: request.userAgent,
21
+ cookie: request.cookie,
22
+ pathname: request.pathname,
23
+ query: toRscSafeRecord(request.query),
24
+ params: toRscSafeRecord(request.params),
25
+ headers: toRscSafeRecord(request.headers),
26
+ host: request.host,
27
+ 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 || {},
37
+ response: {
38
+ locals: ssrContext?.response?.locals || {}
39
+ }
40
+ };
41
+ }
6
42
  function wrapRuntimeContextProvider(App, contextValue) {
7
43
  const { isBrowser, initialData, routes, context, routeManifest, routerContext, unstable_getBlockNavState, ssrContext, _internalContext, _internalRouterBaseName, ...rest } = contextValue;
8
44
  const internalContextValue = contextValue;
@@ -15,6 +51,27 @@ function wrapRuntimeContextProvider(App, contextValue) {
15
51
  ...rest
16
52
  };
17
53
  stripRuntimeContextExtensions(runtimeContextValue);
54
+ if (getGlobalEnableRsc() && !isBrowser) {
55
+ const rscSafeRequestContext = createRscSafeRequestContext(ssrContext);
56
+ const rscInternalContextValue = {
57
+ ...internalContextValue,
58
+ context: rscSafeRequestContext,
59
+ requestContext: rscSafeRequestContext,
60
+ ssrContext: createRscSafeSsrContext(ssrContext)
61
+ };
62
+ const rscRuntimeContextValue = {
63
+ ...runtimeContextValue,
64
+ context: rscSafeRequestContext,
65
+ requestContext: rscSafeRequestContext
66
+ };
67
+ return /*#__PURE__*/ jsx(InternalRuntimeContext.Provider, {
68
+ value: rscInternalContextValue,
69
+ children: /*#__PURE__*/ jsx(RuntimeContext.Provider, {
70
+ value: rscRuntimeContextValue,
71
+ children: App
72
+ })
73
+ });
74
+ }
18
75
  return /*#__PURE__*/ jsx(InternalRuntimeContext.Provider, {
19
76
  value: internalContextValue,
20
77
  children: /*#__PURE__*/ jsx(RuntimeContext.Provider, {
@@ -1,12 +1,16 @@
1
1
  import { attributesToString } from "./utils.mjs";
2
+ const escapeHtmlAttribute = (value)=>value.replaceAll('&', '&amp;').replaceAll('"', '&quot;').replaceAll('<', '&lt;').replaceAll('>', '&gt;');
2
3
  const createFederatedCssLinks = (assets, options)=>{
3
4
  if (void 0 === assets || 0 === assets.length) return '';
4
5
  const seen = new Set(options.existingAssets || []);
5
6
  const attributes = attributesToString(options.attributes || {});
6
7
  const links = [];
7
- for (const asset of assets)if (!('' === asset || seen.has(asset) || options.template.includes(asset))) {
8
- seen.add(asset);
9
- links.push(`<link${attributes} href="${asset}" rel="stylesheet" />`);
8
+ for (const asset of assets){
9
+ const href = escapeHtmlAttribute(asset);
10
+ if (!('' === asset || seen.has(asset) || options.template.includes(asset) || options.template.includes(href))) {
11
+ seen.add(asset);
12
+ links.push(`<link${attributes} href="${href}" rel="stylesheet" />`);
13
+ }
10
14
  }
11
15
  return links.join('');
12
16
  };
@@ -2,15 +2,13 @@ import { jsx } from "react/jsx-runtime";
2
2
  import { storage } from "@modern-js/runtime-utils/node";
3
3
  import { getPathname, parseCookie, parseHeaders, parseQuery } from "@modern-js/runtime-utils/universal/request";
4
4
  import react, { Fragment } from "react";
5
- import { getRouterServerSnapshot } from "../../router/runtime/lifecycle.mjs";
6
- import { handleRSCRedirect } from "../../router/runtime/rsc-router.mjs";
7
5
  import { getGlobalInternalRuntimeContext, getGlobalRSCRoot } from "../context/index.mjs";
8
6
  import { getInitialContext } from "../context/runtime.mjs";
9
7
  import { getServerPayload } from "../context/serverPayload/index.mjs";
10
8
  import { createRoot } from "../react/index.mjs";
11
9
  import { CHUNK_CSS_PLACEHOLDER } from "./constants.mjs";
12
- import { withRouterCleanup } from "./routerCleanup.mjs";
13
- import { SSRErrors } from "./tracer.mjs";
10
+ import { applyRouterSnapshotResult, createLoaderRedirectResponse, finalizeRenderResponse } from "./requestResponse.mjs";
11
+ import { createRouterCleanup, finishWithRouterCleanup, runWithRouterCleanupOnError } from "./routerCleanup.mjs";
14
12
  import { getSSRConfigByEntry, getSSRMode } from "./utils.mjs";
15
13
  async function handleRSCRequest(request, Root, context, options, handleRequest) {
16
14
  const serverPayload = getServerPayload();
@@ -30,29 +28,6 @@ async function handleRSCRequest(request, Root, context, options, handleRequest)
30
28
  runtimeContext: context
31
29
  });
32
30
  }
33
- const isRedirectStatus = (status)=>status >= 300 && status <= 399;
34
- const processRedirect = (headers, status, ctx)=>{
35
- if (ctx.enableRsc && ctx.isRSCNavigation) return handleRSCRedirect(headers, ctx.basename, status);
36
- return new Response(null, {
37
- status,
38
- headers
39
- });
40
- };
41
- const applyRouterSnapshotResult = (context, onError)=>{
42
- const routerServerSnapshot = getRouterServerSnapshot(context);
43
- const routerStatusCode = routerServerSnapshot?.statusCode ?? context.routerContext?.statusCode;
44
- if (routerStatusCode && 200 !== routerStatusCode) context.ssrContext?.response.status(routerStatusCode);
45
- const errors = Object.values(routerServerSnapshot?.errors || context.routerContext?.errors || {});
46
- if (errors.length > 0) onError(errors[0], SSRErrors.LOADER_ERROR);
47
- };
48
- const createLoaderRedirectResponse = (beforeRenderResult, redirectCtx)=>{
49
- if (!beforeRenderResult || !isRedirectStatus(beforeRenderResult.status)) return;
50
- if (beforeRenderResult.headers.has('X-Modernjs-Redirect')) return beforeRenderResult;
51
- const redirectUrl = beforeRenderResult.headers.get('Location') || '/';
52
- return processRedirect(new Headers({
53
- Location: redirectUrl
54
- }), beforeRenderResult.status, redirectCtx);
55
- };
56
31
  const renderRequest = async (request, Root, context, options, handleRequest, enableRsc)=>{
57
32
  if (enableRsc) return handleRSCRequest(request, Root, context, options, handleRequest);
58
33
  return handleRequest(request, Root, {
@@ -60,17 +35,6 @@ const renderRequest = async (request, Root, context, options, handleRequest, ena
60
35
  runtimeContext: context
61
36
  });
62
37
  };
63
- const finalizeRenderResponse = (response, responseProxy, redirectCtx, routerCleanup)=>{
64
- if (-1 !== responseProxy.status && isRedirectStatus(responseProxy.status) && responseProxy.headers.Location) return processRedirect(new Headers(responseProxy.headers), responseProxy.status, redirectCtx);
65
- Object.entries(responseProxy.headers).forEach(([key, value])=>{
66
- response.headers.set(key, value);
67
- });
68
- if (-1 !== responseProxy.status) return routerCleanup.deferUntilBodyDone(new Response(response.body, {
69
- status: responseProxy.status,
70
- headers: response.headers
71
- }));
72
- return routerCleanup.deferUntilBodyDone(response);
73
- };
74
38
  function createSSRContext(request, options) {
75
39
  const { config, loaderContext, onError, onTiming, locals, resource, params, responseProxy, reporter } = options;
76
40
  const { nonce, useJsonScript } = config;
@@ -166,20 +130,26 @@ const createRequestHandler = async (handleRequest, createRequestOptions)=>{
166
130
  isRSCNavigation: 'true' === request.headers.get('x-rsc-tree'),
167
131
  basename: ssrContext.baseUrl || '/'
168
132
  };
169
- return withRouterCleanup(context, options.onError, async (routerCleanup)=>{
170
- const beforeRenderResult = await runBeforeRender(context);
133
+ const routerCleanup = createRouterCleanup(context, options.onError);
134
+ const beforeRenderResult = await runWithRouterCleanupOnError(routerCleanup, ()=>runBeforeRender(context));
135
+ await runWithRouterCleanupOnError(routerCleanup, ()=>{
171
136
  applyRouterSnapshotResult(context, options.onError);
172
- if ("u" > typeof Response) {
173
- const redirectResponse = createLoaderRedirectResponse(beforeRenderResult, redirectCtx);
174
- if (redirectResponse) return redirectResponse;
137
+ });
138
+ if ("u" > typeof Response) {
139
+ const redirectResponse = await runWithRouterCleanupOnError(routerCleanup, ()=>createLoaderRedirectResponse(beforeRenderResult, redirectCtx));
140
+ if (redirectResponse) {
141
+ await routerCleanup.run();
142
+ return redirectResponse;
175
143
  }
144
+ }
145
+ await runWithRouterCleanupOnError(routerCleanup, ()=>{
176
146
  if (!createRequestOptions?.enableRsc) {
177
147
  const { htmlTemplate } = options.resource;
178
148
  options.resource.htmlTemplate = htmlTemplate.replace('</head>', `${CHUNK_CSS_PLACEHOLDER}</head>`);
179
149
  }
180
- const response = await renderRequest(request, Root, context, options, handleRequest, !!createRequestOptions?.enableRsc);
181
- return finalizeRenderResponse(response, responseProxy, redirectCtx, routerCleanup);
182
150
  });
151
+ const response = await runWithRouterCleanupOnError(routerCleanup, ()=>renderRequest(request, Root, context, options, handleRequest, !!createRequestOptions?.enableRsc));
152
+ return finishWithRouterCleanup(routerCleanup, ()=>finalizeRenderResponse(response, responseProxy, redirectCtx, routerCleanup));
183
153
  });
184
154
  };
185
155
  return requestHandler;
@@ -0,0 +1,39 @@
1
+ import { getRouterServerSnapshot } from "../../router/runtime/lifecycle.mjs";
2
+ import { handleRSCRedirect } from "../../router/runtime/rsc-router.mjs";
3
+ import { SSRErrors } from "./tracer.mjs";
4
+ const isRedirectStatus = (status)=>status >= 300 && status <= 399;
5
+ const isNullBodyStatus = (status)=>204 === status || 205 === status || 304 === status;
6
+ const processRedirect = (headers, status, ctx)=>{
7
+ if (ctx.enableRsc && ctx.isRSCNavigation) return handleRSCRedirect(headers, ctx.basename, status);
8
+ return new Response(null, {
9
+ status,
10
+ headers
11
+ });
12
+ };
13
+ const applyRouterSnapshotResult = (context, onError)=>{
14
+ const routerServerSnapshot = getRouterServerSnapshot(context);
15
+ const routerStatusCode = routerServerSnapshot?.statusCode ?? context.routerContext?.statusCode;
16
+ if (routerStatusCode && 200 !== routerStatusCode) context.ssrContext?.response.status(routerStatusCode);
17
+ const errors = Object.values(routerServerSnapshot?.errors || context.routerContext?.errors || {});
18
+ if (errors.length > 0) onError(errors[0], SSRErrors.LOADER_ERROR);
19
+ };
20
+ const createLoaderRedirectResponse = (beforeRenderResult, redirectCtx)=>{
21
+ if (!beforeRenderResult || !isRedirectStatus(beforeRenderResult.status)) return;
22
+ if (beforeRenderResult.headers.has('X-Modernjs-Redirect')) return beforeRenderResult;
23
+ const redirectUrl = beforeRenderResult.headers.get('Location') || '/';
24
+ return processRedirect(new Headers({
25
+ Location: redirectUrl
26
+ }), beforeRenderResult.status, redirectCtx);
27
+ };
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);
30
+ Object.entries(responseProxy.headers).forEach(([key, value])=>{
31
+ response.headers.set(key, value);
32
+ });
33
+ if (-1 !== responseProxy.status) return routerCleanup.deferUntilBodyDone(new Response(isNullBodyStatus(responseProxy.status) ? null : response.body, {
34
+ status: responseProxy.status,
35
+ headers: response.headers
36
+ }));
37
+ return routerCleanup.deferUntilBodyDone(response);
38
+ };
39
+ export { applyRouterSnapshotResult, createLoaderRedirectResponse, finalizeRenderResponse };
@@ -1,9 +1,16 @@
1
1
  import { getRouterRuntimeState } from "../../router/runtime/lifecycle.mjs";
2
2
  const ROUTER_CLEANUP_ERROR = 'An error occurs during router runtime cleanup';
3
- async function withRouterCleanup(runtimeContext, onError, callback) {
4
- const routerCleanup = createRouterCleanup(runtimeContext, onError);
3
+ async function runWithRouterCleanupOnError(routerCleanup, callback) {
5
4
  try {
6
- return await callback(routerCleanup);
5
+ return await callback();
6
+ } catch (error) {
7
+ await routerCleanup.run();
8
+ throw error;
9
+ }
10
+ }
11
+ async function finishWithRouterCleanup(routerCleanup, callback) {
12
+ try {
13
+ return await callback();
7
14
  } finally{
8
15
  if (!routerCleanup.deferred) await routerCleanup.run();
9
16
  }
@@ -63,4 +70,4 @@ function createRouterCleanup(runtimeContext, onError) {
63
70
  deferUntilBodyDone
64
71
  };
65
72
  }
66
- export { ROUTER_CLEANUP_ERROR, createRouterCleanup, withRouterCleanup };
73
+ export { ROUTER_CLEANUP_ERROR, createRouterCleanup, finishWithRouterCleanup, runWithRouterCleanupOnError };
@@ -42,6 +42,10 @@ function getMatchedRouteAssets(runtimeContext, routeManifest) {
42
42
  const matchedRouteIds = getRouterMatchedRouteIds(runtimeContext) ?? [];
43
43
  return matchedRouteIds.flatMap((routeId)=>routeAssets[routeId]?.assets ?? []);
44
44
  }
45
+ function getMatchedRouteChunks(runtimeContext, routeManifest, routeAssetToChunk) {
46
+ if (!routeManifest) return [];
47
+ return getMatchedRouteAssets(runtimeContext, routeManifest).map(routeAssetToChunk);
48
+ }
45
49
  const orderHydrationScriptChunks = ({ asyncEntryChunks, collectedChunks, matchedRouteChunks, entryName })=>{
46
50
  const asyncEntryScriptChunks = [];
47
51
  const asyncEntryDependencyChunks = [];
@@ -72,13 +76,12 @@ function createRouteHydrationScriptTags(runtimeContext, entryName, options = {})
72
76
  const { nonce, template } = options;
73
77
  const routeAssets = getRouteAssets(runtimeContext);
74
78
  if (void 0 === routeAssets) return '';
75
- const matchedRouteIds = getRouterMatchedRouteIds(runtimeContext) ?? [];
76
- const assetEntries = [
77
- ...matchedRouteIds.map((routeId)=>routeAssets[routeId]),
78
- routeAssets[`async-${entryName}`]
79
- ].filter((entry)=>void 0 !== entry);
80
- const jsAssets = Array.from(new Set(assetEntries.flatMap((entry)=>(entry.assets ?? []).filter((asset)=>asset.endsWith('.js')))));
79
+ const existingScriptSrcs = void 0 === template ? new Set() : new Set(getScriptTags(template).map(({ src })=>src));
80
+ const jsAssets = Array.from(new Set([
81
+ ...getMatchedRouteAssets(runtimeContext),
82
+ ...routeAssets[`async-${entryName}`]?.assets ?? []
83
+ ].filter((asset)=>asset.endsWith('.js'))));
81
84
  const nonceAttr = void 0 === nonce || '' === nonce ? '' : ` nonce="${nonce}"`;
82
- return jsAssets.filter((asset)=>template?.includes(asset) !== true).map((asset)=>`<script src=${asset}${nonceAttr}></script>`).join(' ');
85
+ return jsAssets.filter((asset)=>!existingScriptSrcs.has(asset)).map((asset)=>`<script src=${asset}${nonceAttr}></script>`).join(' ');
83
86
  }
84
- export { createRouteHydrationScriptTags, getMatchedRouteAssets, injectBeforeHydrationEntryScript, orderHydrationScriptChunks, replaceChunkJsPlaceholder };
87
+ export { createRouteHydrationScriptTags, getMatchedRouteChunks, injectBeforeHydrationEntryScript, orderHydrationScriptChunks, replaceChunkJsPlaceholder };
@@ -4,19 +4,20 @@ import { SSR_DATA_JSON_ID } from "../../constants.mjs";
4
4
  import { SSR_DATA_PLACEHOLDER } from "../constants.mjs";
5
5
  import { createRouteHydrationScriptTags, replaceChunkJsPlaceholder } from "../scriptOrder.mjs";
6
6
  import { buildHtml } from "../shared.mjs";
7
- import { attributesToString, safeReplace } from "../utils.mjs";
7
+ import { attributesToString } from "../utils.mjs";
8
8
  function buildShellAfterTemplate(afterAppTemplate, options) {
9
9
  const { request, config, ssrConfig, runtimeContext, renderLevel, entryName } = options;
10
10
  const callbacks = [
11
+ (template)=>injectJs(template, entryName, config.nonce),
11
12
  createReplaceSSRData({
12
13
  request,
13
14
  ssrConfig,
14
15
  nonce: config.nonce,
15
16
  useJsonScript: config.useJsonScript,
16
17
  runtimeContext,
17
- renderLevel
18
- }),
19
- (template)=>injectJs(template, entryName, config.nonce)
18
+ renderLevel,
19
+ entryName
20
+ })
20
21
  ];
21
22
  async function injectJs(template, entryName, nonce) {
22
23
  const jsChunkStr = createRouteHydrationScriptTags(runtimeContext, entryName, {
@@ -29,7 +30,7 @@ function buildShellAfterTemplate(afterAppTemplate, options) {
29
30
  return buildHtml(afterAppTemplate, callbacks);
30
31
  }
31
32
  function createReplaceSSRData(options) {
32
- const { runtimeContext, nonce, renderLevel, useJsonScript, ssrConfig } = options;
33
+ const { runtimeContext, nonce, renderLevel, useJsonScript, ssrConfig, entryName } = options;
33
34
  const { request, reporter } = runtimeContext.ssrContext;
34
35
  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;
35
36
  const ssrData = {
@@ -60,6 +61,9 @@ function createReplaceSSRData(options) {
60
61
  const ssrDataScript = useJsonScript ? `<script type="application/json" id="${SSR_DATA_JSON_ID}">${serializeSSRData}</script>` : `<script${attrsStr}>window._SSR_DATA = ${serializeSSRData}</script>`;
61
62
  const hydrationScripts = getRouterHydrationScripts(runtimeContext);
62
63
  const ssrScripts = hydrationScripts.length ? `${ssrDataScript}\n${hydrationScripts.join('\n')}` : ssrDataScript;
63
- return (template)=>safeReplace(template, SSR_DATA_PLACEHOLDER, ssrScripts);
64
+ return (template)=>{
65
+ if (!template.includes(SSR_DATA_PLACEHOLDER)) return template;
66
+ return replaceChunkJsPlaceholder(template, ssrScripts, entryName, SSR_DATA_PLACEHOLDER);
67
+ };
64
68
  }
65
69
  export { buildShellAfterTemplate };
@@ -2,12 +2,12 @@ import { buildShellAfterTemplate } from "./afterTemplate.mjs";
2
2
  import { buildShellBeforeTemplate } from "./beforeTemplate.mjs";
3
3
  const HTML_SEPARATOR = '<!--<?- html ?>-->';
4
4
  const getTemplates = async (htmlTemplate, options)=>{
5
- const [beforeAppTemplate = '', afterAppHtmlTemplate = ''] = htmlTemplate.split(HTML_SEPARATOR) || [];
5
+ const builtTemplate = await buildShellAfterTemplate(htmlTemplate, options);
6
+ const [beforeAppTemplate = '', afterAppHtmlTemplate = ''] = builtTemplate.split(HTML_SEPARATOR) || [];
6
7
  const builtBeforeTemplate = await buildShellBeforeTemplate(beforeAppTemplate, options);
7
- const builtAfterTemplate = await buildShellAfterTemplate(afterAppHtmlTemplate, options);
8
8
  return {
9
9
  shellBefore: builtBeforeTemplate,
10
- shellAfter: builtAfterTemplate
10
+ shellAfter: afterAppHtmlTemplate
11
11
  };
12
12
  };
13
13
  export { getTemplates };