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

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (86) hide show
  1. package/dist/cjs/cli/index.js +1 -11
  2. package/dist/cjs/cli/ssr/index.js +1 -0
  3. package/dist/cjs/core/browser/hydrate.js +31 -27
  4. package/dist/cjs/core/browser/index.js +4 -15
  5. package/dist/cjs/core/react/wrapper.js +23 -28
  6. package/dist/cjs/core/server/requestResponse.js +5 -5
  7. package/dist/cjs/core/server/scriptOrder.js +1 -1
  8. package/dist/cjs/core/server/stream/beforeTemplate.worker.js +1 -10
  9. package/dist/cjs/core/server/string/index.js +3 -3
  10. package/dist/cjs/core/server/utils.js +3 -3
  11. package/dist/cjs/document/cli/index.js +5 -2
  12. package/dist/cjs/module-federation/distributed-ssr.js +13 -12
  13. package/dist/cjs/module-federation/last-known-good.js +1 -1
  14. package/dist/cjs/module-federation/manifest-recovery-runtime-plugin.js +27 -38
  15. package/dist/cjs/router/cli/code/index.js +16 -9
  16. package/dist/cjs/router/cli/code/templates.js +36 -27
  17. package/dist/cjs/router/cli/handler.js +7 -1
  18. package/dist/cjs/router/runtime/plugin.js +22 -17
  19. package/dist/cjs/router/runtime/plugin.node.js +11 -3
  20. package/dist/cjs/router/runtime/provider.js +2 -2
  21. package/dist/cjs/router/runtime/redirect.js +51 -0
  22. package/dist/cjs/router/runtime/routerHelper.js +4 -0
  23. package/dist/cjs/router/runtime/rsc-router.js +2 -13
  24. package/dist/cjs/router/runtime/utils.js +3 -2
  25. package/dist/esm/cli/index.mjs +2 -12
  26. package/dist/esm/cli/ssr/index.mjs +1 -0
  27. package/dist/esm/core/browser/hydrate.mjs +30 -22
  28. package/dist/esm/core/browser/index.mjs +5 -13
  29. package/dist/esm/core/react/wrapper.mjs +23 -28
  30. package/dist/esm/core/server/requestResponse.mjs +4 -4
  31. package/dist/esm/core/server/scriptOrder.mjs +1 -1
  32. package/dist/esm/core/server/stream/beforeTemplate.worker.mjs +1 -10
  33. package/dist/esm/core/server/string/index.mjs +3 -3
  34. package/dist/esm/core/server/utils.mjs +1 -1
  35. package/dist/esm/document/cli/index.mjs +1 -1
  36. package/dist/esm/module-federation/distributed-ssr.mjs +13 -12
  37. package/dist/esm/module-federation/last-known-good.mjs +1 -1
  38. package/dist/esm/module-federation/manifest-recovery-runtime-plugin.mjs +22 -33
  39. package/dist/esm/router/cli/code/index.mjs +16 -9
  40. package/dist/esm/router/cli/code/templates.mjs +36 -27
  41. package/dist/esm/router/cli/handler.mjs +7 -1
  42. package/dist/esm/router/runtime/plugin.mjs +24 -19
  43. package/dist/esm/router/runtime/plugin.node.mjs +12 -4
  44. package/dist/esm/router/runtime/provider.mjs +2 -2
  45. package/dist/esm/router/runtime/redirect.mjs +13 -0
  46. package/dist/esm/router/runtime/routerHelper.mjs +2 -1
  47. package/dist/esm/router/runtime/rsc-router.mjs +2 -13
  48. package/dist/esm/router/runtime/utils.mjs +2 -1
  49. package/dist/esm-node/cli/index.mjs +2 -12
  50. package/dist/esm-node/cli/ssr/index.mjs +1 -0
  51. package/dist/esm-node/core/browser/hydrate.mjs +30 -22
  52. package/dist/esm-node/core/browser/index.mjs +5 -13
  53. package/dist/esm-node/core/react/wrapper.mjs +23 -28
  54. package/dist/esm-node/core/server/requestResponse.mjs +4 -4
  55. package/dist/esm-node/core/server/scriptOrder.mjs +1 -1
  56. package/dist/esm-node/core/server/stream/beforeTemplate.worker.mjs +1 -10
  57. package/dist/esm-node/core/server/string/index.mjs +3 -3
  58. package/dist/esm-node/core/server/utils.mjs +1 -1
  59. package/dist/esm-node/document/cli/index.mjs +1 -1
  60. package/dist/esm-node/module-federation/distributed-ssr.mjs +13 -12
  61. package/dist/esm-node/module-federation/last-known-good.mjs +1 -1
  62. package/dist/esm-node/module-federation/manifest-recovery-runtime-plugin.mjs +22 -33
  63. package/dist/esm-node/router/cli/code/index.mjs +16 -9
  64. package/dist/esm-node/router/cli/code/templates.mjs +36 -27
  65. package/dist/esm-node/router/cli/handler.mjs +7 -1
  66. package/dist/esm-node/router/runtime/plugin.mjs +24 -19
  67. package/dist/esm-node/router/runtime/plugin.node.mjs +12 -4
  68. package/dist/esm-node/router/runtime/provider.mjs +2 -2
  69. package/dist/esm-node/router/runtime/redirect.mjs +14 -0
  70. package/dist/esm-node/router/runtime/routerHelper.mjs +2 -1
  71. package/dist/esm-node/router/runtime/rsc-router.mjs +2 -13
  72. package/dist/esm-node/router/runtime/utils.mjs +2 -1
  73. package/dist/types/core/browser/hydrate.d.ts +0 -1
  74. package/dist/types/core/browser/index.d.ts +0 -1
  75. package/dist/types/core/server/utils.d.ts +1 -1
  76. package/dist/types/document/cli/index.d.ts +1 -0
  77. package/dist/types/module-federation/distributed-ssr.d.ts +3 -3
  78. package/dist/types/module-federation/manifest-recovery-runtime-plugin.d.ts +1 -1
  79. package/dist/types/router/cli/code/index.d.ts +6 -1
  80. package/dist/types/router/cli/code/templates.d.ts +8 -3
  81. package/dist/types/router/cli/handler.d.ts +4 -0
  82. package/dist/types/router/runtime/redirect.d.ts +1 -0
  83. package/dist/types/router/runtime/routerHelper.d.ts +7 -0
  84. package/dist/types/router/runtime/rsc-router.d.ts +1 -2
  85. package/package.json +15 -14
  86. package/rstest.config.mts +2 -0
@@ -8,24 +8,24 @@ function distributedSsrFragmentKey(remote, expose) {
8
8
  }
9
9
  function getDistributedSsrFragmentContext(response) {
10
10
  const locals = response?.locals;
11
- if (!locals || 'object' != typeof locals) return;
12
- const context = locals[DISTRIBUTED_SSR_FRAGMENTS_LOCALS_KEY];
13
- if (!context || 'object' != typeof context) return;
11
+ if ('object' != typeof locals || null === locals) return;
12
+ const context = DISTRIBUTED_SSR_FRAGMENTS_LOCALS_KEY in locals ? locals[DISTRIBUTED_SSR_FRAGMENTS_LOCALS_KEY] : void 0;
13
+ if ('object' != typeof context || null === context) return;
14
14
  return context;
15
15
  }
16
16
  function useDistributedSsrFragmentProps({ boundaryId, expose }) {
17
17
  const runtimeContext = useRuntimeContext();
18
18
  const locals = runtimeContext.requestContext?.response?.locals;
19
- const request = locals && 'object' == typeof locals ? locals[DISTRIBUTED_SSR_FRAGMENT_REQUEST_LOCALS_KEY] : void 0;
20
- if (!request || 'object' != typeof request || request.boundaryId !== boundaryId || request.expose !== expose) throw new Error(`Distributed SSR fragment request contract mismatch for ${boundaryId} ${expose}.`);
21
- const props = request.props;
22
- if (!props || 'object' != typeof props || Array.isArray(props)) throw new Error(`Distributed SSR fragment request props must be an object for ${boundaryId} ${expose}.`);
19
+ const request = 'object' == typeof locals && null !== locals && DISTRIBUTED_SSR_FRAGMENT_REQUEST_LOCALS_KEY in locals ? locals[DISTRIBUTED_SSR_FRAGMENT_REQUEST_LOCALS_KEY] : void 0;
20
+ if ('object' != typeof request || null === request || !('boundaryId' in request) || request.boundaryId !== boundaryId || !('expose' in request) || request.expose !== expose) throw new Error(`Distributed SSR fragment request contract mismatch for ${boundaryId} ${expose}.`);
21
+ const props = 'props' in request ? request.props : void 0;
22
+ if ('object' != typeof props || null === props || Array.isArray(props)) throw new Error(`Distributed SSR fragment request props must be an object for ${boundaryId} ${expose}.`);
23
23
  return props;
24
24
  }
25
25
  function isThenable(value) {
26
- return 'function' == typeof value.then;
26
+ return void 0 !== value && 'then' in value && 'function' == typeof value.then;
27
27
  }
28
- function DistributedSsrBoundary({ children, expose, fallback, fragmentProps = {}, remote }) {
28
+ function DistributedSsrBoundary({ children, expose, fallback, fragmentProps, remote }) {
29
29
  const runtimeContext = useRuntimeContext();
30
30
  const key = distributedSsrFragmentKey(remote, expose);
31
31
  const attributes = {
@@ -36,12 +36,13 @@ function DistributedSsrBoundary({ children, expose, fallback, fragmentProps = {}
36
36
  children: children
37
37
  });
38
38
  const fragmentContext = getDistributedSsrFragmentContext(runtimeContext.requestContext?.response);
39
- if (!fragmentContext) return /*#__PURE__*/ jsx("div", {
39
+ if (void 0 === fragmentContext) return /*#__PURE__*/ jsx("div", {
40
40
  ...attributes,
41
41
  children: children
42
42
  });
43
- const fragmentOrPromise = fragmentContext.resolve?.(remote, expose, fragmentProps) ?? fragmentContext.fragments?.[key];
44
- if (fragmentOrPromise && isThenable(fragmentOrPromise)) throw fragmentOrPromise;
43
+ const resolverFragmentProps = void 0 === fragmentProps ? {} : Object.fromEntries(Object.entries(fragmentProps));
44
+ const fragmentOrPromise = fragmentContext.resolve?.(remote, expose, resolverFragmentProps) ?? fragmentContext.fragments?.[key];
45
+ if (isThenable(fragmentOrPromise)) throw fragmentOrPromise;
45
46
  const fragment = fragmentOrPromise;
46
47
  if (fragment?.status === 'ready') return /*#__PURE__*/ jsx("div", {
47
48
  ...attributes,
@@ -34,7 +34,7 @@ function staleRecordResult(ref, env, ageMs, maxStaleMs) {
34
34
  }
35
35
  function createLastKnownGoodProvider(options) {
36
36
  const storage = options.storage ?? createInMemoryLkgStorage();
37
- const now = options.now ?? (()=>Date.now());
37
+ const now = options.now ?? (()=>Math.floor(performance.timeOrigin + performance.now()));
38
38
  const maxStaleMs = options.freshness?.maxStaleMs;
39
39
  async function serveFromCache(ref, env, fallback) {
40
40
  const key = deliveryUnitResolutionKey(ref.unitId, env);
@@ -1,4 +1,5 @@
1
1
  import "node:module";
2
+ import { wait } from "@modern-js/utils/universal";
2
3
  const DEFAULT_ATTEMPTS = 3;
3
4
  const DEFAULT_RETRY_DELAY_MS = 100;
4
5
  const DEFAULT_TIMEOUT_MS = 1000;
@@ -44,7 +45,7 @@ const isRetryableError = (error)=>{
44
45
  return error instanceof TypeError || /(?:fetch failed|network|ECONNREFUSED|ECONNRESET|ETIMEDOUT|EAI_AGAIN)/i.test(message);
45
46
  };
46
47
  const isHttpManifestUrl = (id)=>{
47
- if (!id) return false;
48
+ if (void 0 === id || 0 === id.length) return false;
48
49
  try {
49
50
  const url = new URL(id);
50
51
  return ('http:' === url.protocol || 'https:' === url.protocol) && url.pathname.endsWith('.json');
@@ -52,47 +53,35 @@ const isHttpManifestUrl = (id)=>{
52
53
  return false;
53
54
  }
54
55
  };
55
- const defaultWait = (milliseconds)=>new Promise((resolve)=>{
56
- setTimeout(resolve, milliseconds);
56
+ const defaultWait = (milliseconds)=>wait(milliseconds).then(()=>void 0);
57
+ const fetchWithTimeout = (fetchImpl, url, timeoutMs)=>fetchImpl(url, {
58
+ signal: AbortSignal.timeout(timeoutMs)
57
59
  });
58
- const fetchWithTimeout = async (fetchImpl, url, timeoutMs)=>{
59
- const controller = new AbortController();
60
- const timeout = setTimeout(()=>controller.abort(), timeoutMs);
61
- try {
62
- return await fetchImpl(url, {
63
- signal: controller.signal
64
- });
65
- } finally{
66
- clearTimeout(timeout);
67
- }
68
- };
69
60
  const createModuleFederationManifestRecoveryPlugin = (options = {})=>{
70
61
  const attempts = clampInteger(options.attempts, DEFAULT_ATTEMPTS, 1, MAX_ATTEMPTS);
71
62
  const retryDelayMs = clampInteger(options.retryDelayMs, DEFAULT_RETRY_DELAY_MS, 0, MAX_RETRY_DELAY_MS);
72
63
  const timeoutMs = clampInteger(options.timeoutMs, DEFAULT_TIMEOUT_MS, 1, MAX_TIMEOUT_MS);
73
64
  const fetchImpl = options.fetchImpl ?? globalThis.fetch;
74
65
  const waitImpl = options.waitImpl ?? defaultWait;
66
+ const recoverManifest = (url, attempt)=>{
67
+ const fetchManifest = ()=>Promise.resolve().then(()=>fetchWithTimeout(fetchImpl, url, timeoutMs)).then((response)=>{
68
+ if (!response.ok) {
69
+ if (!RETRYABLE_HTTP_STATUSES.has(response.status) || attempt === attempts - 1) return;
70
+ return recoverManifest(url, attempt + 1);
71
+ }
72
+ return Promise.resolve().then(()=>response.json()).then((manifest)=>manifest, ()=>void 0);
73
+ }, (error)=>{
74
+ if (!isRetryableError(error) || attempt === attempts - 1) return;
75
+ return recoverManifest(url, attempt + 1);
76
+ });
77
+ if (attempt > 0 && retryDelayMs > 0) return waitImpl(retryDelayMs).then(fetchManifest);
78
+ return fetchManifest();
79
+ };
75
80
  return {
76
81
  name: 'modern-js-manifest-recovery-plugin',
77
- async errorLoadRemote (args) {
78
- if ('afterResolve' !== args.lifecycle || !isHttpManifestUrl(args.id) || !isRetryableError(args.error) || 'function' != typeof fetchImpl) return;
79
- for(let attempt = 0; attempt < attempts; attempt++){
80
- if (attempt > 0 && retryDelayMs > 0) await waitImpl(retryDelayMs);
81
- try {
82
- const response = await fetchWithTimeout(fetchImpl, args.id, timeoutMs);
83
- if (!response.ok) {
84
- if (!RETRYABLE_HTTP_STATUSES.has(response.status) || attempt === attempts - 1) return;
85
- continue;
86
- }
87
- try {
88
- return await response.json();
89
- } catch {
90
- break;
91
- }
92
- } catch (error) {
93
- if (!isRetryableError(error) || attempt === attempts - 1) break;
94
- }
95
- }
82
+ errorLoadRemote (args) {
83
+ if ('afterResolve' !== args.lifecycle || !isHttpManifestUrl(args.id) || !isRetryableError(args.error) || 'function' != typeof fetchImpl) return Promise.resolve(void 0);
84
+ return recoverManifest(args.id, 0);
96
85
  }
97
86
  };
98
87
  };
@@ -40,8 +40,9 @@ async function generateRoutesForEntry(entrypoint, appContext) {
40
40
  }
41
41
  return routes;
42
42
  }
43
- const generateCode = async (appContext, config, entrypoints, api)=>{
43
+ const generateCode = async (appContext, config, entrypoints, api, options = {})=>{
44
44
  const { internalDirectory, srcDirectory, internalSrcAlias, packageName } = appContext;
45
+ const includeRouteServerLoadersInSsrEntry = false !== options.includeRouteServerLoadersInSsrEntry || !isUseRsc(config);
45
46
  const hooks = api.getHooks();
46
47
  const generatedRoutesByEntry = {};
47
48
  const eagerRouteComponentFilesByEntry = new Map();
@@ -99,6 +100,7 @@ const generateCode = async (appContext, config, entrypoints, api)=>{
99
100
  internalDirectory,
100
101
  splitRouteChunks: config?.output?.splitRouteChunks,
101
102
  isRscClientBundle: isUseRsc(config),
103
+ hydrateRscClientRoutes: options.hydrateRscClientRoutes,
102
104
  srcDirectory,
103
105
  internalSrcAlias: appContext.internalSrcAlias
104
106
  })
@@ -106,12 +108,14 @@ const generateCode = async (appContext, config, entrypoints, api)=>{
106
108
  if (entrypoint.nestedRoutesEntry && (isUseSSRBundle(config) || isUseRsc(config))) {
107
109
  const routesServerFile = getServerLoadersFile(internalDirectory, entryName);
108
110
  const filtedRoutesForServer = filterRoutesForServer(routes);
109
- const routesForServerLoaderMatches = filterRoutesLoader(routes);
110
- const code = __rspack_external__templates_mjs_ab577925.routesForServer({
111
- routesForServerLoaderMatches
112
- });
113
- await fs.ensureFile(routesServerFile);
114
- await fs.writeFile(routesServerFile, code);
111
+ if (includeRouteServerLoadersInSsrEntry) {
112
+ const routesForServerLoaderMatches = filterRoutesLoader(routes);
113
+ const code = __rspack_external__templates_mjs_ab577925.routesForServer({
114
+ routesForServerLoaderMatches
115
+ });
116
+ await fs.ensureFile(routesServerFile);
117
+ await fs.writeFile(routesServerFile, code);
118
+ } else await fs.remove(routesServerFile);
115
119
  const serverRoutesCode = await __rspack_external__templates_mjs_ab577925.fileSystemRoutes({
116
120
  metaName,
117
121
  routes: filtedRoutesForServer,
@@ -121,12 +125,15 @@ const generateCode = async (appContext, config, entrypoints, api)=>{
121
125
  internalDirectory,
122
126
  splitRouteChunks: config?.output?.splitRouteChunks,
123
127
  isRscClientBundle: false,
128
+ isolateRouteDataInRscLayer: isUseRsc(config) && options.isolateRouteDataInRscLayer,
124
129
  srcDirectory,
125
130
  internalSrcAlias: appContext.internalSrcAlias
126
131
  });
127
- await fs.outputFile(path.resolve(internalDirectory, `./${entryName}/routes.server.js`), serverRoutesCode, 'utf8');
132
+ await fs.outputFile(path.resolve(internalDirectory, `./${entryName}/${options.serverRoutesFileName || 'routes.server.js'}`), serverRoutesCode, 'utf8');
128
133
  }
129
- const serverLoaderCombined = __rspack_external__templates_mjs_ab577925.ssrLoaderCombinedModule(entrypoints, entrypoint, config, appContext);
134
+ const serverLoaderCombined = __rspack_external__templates_mjs_ab577925.ssrLoaderCombinedModule(entrypoints, entrypoint, config, appContext, {
135
+ includeRouteServerLoaders: includeRouteServerLoadersInSsrEntry
136
+ });
130
137
  if (serverLoaderCombined) {
131
138
  const serverLoaderFile = getServerCombinedModuleFile(internalDirectory, entryName);
132
139
  await fs.outputFile(serverLoaderFile, serverLoaderCombined);
@@ -91,7 +91,7 @@ async function hasUseClientDirective(componentPath, srcDirectory, internalSrcAli
91
91
  await fh?.close();
92
92
  }
93
93
  }
94
- const fileSystemRoutes = async ({ metaName, routes, ssrMode, nestedRoutesEntry, entryName, internalDirectory, splitRouteChunks = true, isRscClientBundle = false, srcDirectory, internalSrcAlias })=>{
94
+ const fileSystemRoutes = async ({ metaName, routes, ssrMode, nestedRoutesEntry, entryName, internalDirectory, splitRouteChunks = true, isRscClientBundle = false, hydrateRscClientRoutes = false, isolateRouteDataInRscLayer = false, srcDirectory, internalSrcAlias })=>{
95
95
  const components = [];
96
96
  const loadings = [];
97
97
  const errors = [];
@@ -163,7 +163,6 @@ const fileSystemRoutes = async ({ metaName, routes, ssrMode, nestedRoutesEntry,
163
163
  componentPath: route._component,
164
164
  routeId: route.id
165
165
  });
166
- rootLayoutCode = `import RootLayout from '${route._component}'`;
167
166
  component = 'RootLayout';
168
167
  } else if (splitRouteChunks) {
169
168
  lazyImport = createLazyImport({
@@ -184,8 +183,9 @@ const fileSystemRoutes = async ({ metaName, routes, ssrMode, nestedRoutesEntry,
184
183
  component = `component_${components.length - 1}`;
185
184
  }
186
185
  const isClientComponent = 'nested' === route.type && Boolean(route._component) && Boolean(srcDirectory) && Boolean(internalSrcAlias) && await hasUseClientDirective(route._component, srcDirectory, internalSrcAlias);
187
- const shouldHydrateRscRoute = isRscClientBundle && !isClientComponent && !route.loader && !route.data;
186
+ const shouldHydrateRscRoute = hydrateRscClientRoutes && isRscClientBundle && !isClientComponent && ('nested' !== route.type || !route.loader && !route.data);
188
187
  const shouldIncludeClientBundle = !isRscClientBundle || isClientComponent || shouldHydrateRscRoute;
188
+ if ('nested' === route.type && route.isRoot && route._component && shouldIncludeClientBundle) rootLayoutCode = `import RootLayout from '${route._component}'`;
189
189
  const finalRoute = {
190
190
  ...route,
191
191
  loading,
@@ -246,32 +246,30 @@ const fileSystemRoutes = async ({ metaName, routes, ssrMode, nestedRoutesEntry,
246
246
  const importComponentsCode = components.map((component, index)=>`import component_${index} from '${component}';\n`).join('');
247
247
  const importErrorComponentsCode = errors.map((error, index)=>`import error_${index} from '${error}';\n`).join('');
248
248
  let importLoadersCode = '';
249
- for (const [key, loaderInfo] of Object.entries(loadersMap))if (loaderInfo.inline) {
249
+ const isolatedRouteDataDirectory = path.join(internalDirectory, entryName, '__rsc_route_data__');
250
+ await fs.remove(isolatedRouteDataDirectory);
251
+ if (isolateRouteDataInRscLayer) await fs.ensureDir(isolatedRouteDataDirectory);
252
+ for (const [key, loaderInfo] of Object.entries(loadersMap)){
250
253
  const { route } = loaderInfo;
251
- if (route.action) importLoadersCode += `import { loader as ${key}, action as action_${loaderInfo.loaderId} } from "${slash(loaderInfo.filePath)}${getDataLoaderPath({
254
+ const loaderRequest = `${slash(loaderInfo.filePath)}${getDataLoaderPath({
252
255
  loaderId: key,
253
256
  clientData: loaderInfo.clientData,
254
- action: route.action,
257
+ action: route.action || false,
255
258
  inline: loaderInfo.inline,
256
259
  routeId: loaderInfo.routeId,
257
260
  inValidSSRRoute: loaderInfo.inValidSSRRoute
258
- })}";\n`;
259
- else importLoadersCode += `import { loader as ${key} } from "${slash(loaderInfo.filePath)}${getDataLoaderPath({
260
- loaderId: key,
261
- clientData: loaderInfo.clientData,
262
- action: false,
263
- inline: loaderInfo.inline,
264
- routeId: route.id,
265
- inValidSSRRoute: loaderInfo.inValidSSRRoute
266
- })}";\n`;
267
- } else importLoadersCode += `import ${key} from "${slash(loaderInfo.filePath)}${getDataLoaderPath({
268
- loaderId: key,
269
- clientData: loaderInfo.clientData,
270
- action: false,
271
- inline: loaderInfo.inline,
272
- routeId: loaderInfo.routeId,
273
- inValidSSRRoute: loaderInfo.inValidSSRRoute
274
- })}";\n`;
261
+ })}`;
262
+ let loaderImport = loaderRequest;
263
+ if (isolateRouteDataInRscLayer) {
264
+ const isolatedLoaderFile = path.join(isolatedRouteDataDirectory, `${key}.js`);
265
+ const isolatedLoaderCode = loaderInfo.inline ? route.action ? `export { loader, action } from ${JSON.stringify(loaderRequest)};` : `export { loader } from ${JSON.stringify(loaderRequest)};` : `export { default } from ${JSON.stringify(loaderRequest)};`;
266
+ await fs.outputFile(isolatedLoaderFile, isolatedLoaderCode, 'utf8');
267
+ loaderImport = `./__rsc_route_data__/${key}.js`;
268
+ }
269
+ if (loaderInfo.inline) if (route.action) importLoadersCode += `import { loader as ${key}, action as action_${loaderInfo.loaderId} } from "${loaderImport}";\n`;
270
+ else importLoadersCode += `import { loader as ${key} } from "${loaderImport}";\n`;
271
+ else importLoadersCode += `import ${key} from "${loaderImport}";\n`;
272
+ }
275
273
  let importConfigsCode = '';
276
274
  for (const [key, configPath] of Object.entries(configsMap))importConfigsCode += `import * as ${key} from "${slash(configPath)}";\n`;
277
275
  await fs.ensureFile(loadersMapFile);
@@ -297,7 +295,7 @@ const fileSystemRoutes = async ({ metaName, routes, ssrMode, nestedRoutesEntry,
297
295
  ${routeComponentsCode}
298
296
  `;
299
297
  };
300
- function ssrLoaderCombinedModule(entrypoints, entrypoint, config, appContext) {
298
+ function ssrLoaderCombinedModule(entrypoints, entrypoint, config, appContext, options = {}) {
301
299
  const { entryName, isMainEntry } = entrypoint;
302
300
  const { packageName } = appContext;
303
301
  const ssr = getEntryOptions(entryName, isMainEntry, config.server.ssr, config.server.ssrByEntries, packageName);
@@ -305,6 +303,17 @@ function ssrLoaderCombinedModule(entrypoints, entrypoint, config, appContext) {
305
303
  if (entrypoint.nestedRoutesEntry && (ssr || ssg)) {
306
304
  const serverLoaderRuntime = require.resolve('@modern-js/plugin-data-loader/runtime');
307
305
  const serverLoadersFile = './route-server-loaders.js';
306
+ const includeRouteServerLoaders = false !== options.includeRouteServerLoaders;
307
+ if (!includeRouteServerLoaders) {
308
+ if (!config.source.enableAsyncEntry) return `export * from "${slash(serverLoaderRuntime)}"`;
309
+ return `
310
+ async function loadModules() {
311
+ return import("${slash(serverLoaderRuntime)}");
312
+ }
313
+
314
+ export { loadModules };
315
+ `;
316
+ }
308
317
  const combinedModule = `export * from "${slash(serverLoaderRuntime)}"; export * from "${serverLoadersFile}"`;
309
318
  if (!config.source.enableAsyncEntry) return combinedModule;
310
319
  return `
@@ -325,7 +334,7 @@ function ssrLoaderCombinedModule(entrypoints, entrypoint, config, appContext) {
325
334
  }
326
335
  return null;
327
336
  }
328
- const runtimeGlobalContext = async ({ entryName, metaName, srcDirectory, nestedRoutesEntry, internalSrcAlias, globalApp, rscType = false, basename })=>{
337
+ const runtimeGlobalContext = async ({ entryName, metaName, srcDirectory, nestedRoutesEntry, internalSrcAlias, globalApp, rscType = false, routesImportPath = './routes', basename })=>{
329
338
  const imports = [
330
339
  `import { setGlobalContext } from '@${metaName}/runtime/context';`
331
340
  ];
@@ -356,7 +365,7 @@ const runtimeGlobalContext = async ({ entryName, metaName, srcDirectory, nestedR
356
365
  const enableRsc = Boolean(rscType);
357
366
  if (isClient) return `${imports.join('\n')}
358
367
 
359
- import { routes } from './routes';
368
+ import { routes } from '${routesImportPath}';
360
369
 
361
370
  const entryName = '${entryName}';
362
371
  const basename = '${basename || '/'}';
@@ -372,7 +381,7 @@ const runtimeGlobalContext = async ({ entryName, metaName, srcDirectory, nestedR
372
381
  `;
373
382
  return `${imports.join('\n')}
374
383
 
375
- import { routes } from './routes';
384
+ import { routes } from '${routesImportPath}';
376
385
 
377
386
  const entryName = '${entryName}';
378
387
  const basename = '${basename || '/'}';
@@ -21,7 +21,12 @@ async function handleGeneratorEntryCode(api, entrypoints, options = {}) {
21
21
  const { generatorRegisterCode, generateCode, generatorServerRegisterCode } = await import("./code/index.mjs");
22
22
  originEntrypointsByKey.set(entrypointsKey, cloneDeep(entrypoints));
23
23
  const enableRsc = resolvedConfig?.server?.rsc;
24
- const routesByEntry = await generateCode(appContext, resolvedConfig, entrypoints, api);
24
+ const routesByEntry = await generateCode(appContext, resolvedConfig, entrypoints, api, {
25
+ hydrateRscClientRoutes: normalizedOptions.hydrateRscClientRoutes,
26
+ includeRouteServerLoadersInSsrEntry: normalizedOptions.includeRouteServerLoadersInSsrEntry,
27
+ isolateRouteDataInRscLayer: normalizedOptions.isolateRouteDataInRscLayer,
28
+ serverRoutesFileName: normalizedOptions.serverRoutesFileName
29
+ });
25
30
  await Promise.all(entrypoints.map(async (entrypoint)=>{
26
31
  if (entrypoint.nestedRoutesEntry || entrypoint.pageRoutesEntry) {
27
32
  const route = appContext.serverRoutes.find((r)=>r.entryName === entrypoint.entryName);
@@ -44,6 +49,7 @@ async function handleGeneratorEntryCode(api, entrypoints, options = {}) {
44
49
  internalSrcAlias: appContext.internalSrcAlias,
45
50
  globalApp: entrypoint.fileSystemRoutes?.globalApp,
46
51
  rscType: 'server',
52
+ routesImportPath: normalizedOptions.serverRoutesFileName ? `./${normalizedOptions.serverRoutesFileName.replace(/\.js$/, '')}` : void 0,
47
53
  basename
48
54
  }));
49
55
  }
@@ -1,11 +1,12 @@
1
1
  import "node:module";
2
2
  import { Fragment, jsx, jsxs } from "react/jsx-runtime";
3
3
  import { merge } from "@modern-js/runtime-utils/merge";
4
- import { RouterProvider, createBrowserRouter, createHashRouter, createRoutesFromElements, useHref, useLocation, useMatches } from "@modern-js/runtime-utils/router";
4
+ import { RouterProvider, createBrowserRouter, createHashRouter, createRoutesFromElements, useHref, useInRouterContext, useLocation, useMatches, useNavigate, useParams } from "@modern-js/runtime-utils/router";
5
5
  import { normalizePathname } from "@modern-js/runtime-utils/url";
6
6
  import * as __rspack_external_react from "react";
7
- import { InternalRuntimeContext, getGlobalIsRscClient, getGlobalLayoutApp, getGlobalRoutes } from "../../core/context/index.mjs";
7
+ import { InternalRuntimeContext, getGlobalEnableRsc, getGlobalIsRscClient, getGlobalLayoutApp, getGlobalRoutes } from "../../core/context/index.mjs";
8
8
  import { applyRouterRuntimeState } from "./lifecycle.mjs";
9
+ import { Link } from "./PrefetchLink.mjs";
9
10
  import { routerProviderRegistryHooks } from "./provider.mjs";
10
11
  import { createClientRouterFromPayload } from "./rsc-router.mjs";
11
12
  import { createRouteObjectsFromConfig, deserializeErrors, renderRoutes, urlJoin } from "./utils.mjs";
@@ -39,9 +40,13 @@ const routerPlugin = (userConfig = {})=>({
39
40
  }
40
41
  }
41
42
  context.router = {
43
+ Link: Link,
42
44
  useMatches: useMatches,
43
45
  useLocation: useLocation,
44
- useHref: useHref
46
+ useHref: useHref,
47
+ useInRouterContext: useInRouterContext,
48
+ useNavigate: useNavigate,
49
+ useParams: useParams
45
50
  };
46
51
  Object.defineProperty(context, 'routes', {
47
52
  get () {
@@ -65,7 +70,7 @@ const routerPlugin = (userConfig = {})=>({
65
70
  };
66
71
  let cachedRouter = null;
67
72
  const RouterWrapper = (props)=>{
68
- const routerResult = useRouterCreation(process.env.MODERN_ENABLE_RSC ? {
73
+ const routerResult = useRouterCreation(("u" > typeof __MODERN_ENABLE_RSC__ ? __MODERN_ENABLE_RSC__ : true === getGlobalEnableRsc()) ? {
69
74
  ...props,
70
75
  rscPayload: props?.rscPayload
71
76
  } : props, {
@@ -83,18 +88,18 @@ const routerPlugin = (userConfig = {})=>({
83
88
  const { routes } = routerResult;
84
89
  routesContainer.current = routes;
85
90
  beforeCreateRouter = false;
86
- const RouterContent = ()=>/*#__PURE__*/ jsxs(Fragment, {
87
- children: [
88
- /*#__PURE__*/ jsx(RouterProvider, {
89
- router: router
90
- }),
91
- /*#__PURE__*/ jsx(EmptyComponent, {}),
92
- /*#__PURE__*/ jsx(EmptyComponent, {})
93
- ]
94
- });
91
+ const routerContent = /*#__PURE__*/ jsxs(Fragment, {
92
+ children: [
93
+ /*#__PURE__*/ jsx(RouterProvider, {
94
+ router: router
95
+ }),
96
+ /*#__PURE__*/ jsx(EmptyComponent, {}),
97
+ /*#__PURE__*/ jsx(EmptyComponent, {})
98
+ ]
99
+ });
95
100
  return App ? /*#__PURE__*/ jsx(App, {
96
- children: /*#__PURE__*/ jsx(RouterContent, {})
97
- }) : /*#__PURE__*/ jsx(RouterContent, {});
101
+ children: routerContent
102
+ }) : routerContent;
98
103
  };
99
104
  return RouterWrapper;
100
105
  });
@@ -122,15 +127,15 @@ function useRouterCreation(props, options) {
122
127
  const baseUrl = selectBasePath(location.pathname).replace(/^\/*/, '/');
123
128
  const _basename = '/' === baseUrl ? urlJoin(baseUrl, runtimeContext._internalRouterBaseName || basename || '') : baseUrl;
124
129
  const { unstable_getBlockNavState: getBlockNavState } = runtimeContext;
125
- const rscPayload = process.env.MODERN_ENABLE_RSC && props?.rscPayload ? safeUse(props.rscPayload) : null;
126
- let hydrationData = process.env.MODERN_ENABLE_RSC ? window._ROUTER_DATA || rscPayload : window._ROUTER_DATA;
130
+ const rscPayload = ("u" > typeof __MODERN_ENABLE_RSC__ ? __MODERN_ENABLE_RSC__ : true === getGlobalEnableRsc()) && props?.rscPayload ? safeUse(props.rscPayload) : null;
131
+ let hydrationData = "u" > typeof __MODERN_ENABLE_RSC__ ? __MODERN_ENABLE_RSC__ ? window._ROUTER_DATA || rscPayload : window._ROUTER_DATA : true === getGlobalEnableRsc() ? window._ROUTER_DATA || rscPayload : window._ROUTER_DATA;
127
132
  return (0, __rspack_external_react.useMemo)(()=>{
128
133
  if (hydrationData?.errors) hydrationData = {
129
134
  ...hydrationData,
130
135
  errors: deserializeErrors(hydrationData.errors)
131
136
  };
132
137
  let routes = null;
133
- routes = process.env.MODERN_ENABLE_RSC && getGlobalIsRscClient() ? createRoutes ? createRoutes() : createRouteObjectsFromConfig({
138
+ routes = ("u" > typeof __MODERN_ENABLE_RSC__ ? __MODERN_ENABLE_RSC__ : true === getGlobalEnableRsc()) && getGlobalIsRscClient() ? createRoutes ? createRoutes() : createRouteObjectsFromConfig({
134
139
  routesConfig: finalRouteConfig
135
140
  }) : createRoutes ? createRoutes() : createRoutesFromElements(renderRoutes({
136
141
  routesConfig: finalRouteConfig,
@@ -138,7 +143,7 @@ function useRouterCreation(props, options) {
138
143
  }));
139
144
  if (!routes) routes = [];
140
145
  const hooks = api.getHooks();
141
- if (process.env.MODERN_ENABLE_RSC && rscPayload) try {
146
+ if (("u" > typeof __MODERN_ENABLE_RSC__ ? __MODERN_ENABLE_RSC__ : true === getGlobalEnableRsc()) && rscPayload) try {
142
147
  const router = createClientRouterFromPayload(rscPayload, routes, _basename);
143
148
  return {
144
149
  router,
@@ -2,7 +2,7 @@ import "node:module";
2
2
  import { Fragment, jsx, jsxs } from "react/jsx-runtime";
3
3
  import { merge } from "@modern-js/runtime-utils/merge";
4
4
  import { createRequestContext } from "@modern-js/runtime-utils/node";
5
- import { StaticRouterProvider, createRoutesFromElements, createStaticHandler, createStaticRouter } from "@modern-js/runtime-utils/router";
5
+ import { StaticRouterProvider, createRoutesFromElements, createStaticHandler, createStaticRouter, useInRouterContext, useLocation, useNavigate, useParams } from "@modern-js/runtime-utils/router";
6
6
  import { time } from "@modern-js/runtime-utils/time";
7
7
  import { LOADER_REPORTER_NAME } from "@modern-js/utils/universal/constants";
8
8
  import { useContext } from "react";
@@ -10,6 +10,7 @@ import { InternalRuntimeContext, getGlobalEnableRsc, getGlobalLayoutApp, getGlob
10
10
  import { setServerPayload } from "../../core/context/serverPayload/index.server.mjs";
11
11
  import DeferredDataScripts_node from "./DeferredDataScripts.node.mjs";
12
12
  import { applyRouterRuntimeState, createRouterServerSnapshot } from "./lifecycle.mjs";
13
+ import { Link } from "./PrefetchLink.mjs";
13
14
  import { routerProviderRegistryHooks } from "./provider.mjs";
14
15
  import { RSCStaticRouter, createServerPayload, handleRSCRedirect, prepareRSCRoutes } from "./rsc-router.mjs";
15
16
  import { createRouteObjectsFromConfig, renderRoutes, urlJoin } from "./utils.mjs";
@@ -47,6 +48,13 @@ const routerPlugin = (userConfig = {})=>({
47
48
  setup: (api)=>{
48
49
  let finalRouteConfig = {};
49
50
  api.onBeforeRender(async (context, interrupt)=>{
51
+ context.router = {
52
+ Link: Link,
53
+ useInRouterContext: useInRouterContext,
54
+ useLocation: useLocation,
55
+ useNavigate: useNavigate,
56
+ useParams: useParams
57
+ };
50
58
  const pluginConfig = api.getRuntimeConfig();
51
59
  const { basename = '', routesConfig, createRoutes } = merge(pluginConfig.router || {}, userConfig);
52
60
  finalRouteConfig = {
@@ -135,10 +143,8 @@ const routerPlugin = (userConfig = {})=>({
135
143
  const enableRsc = getGlobalEnableRsc();
136
144
  return (props)=>{
137
145
  const context = useContext(InternalRuntimeContext);
138
- const { routerContext, ssrContext, routes } = context;
139
- const { nonce, mode, useJsonScript } = ssrContext;
146
+ const { routerContext, routes } = context;
140
147
  const { basename } = routerContext;
141
- const remixRouter = createStaticRouter(routes, routerContext);
142
148
  if (enableRsc) return App ? /*#__PURE__*/ jsx(App, {
143
149
  children: /*#__PURE__*/ jsx(RSCStaticRouter, {
144
150
  basename: basename
@@ -147,6 +153,8 @@ const routerPlugin = (userConfig = {})=>({
147
153
  basename: basename
148
154
  });
149
155
  {
156
+ const { nonce, mode, useJsonScript } = context.ssrContext;
157
+ const remixRouter = createStaticRouter(routes, routerContext);
150
158
  const routerWrapper = /*#__PURE__*/ jsxs(Fragment, {
151
159
  children: [
152
160
  /*#__PURE__*/ jsx(StaticRouterProvider, {
@@ -17,7 +17,7 @@ function createRouterProviderRealm(registrations) {
17
17
  const providers = new Map();
18
18
  let defaultProvider;
19
19
  for (const registration of registrations){
20
- if (!registration.name) throw new Error('[@modern-js/runtime] A router provider realm cannot contain an unnamed provider.');
20
+ if (0 === registration.name.length) throw new Error('[@modern-js/runtime] A router provider realm cannot contain an unnamed provider.');
21
21
  if (providers.has(registration.name)) throw new Error(`[@modern-js/runtime] Router provider "${registration.name}" is declared more than once in the same runtime realm.`);
22
22
  if (true === registration.isDefault && void 0 !== defaultProvider && defaultProvider !== registration.name) throw new Error(`[@modern-js/runtime] Router provider realm declares both "${defaultProvider}" and "${registration.name}" as defaults.`);
23
23
  providers.set(registration.name, registration.factory);
@@ -27,7 +27,7 @@ function createRouterProviderRealm(registrations) {
27
27
  ...providers.keys()
28
28
  ]);
29
29
  return Object.freeze({
30
- ...defaultProvider ? {
30
+ ...void 0 !== defaultProvider ? {
31
31
  defaultProvider
32
32
  } : {},
33
33
  get: (name)=>providers.get(name),
@@ -0,0 +1,14 @@
1
+ import "node:module";
2
+ const handleRSCRedirect = (headers, basename, status)=>{
3
+ const newHeaders = new Headers(headers);
4
+ let redirectUrl = headers.get('Location');
5
+ if ('/' !== basename) redirectUrl = redirectUrl.replace(basename, '');
6
+ newHeaders.set('X-Modernjs-Redirect', redirectUrl);
7
+ newHeaders.set('X-Modernjs-BaseUrl', basename);
8
+ newHeaders.delete('Location');
9
+ return new Response(null, {
10
+ status,
11
+ headers: newHeaders
12
+ });
13
+ };
14
+ export { handleRSCRedirect };
@@ -1,5 +1,6 @@
1
1
  import "node:module";
2
2
  import { ROUTE_MODULES } from "@modern-js/utils/universal/constants";
3
+ const isRouteErrorResponse = (error)=>null !== error && 'object' == typeof error && 'number' == typeof error.status && 'string' == typeof error.statusText && 'boolean' == typeof error.internal && 'data' in error;
3
4
  const isObjectLike = (value)=>'object' == typeof value && null !== value || 'function' == typeof value;
4
5
  const isRouteComponent = (value)=>'function' == typeof value || isObjectLike(value) && '$$typeof' in value;
5
6
  const getRouteModules = ()=>{
@@ -52,4 +53,4 @@ const handleRouteModuleError = (error)=>{
52
53
  console.error(error);
53
54
  return null;
54
55
  };
55
- export { createShouldRevalidate, handleRouteModule, handleRouteModuleError, resolveRouteComponent };
56
+ export { createShouldRevalidate, handleRouteModule, handleRouteModuleError, isRouteErrorResponse, resolveRouteComponent };
@@ -86,18 +86,6 @@ const createServerPayload = (routerContext, routes)=>{
86
86
  })
87
87
  };
88
88
  };
89
- const handleRSCRedirect = (headers, basename, status)=>{
90
- const newHeaders = new Headers(headers);
91
- let redirectUrl = headers.get('Location');
92
- if ('/' !== basename) redirectUrl = redirectUrl.replace(basename, '');
93
- newHeaders.set('X-Modernjs-Redirect', redirectUrl);
94
- newHeaders.set('X-Modernjs-BaseUrl', basename);
95
- newHeaders.delete('Location');
96
- return new Response(null, {
97
- status: status,
98
- headers: newHeaders
99
- });
100
- };
101
89
  const prepareRSCRoutes = async (routes)=>{
102
90
  const isLazyComponent = (component)=>null != component && 'object' == typeof component && '_init' in component && '_payload' in component;
103
91
  const processRoutes = async (routesList)=>{
@@ -326,4 +314,5 @@ const RSCStaticRouter = ({ basename })=>{
326
314
  children: createRSCStaticRouterComponent(payload, basename)
327
315
  });
328
316
  };
329
- export { RSCStaticRouter, createClientRouterFromPayload, createServerPayload, handleRSCRedirect, prepareRSCRoutes };
317
+ export { handleRSCRedirect } from "./redirect.mjs";
318
+ export { RSCStaticRouter, createClientRouterFromPayload, createServerPayload, prepareRSCRoutes };
@@ -1,10 +1,11 @@
1
1
  import "node:module";
2
2
  import { jsx } from "react/jsx-runtime";
3
3
  import { renderNestedRoute } from "@modern-js/runtime-utils/browser";
4
- import { Route, UNSAFE_ErrorResponseImpl, isRouteErrorResponse } from "@modern-js/runtime-utils/router";
4
+ import { Route, UNSAFE_ErrorResponseImpl } from "@modern-js/runtime-utils/router";
5
5
  import react from "react";
6
6
  import { DefaultNotFound } from "./DefaultNotFound.mjs";
7
7
  import DeferredDataScripts from "./DeferredDataScripts.mjs";
8
+ import { isRouteErrorResponse } from "./routerHelper.mjs";
8
9
  function getRouteComponents(routes, { globalApp, ssrMode, props }) {
9
10
  const Layout = ({ Component, ...props })=>{
10
11
  const GlobalLayout = globalApp;
@@ -1,6 +1,5 @@
1
1
  import type React from 'react';
2
2
  import { type Root } from 'react-dom/client';
3
3
  import type { TRuntimeContext } from '../context/runtime';
4
- export declare const isReact18: () => boolean;
5
4
  export declare function hydrateWithReact(App: React.ReactElement, rootElement: HTMLElement): Promise<Root>;
6
5
  export declare function hydrateRoot(App: React.ReactElement, context: TRuntimeContext, ModernRender: (App: React.ReactElement) => Promise<HTMLElement | Root>, ModernHydrate: (App: React.ReactElement, callback?: () => void) => Promise<HTMLElement | Root>): Promise<HTMLElement | Root>;
@@ -9,5 +9,4 @@ export declare function render(App: React.ReactElement<{
9
9
  export declare function createNestedAppRenderer(): RenderFunc;
10
10
  export declare function renderWithReact18(App: React.ReactElement, rootElement: HTMLElement): Promise<import("react-dom/client").Root>;
11
11
  export declare function renderWithReact17(App: React.ReactElement, rootElement: HTMLElement): Promise<HTMLElement>;
12
- export declare function hydrateWithReact18(App: React.ReactElement, rootElement: HTMLElement): Promise<import("react-dom/client").Root>;
13
12
  export declare function hydrateWithReact17(App: React.ReactElement, rootElement: HTMLElement, callback?: () => void): Promise<any>;
@@ -1,5 +1,5 @@
1
1
  import type { ServerUserConfig } from '@modern-js/app-tools';
2
- import { type StaticHandlerContext } from '@modern-js/runtime-utils/router';
2
+ import type { StaticHandlerContext } from '@modern-js/runtime-utils/router';
3
3
  import type { SSRConfig } from './shared';
4
4
  export declare function attributesToString(attributes: Record<string, any>): string;
5
5
  /**
@@ -1,5 +1,6 @@
1
1
  import type { AppTools, CliPlugin } from '@modern-js/app-tools';
2
2
  import type { Entrypoint } from '@modern-js/types/cli';
3
+ export declare const processScriptPlaceholders: (html: string, nonce?: string) => string;
3
4
  export declare const getDocumentByEntryName: (entrypoints: Entrypoint[], entryName: string, fallbackDir?: string) => string | undefined;
4
5
  export declare const documentPlugin: () => CliPlugin<AppTools>;
5
6
  export default documentPlugin;