@bleedingdev/modern-js-runtime 3.5.0-ultramodern.4 → 3.5.0-ultramodern.41

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 (84) hide show
  1. package/dist/cjs/boundary-debugger/index.js +13 -3
  2. package/dist/cjs/cli/ssr/index.js +1 -2
  3. package/dist/cjs/core/context/public.js +49 -0
  4. package/dist/cjs/core/context/runtime.js +6 -8
  5. package/dist/cjs/core/react/wrapper.js +57 -0
  6. package/dist/cjs/core/server/federatedCss.js +7 -3
  7. package/dist/cjs/core/server/requestHandler.js +15 -45
  8. package/dist/cjs/core/server/requestResponse.js +83 -0
  9. package/dist/cjs/core/server/routerCleanup.js +16 -6
  10. package/dist/cjs/core/server/scriptOrder.js +13 -10
  11. package/dist/cjs/core/server/string/loadable.js +3 -11
  12. package/dist/cjs/index.js +7 -6
  13. package/dist/cjs/router/cli/code/templates.js +3 -2
  14. package/dist/cjs/router/cli/nestedRoutesSpec.js +3 -1
  15. package/dist/cjs/router/runtime/hooks.js +7 -6
  16. package/dist/cjs/router/runtime/provider.js +1 -1
  17. package/dist/esm/boundary-debugger/index.mjs +13 -3
  18. package/dist/esm/cli/code.mjs +12 -12
  19. package/dist/esm/cli/ssr/index.mjs +1 -2
  20. package/dist/esm/core/context/public.mjs +5 -0
  21. package/dist/esm/core/context/runtime.mjs +4 -6
  22. package/dist/esm/core/react/wrapper.mjs +58 -1
  23. package/dist/esm/core/server/federatedCss.mjs +7 -3
  24. package/dist/esm/core/server/requestHandler.mjs +15 -45
  25. package/dist/esm/core/server/requestResponse.mjs +39 -0
  26. package/dist/esm/core/server/routerCleanup.mjs +11 -4
  27. package/dist/esm/core/server/scriptOrder.mjs +11 -8
  28. package/dist/esm/core/server/string/loadable.mjs +3 -8
  29. package/dist/esm/exports/loadable.mjs +3 -3
  30. package/dist/esm/index.mjs +2 -1
  31. package/dist/esm/router/cli/code/index.mjs +5 -5
  32. package/dist/esm/router/cli/code/templates.mjs +3 -2
  33. package/dist/esm/router/cli/handler.mjs +3 -3
  34. package/dist/esm/router/cli/nestedRoutesSpec.mjs +3 -1
  35. package/dist/esm/router/runtime/hooks.mjs +7 -6
  36. package/dist/esm/router/runtime/provider.mjs +1 -1
  37. package/dist/esm-node/boundary-debugger/index.mjs +13 -3
  38. package/dist/esm-node/cli/code.mjs +12 -12
  39. package/dist/esm-node/cli/ssr/index.mjs +1 -2
  40. package/dist/esm-node/core/context/public.mjs +6 -0
  41. package/dist/esm-node/core/context/runtime.mjs +4 -6
  42. package/dist/esm-node/core/react/wrapper.mjs +58 -1
  43. package/dist/esm-node/core/server/federatedCss.mjs +7 -3
  44. package/dist/esm-node/core/server/requestHandler.mjs +15 -45
  45. package/dist/esm-node/core/server/requestResponse.mjs +40 -0
  46. package/dist/esm-node/core/server/routerCleanup.mjs +11 -4
  47. package/dist/esm-node/core/server/scriptOrder.mjs +11 -8
  48. package/dist/esm-node/core/server/string/loadable.mjs +3 -8
  49. package/dist/esm-node/exports/loadable.mjs +3 -3
  50. package/dist/esm-node/index.mjs +2 -1
  51. package/dist/esm-node/router/cli/code/index.mjs +5 -5
  52. package/dist/esm-node/router/cli/code/templates.mjs +3 -2
  53. package/dist/esm-node/router/cli/handler.mjs +3 -3
  54. package/dist/esm-node/router/cli/nestedRoutesSpec.mjs +3 -1
  55. package/dist/esm-node/router/runtime/hooks.mjs +7 -6
  56. package/dist/esm-node/router/runtime/provider.mjs +1 -1
  57. package/dist/types/boundary-debugger/index.d.ts +1 -1
  58. package/dist/types/common.d.ts +8 -1
  59. package/dist/types/core/context/index.d.ts +25 -9
  60. package/dist/types/core/context/monitors/default.d.ts +10 -2
  61. package/dist/types/core/context/monitors/index.d.ts +1 -1
  62. package/dist/types/core/context/monitors/index.server.d.ts +2 -2
  63. package/dist/types/core/context/public.d.ts +27 -0
  64. package/dist/types/core/context/runtime.d.ts +12 -22
  65. package/dist/types/core/react/index.d.ts +1 -1
  66. package/dist/types/core/server/requestResponse.d.ts +15 -0
  67. package/dist/types/core/server/routerCleanup.d.ts +2 -1
  68. package/dist/types/core/server/scriptOrder.d.ts +1 -1
  69. package/dist/types/core/server/stream/shared.d.ts +2 -2
  70. package/dist/types/core/server/string/loadable.d.ts +0 -2
  71. package/dist/types/exports/head.d.ts +1 -1
  72. package/dist/types/index.d.ts +5 -5
  73. package/dist/types/internal.d.ts +0 -1
  74. package/dist/types/router/runtime/hooks.d.ts +10 -6
  75. package/dist/types/router/runtime/internal.d.ts +1 -1
  76. package/dist/types/router/runtime/plugin.d.ts +1 -1
  77. package/dist/types/router/runtime/plugin.node.d.ts +1 -1
  78. package/dist/types/router/runtime/provider.d.ts +1 -1
  79. package/dist/types/router/runtime/types.d.ts +27 -5
  80. package/package.json +17 -24
  81. package/dist/cjs/exports/tanstack-router.js +0 -83
  82. package/dist/esm/exports/tanstack-router.mjs +0 -30
  83. package/dist/esm-node/exports/tanstack-router.mjs +0 -31
  84. package/dist/types/exports/tanstack-router.d.ts +0 -88
@@ -3,7 +3,7 @@ import { cloneDeep } from "@modern-js/utils/lodash";
3
3
  import path from "path";
4
4
  import { isPageComponentFile } from "./code/utils.mjs";
5
5
  import { modifyEntrypoints } from "./entry.mjs";
6
- import * as __rspack_external__code_templates_mjs_5e908598 from "./code/templates.mjs";
6
+ import * as __rspack_external__code_templates_mjs_f6c22489 from "./code/templates.mjs";
7
7
  const DEFAULT_ENTRYPOINTS_KEY = '__default_router_entries__';
8
8
  const originEntrypointsByKey = new Map();
9
9
  async function handleModifyEntrypoints(entrypoints, routesDir, options = {}) {
@@ -25,7 +25,7 @@ async function handleGeneratorEntryCode(api, entrypoints, options = {}) {
25
25
  if (entrypoint.nestedRoutesEntry || entrypoint.pageRoutesEntry) {
26
26
  const route = appContext.serverRoutes.find((r)=>r.entryName === entrypoint.entryName);
27
27
  const basename = route?.urlPath || '/';
28
- generatorRegisterCode(internalDirectory, entrypoint.entryName, await __rspack_external__code_templates_mjs_5e908598.runtimeGlobalContext({
28
+ generatorRegisterCode(internalDirectory, entrypoint.entryName, await __rspack_external__code_templates_mjs_f6c22489.runtimeGlobalContext({
29
29
  entryName: entrypoint.entryName,
30
30
  metaName: appContext.metaName,
31
31
  srcDirectory: appContext.srcDirectory,
@@ -35,7 +35,7 @@ async function handleGeneratorEntryCode(api, entrypoints, options = {}) {
35
35
  rscType: enableRsc ? 'client' : void 0,
36
36
  basename
37
37
  }));
38
- if (enableRsc) generatorServerRegisterCode(internalDirectory, entrypoint.entryName, await __rspack_external__code_templates_mjs_5e908598.runtimeGlobalContext({
38
+ if (enableRsc) generatorServerRegisterCode(internalDirectory, entrypoint.entryName, await __rspack_external__code_templates_mjs_f6c22489.runtimeGlobalContext({
39
39
  entryName: entrypoint.entryName,
40
40
  metaName: appContext.metaName,
41
41
  srcDirectory: appContext.srcDirectory,
@@ -1,6 +1,7 @@
1
1
  import node_path from "node:path";
2
2
  import { setTimeout as promises_setTimeout } from "node:timers/promises";
3
3
  import { fs } from "@modern-js/utils";
4
+ import { cloneDeep } from "@modern-js/utils/lodash";
4
5
  const lockPollIntervalMs = 25;
5
6
  const staleLockAgeMs = 120000;
6
7
  const pendingUpdates = new Map();
@@ -43,6 +44,7 @@ async function writeJSONAtomically(filePath, value) {
43
44
  }
44
45
  async function updateNestedRoutesSpec(specPath, nextRoutes) {
45
46
  const resolvedSpecPath = node_path.resolve(specPath);
47
+ const nextRoutesSnapshot = cloneDeep(nextRoutes);
46
48
  const previousUpdate = pendingUpdates.get(resolvedSpecPath) ?? Promise.resolve();
47
49
  const currentUpdate = previousUpdate.catch(()=>void 0).then(async ()=>{
48
50
  const releaseLock = await acquireSpecLock(resolvedSpecPath);
@@ -50,7 +52,7 @@ async function updateNestedRoutesSpec(specPath, nextRoutes) {
50
52
  const existingRoutes = await fs.pathExists(resolvedSpecPath) ? await fs.readJSON(resolvedSpecPath) : {};
51
53
  await writeJSONAtomically(resolvedSpecPath, {
52
54
  ...existingRoutes,
53
- ...nextRoutes
55
+ ...nextRoutesSnapshot
54
56
  });
55
57
  } finally{
56
58
  await releaseLock();
@@ -1,8 +1,9 @@
1
1
  import { createSyncHook } from "@modern-js/plugin";
2
- const modifyRoutes = createSyncHook();
3
- const onBeforeCreateRoutes = createSyncHook();
4
- const onBeforeCreateRouter = createSyncHook();
5
- const onAfterCreateRouter = createSyncHook();
6
- const onBeforeHydrateRouter = createSyncHook();
7
- const onAfterHydrateRouter = createSyncHook();
2
+ const createRouterSyncHook = ()=>createSyncHook();
3
+ const modifyRoutes = createRouterSyncHook();
4
+ const onBeforeCreateRoutes = createRouterSyncHook();
5
+ const onBeforeCreateRouter = createRouterSyncHook();
6
+ const onAfterCreateRouter = createRouterSyncHook();
7
+ const onBeforeHydrateRouter = createRouterSyncHook();
8
+ const onAfterHydrateRouter = createRouterSyncHook();
8
9
  export { modifyRoutes, onAfterCreateRouter, onAfterHydrateRouter, onBeforeCreateRouter, onBeforeCreateRoutes, onBeforeHydrateRouter };
@@ -40,7 +40,7 @@ function registerRouterProvider(name, factory, options = {}) {
40
40
  }
41
41
  function resolveRouterProvider(framework, options = {}) {
42
42
  const registry = getRegistry();
43
- const name = framework || registry.defaultProvider || options.localDefault?.name;
43
+ const name = framework || options.localDefault?.name || registry.defaultProvider;
44
44
  if (void 0 === name) throw new Error('[@modern-js/runtime] No default router provider is registered. This is a bug in the runtime setup.');
45
45
  if (void 0 !== options.localDefault && name === options.localDefault.name) return options.localDefault.factory;
46
46
  const factory = registry.providers.get(name);
@@ -110,9 +110,20 @@ function BoundaryDebugger({ controlMode = 'visible', enabledByDefault = false, l
110
110
  ]);
111
111
  useEffect(()=>{
112
112
  if (!enabled) return void setBoxes([]);
113
+ let resizeObserver;
114
+ const observedElements = new Set();
115
+ const observeBoundaryElements = (elements)=>{
116
+ if (void 0 === resizeObserver) return;
117
+ for (const element of elements)if (!observedElements.has(element)) {
118
+ observedElements.add(element);
119
+ resizeObserver.observe(element);
120
+ }
121
+ };
113
122
  const readBoxes = ()=>{
123
+ const elements = collectBoundaryElements(legacySelector);
124
+ observeBoundaryElements(elements);
114
125
  const seenBoxes = new Set();
115
- const nextBoxes = collectBoundaryElements(legacySelector).map((element)=>{
126
+ const nextBoxes = elements.map((element)=>{
116
127
  const boundaryId = getBoundaryId(element);
117
128
  if (void 0 === boundaryId || '' === boundaryId) return;
118
129
  const rect = element.getBoundingClientRect();
@@ -140,9 +151,8 @@ function BoundaryDebugger({ controlMode = 'visible', enabledByDefault = false, l
140
151
  }).filter((box)=>void 0 !== box);
141
152
  setBoxes(nextBoxes);
142
153
  };
154
+ resizeObserver = "u" < typeof ResizeObserver ? void 0 : new ResizeObserver(readBoxes);
143
155
  readBoxes();
144
- const resizeObserver = "u" < typeof ResizeObserver ? void 0 : new ResizeObserver(readBoxes);
145
- for (const element of collectBoundaryElements(legacySelector))resizeObserver?.observe(element);
146
156
  const mutationObserver = new MutationObserver(readBoxes);
147
157
  mutationObserver.observe(document.body, {
148
158
  childList: true,
@@ -3,8 +3,8 @@ import { formatImportPath, fs } from "@modern-js/utils";
3
3
  import path from "path";
4
4
  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";
5
5
  import { resolveSSRMode } from "./ssr/mode.mjs";
6
- import * as __rspack_external__template_mjs_d6ab8956 from "./template.mjs";
7
- import * as __rspack_external__template_server_mjs_38d6edb1 from "./template.server.mjs";
6
+ import * as __rspack_external__template_mjs_d1604447 from "./template.mjs";
7
+ import * as __rspack_external__template_server_mjs_f98cfe58 from "./template.server.mjs";
8
8
  const normalizePreEntry = (preEntry)=>{
9
9
  if (!preEntry) return [];
10
10
  if (Array.isArray(preEntry)) return preEntry.filter((v)=>'string' == typeof v && v.length > 0);
@@ -36,7 +36,7 @@ const generateCode = async (entrypoints, appContext, config, hooks)=>{
36
36
  nestedRoutesEntry
37
37
  });
38
38
  let indexCode = '';
39
- indexCode = ssrMode || !config.server.rsc || customEntry ? __rspack_external__template_mjs_d6ab8956.index({
39
+ indexCode = ssrMode || !config.server.rsc || customEntry ? __rspack_external__template_mjs_d1604447.index({
40
40
  srcDirectory,
41
41
  internalSrcAlias,
42
42
  metaName,
@@ -46,7 +46,7 @@ const generateCode = async (entrypoints, appContext, config, hooks)=>{
46
46
  mountId,
47
47
  enableRsc: config.server.rsc,
48
48
  isNestedRouter: !!entrypoint.nestedRoutesEntry
49
- }) : __rspack_external__template_mjs_d6ab8956.entryForCSRWithRSC({
49
+ }) : __rspack_external__template_mjs_d1604447.entryForCSRWithRSC({
50
50
  metaName,
51
51
  entryName,
52
52
  mountId,
@@ -77,7 +77,7 @@ const generateCode = async (entrypoints, appContext, config, hooks)=>{
77
77
  if (ssrMode) await fs.outputFile(bootstrapServerFile, `export const requestHandler = import('./${SERVER_ENTRY_POINT_FILE_NAME}').then((m) => m.requestHandler)`, 'utf8');
78
78
  }
79
79
  if (ssrMode) {
80
- const indexServerCode = __rspack_external__template_server_mjs_38d6edb1.serverIndex({
80
+ const indexServerCode = __rspack_external__template_server_mjs_f98cfe58.serverIndex({
81
81
  entry,
82
82
  entryName,
83
83
  internalSrcAlias,
@@ -91,16 +91,16 @@ const generateCode = async (entrypoints, appContext, config, hooks)=>{
91
91
  await fs.outputFile(indexServerFile, indexServerCode, 'utf8');
92
92
  } else if (config.server.rsc) {
93
93
  const indexServerFile = path.resolve(internalDirectory, `./${entryName}/${SERVER_ENTRY_POINT_FILE_NAME}`);
94
- const indexServerCode = __rspack_external__template_server_mjs_38d6edb1.entryForCSRWithRSC({
94
+ const indexServerCode = __rspack_external__template_server_mjs_f98cfe58.entryForCSRWithRSC({
95
95
  entryName,
96
96
  metaName
97
97
  });
98
98
  await fs.outputFile(indexServerFile, indexServerCode, 'utf8');
99
99
  }
100
- const registerCode = __rspack_external__template_mjs_d6ab8956.register();
100
+ const registerCode = __rspack_external__template_mjs_d1604447.register();
101
101
  const registerFile = path.resolve(internalDirectory, `./${entryName}/${ENTRY_POINT_REGISTER_FILE_NAME}`);
102
102
  await fs.outputFile(registerFile, registerCode, 'utf8');
103
- const registerRuntimeCode = __rspack_external__template_mjs_d6ab8956.runtimeRegister({
103
+ const registerRuntimeCode = __rspack_external__template_mjs_d1604447.runtimeRegister({
104
104
  entryName,
105
105
  srcDirectory,
106
106
  internalSrcAlias,
@@ -114,7 +114,7 @@ const generateCode = async (entrypoints, appContext, config, hooks)=>{
114
114
  if (!config.server.rsc || entrypoint.nestedRoutesEntry) {
115
115
  const route = serverRoutes.find((r)=>r.entryName === entryName);
116
116
  const basename = route?.urlPath || '/';
117
- contextCode = __rspack_external__template_mjs_d6ab8956.runtimeGlobalContext({
117
+ contextCode = __rspack_external__template_mjs_d1604447.runtimeGlobalContext({
118
118
  entryName,
119
119
  srcDirectory,
120
120
  internalSrcAlias,
@@ -125,18 +125,18 @@ const generateCode = async (entrypoints, appContext, config, hooks)=>{
125
125
  });
126
126
  } else {
127
127
  const AppProxyPath = path.join(internalDirectory, entryName, './AppProxy.jsx');
128
- const appProxyCode = __rspack_external__template_mjs_d6ab8956.AppProxyForRSC({
128
+ const appProxyCode = __rspack_external__template_mjs_d1604447.AppProxyForRSC({
129
129
  srcDirectory,
130
130
  internalSrcAlias,
131
131
  entry,
132
132
  customEntry
133
133
  });
134
134
  await fs.outputFile(AppProxyPath, appProxyCode);
135
- contextCode = __rspack_external__template_mjs_d6ab8956.runtimeGlobalContextForRSCClient({
135
+ contextCode = __rspack_external__template_mjs_d1604447.runtimeGlobalContextForRSCClient({
136
136
  metaName,
137
137
  customEntry
138
138
  });
139
- const contextServerCode = __rspack_external__template_mjs_d6ab8956.runtimeGlobalContextForRSCServer({
139
+ const contextServerCode = __rspack_external__template_mjs_d1604447.runtimeGlobalContextForRSCServer({
140
140
  metaName
141
141
  });
142
142
  const contextFile = path.resolve(internalDirectory, `./${entryName}/${ENTRY_POINT_RUNTIME_GLOBAL_CONTEXT_FILE_NAME}.server.js`);
@@ -86,14 +86,13 @@ const ssrBuilderPlugin = (modernAPI, outputModule, exportLoadablePath)=>({
86
86
  const hasServerRendering = hasServerRenderingConfig(userConfig);
87
87
  const hasModuleFederationRuntimeMarker = hasServerRendering && shouldUseModuleFederationNodeOutput(config);
88
88
  const hasExplicitMfSsrFlag = isModuleFederationAppSSREnabled(userConfig);
89
- const isCloudflareWorkerSSR = 'workerSSR' === name && userConfig.deploy?.target === 'cloudflare';
90
89
  const requireExplicitMfSsrFlag = 'true' === process.env.MODERN_MF_APP_SSR_REQUIRE_EXPLICIT;
91
90
  if (hasServerRendering && hasModuleFederationRuntimeMarker && !hasExplicitMfSsrFlag) {
92
91
  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.';
93
92
  if (requireExplicitMfSsrFlag) throw new Error(`${warningMessage} (enforced by MODERN_MF_APP_SSR_REQUIRE_EXPLICIT=true)`);
94
93
  console.warn(warningMessage);
95
94
  }
96
- const isModuleFederationAppSSR = hasServerRendering && hasExplicitMfSsrFlag && !isCloudflareWorkerSSR;
95
+ const isModuleFederationAppSSR = hasServerRendering && hasExplicitMfSsrFlag;
97
96
  const ssrEnv = userConfig.deploy?.worker?.ssr || userConfig.server?.rsc ? 'edge' : 'node';
98
97
  const appContext = modernAPI.getAppContext();
99
98
  const { appDirectory, entrypoints } = appContext;
@@ -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 };
@@ -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 };
@@ -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";