@bleedingdev/modern-js-runtime 3.5.0-ultramodern.102 → 3.5.0-ultramodern.103

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 (72) hide show
  1. package/dist/cjs/cli/ssr/index.js +1 -0
  2. package/dist/cjs/core/browser/hydrate.js +31 -27
  3. package/dist/cjs/core/react/wrapper.js +23 -28
  4. package/dist/cjs/core/server/requestResponse.js +5 -5
  5. package/dist/cjs/core/server/scriptOrder.js +1 -1
  6. package/dist/cjs/core/server/stream/beforeTemplate.worker.js +1 -10
  7. package/dist/cjs/core/server/utils.js +3 -3
  8. package/dist/cjs/module-federation/distributed-ssr.js +13 -12
  9. package/dist/cjs/module-federation/last-known-good.js +1 -1
  10. package/dist/cjs/module-federation/manifest-recovery-runtime-plugin.js +27 -38
  11. package/dist/cjs/router/cli/code/index.js +13 -7
  12. package/dist/cjs/router/cli/code/templates.js +33 -24
  13. package/dist/cjs/router/cli/handler.js +2 -0
  14. package/dist/cjs/router/runtime/plugin.js +11 -6
  15. package/dist/cjs/router/runtime/plugin.node.js +11 -3
  16. package/dist/cjs/router/runtime/provider.js +2 -2
  17. package/dist/cjs/router/runtime/redirect.js +51 -0
  18. package/dist/cjs/router/runtime/routerHelper.js +4 -0
  19. package/dist/cjs/router/runtime/rsc-router.js +2 -13
  20. package/dist/cjs/router/runtime/utils.js +3 -2
  21. package/dist/esm/cli/ssr/index.mjs +1 -0
  22. package/dist/esm/core/browser/hydrate.mjs +30 -22
  23. package/dist/esm/core/react/wrapper.mjs +23 -28
  24. package/dist/esm/core/server/requestResponse.mjs +4 -4
  25. package/dist/esm/core/server/scriptOrder.mjs +1 -1
  26. package/dist/esm/core/server/stream/beforeTemplate.worker.mjs +1 -10
  27. package/dist/esm/core/server/utils.mjs +1 -1
  28. package/dist/esm/module-federation/distributed-ssr.mjs +13 -12
  29. package/dist/esm/module-federation/last-known-good.mjs +1 -1
  30. package/dist/esm/module-federation/manifest-recovery-runtime-plugin.mjs +22 -33
  31. package/dist/esm/router/cli/code/index.mjs +13 -7
  32. package/dist/esm/router/cli/code/templates.mjs +33 -24
  33. package/dist/esm/router/cli/handler.mjs +2 -0
  34. package/dist/esm/router/runtime/plugin.mjs +13 -8
  35. package/dist/esm/router/runtime/plugin.node.mjs +12 -4
  36. package/dist/esm/router/runtime/provider.mjs +2 -2
  37. package/dist/esm/router/runtime/redirect.mjs +13 -0
  38. package/dist/esm/router/runtime/routerHelper.mjs +2 -1
  39. package/dist/esm/router/runtime/rsc-router.mjs +2 -13
  40. package/dist/esm/router/runtime/utils.mjs +2 -1
  41. package/dist/esm-node/cli/ssr/index.mjs +1 -0
  42. package/dist/esm-node/core/browser/hydrate.mjs +30 -22
  43. package/dist/esm-node/core/react/wrapper.mjs +23 -28
  44. package/dist/esm-node/core/server/requestResponse.mjs +4 -4
  45. package/dist/esm-node/core/server/scriptOrder.mjs +1 -1
  46. package/dist/esm-node/core/server/stream/beforeTemplate.worker.mjs +1 -10
  47. package/dist/esm-node/core/server/utils.mjs +1 -1
  48. package/dist/esm-node/module-federation/distributed-ssr.mjs +13 -12
  49. package/dist/esm-node/module-federation/last-known-good.mjs +1 -1
  50. package/dist/esm-node/module-federation/manifest-recovery-runtime-plugin.mjs +22 -33
  51. package/dist/esm-node/router/cli/code/index.mjs +13 -7
  52. package/dist/esm-node/router/cli/code/templates.mjs +33 -24
  53. package/dist/esm-node/router/cli/handler.mjs +2 -0
  54. package/dist/esm-node/router/runtime/plugin.mjs +13 -8
  55. package/dist/esm-node/router/runtime/plugin.node.mjs +12 -4
  56. package/dist/esm-node/router/runtime/provider.mjs +2 -2
  57. package/dist/esm-node/router/runtime/redirect.mjs +14 -0
  58. package/dist/esm-node/router/runtime/routerHelper.mjs +2 -1
  59. package/dist/esm-node/router/runtime/rsc-router.mjs +2 -13
  60. package/dist/esm-node/router/runtime/utils.mjs +2 -1
  61. package/dist/types/core/browser/hydrate.d.ts +0 -1
  62. package/dist/types/core/server/utils.d.ts +1 -1
  63. package/dist/types/module-federation/distributed-ssr.d.ts +3 -3
  64. package/dist/types/module-federation/manifest-recovery-runtime-plugin.d.ts +1 -1
  65. package/dist/types/router/cli/code/index.d.ts +2 -0
  66. package/dist/types/router/cli/code/templates.d.ts +5 -2
  67. package/dist/types/router/cli/handler.d.ts +2 -0
  68. package/dist/types/router/runtime/redirect.d.ts +1 -0
  69. package/dist/types/router/runtime/routerHelper.d.ts +7 -0
  70. package/dist/types/router/runtime/rsc-router.d.ts +1 -2
  71. package/package.json +14 -14
  72. package/rstest.config.mts +2 -0
@@ -1,3 +1,4 @@
1
+ import { wait } from "@modern-js/utils/universal";
1
2
  const DEFAULT_ATTEMPTS = 3;
2
3
  const DEFAULT_RETRY_DELAY_MS = 100;
3
4
  const DEFAULT_TIMEOUT_MS = 1000;
@@ -43,7 +44,7 @@ const isRetryableError = (error)=>{
43
44
  return error instanceof TypeError || /(?:fetch failed|network|ECONNREFUSED|ECONNRESET|ETIMEDOUT|EAI_AGAIN)/i.test(message);
44
45
  };
45
46
  const isHttpManifestUrl = (id)=>{
46
- if (!id) return false;
47
+ if (void 0 === id || 0 === id.length) return false;
47
48
  try {
48
49
  const url = new URL(id);
49
50
  return ('http:' === url.protocol || 'https:' === url.protocol) && url.pathname.endsWith('.json');
@@ -51,47 +52,35 @@ const isHttpManifestUrl = (id)=>{
51
52
  return false;
52
53
  }
53
54
  };
54
- const defaultWait = (milliseconds)=>new Promise((resolve)=>{
55
- setTimeout(resolve, milliseconds);
55
+ const defaultWait = (milliseconds)=>wait(milliseconds).then(()=>void 0);
56
+ const fetchWithTimeout = (fetchImpl, url, timeoutMs)=>fetchImpl(url, {
57
+ signal: AbortSignal.timeout(timeoutMs)
56
58
  });
57
- const fetchWithTimeout = async (fetchImpl, url, timeoutMs)=>{
58
- const controller = new AbortController();
59
- const timeout = setTimeout(()=>controller.abort(), timeoutMs);
60
- try {
61
- return await fetchImpl(url, {
62
- signal: controller.signal
63
- });
64
- } finally{
65
- clearTimeout(timeout);
66
- }
67
- };
68
59
  const createModuleFederationManifestRecoveryPlugin = (options = {})=>{
69
60
  const attempts = clampInteger(options.attempts, DEFAULT_ATTEMPTS, 1, MAX_ATTEMPTS);
70
61
  const retryDelayMs = clampInteger(options.retryDelayMs, DEFAULT_RETRY_DELAY_MS, 0, MAX_RETRY_DELAY_MS);
71
62
  const timeoutMs = clampInteger(options.timeoutMs, DEFAULT_TIMEOUT_MS, 1, MAX_TIMEOUT_MS);
72
63
  const fetchImpl = options.fetchImpl ?? globalThis.fetch;
73
64
  const waitImpl = options.waitImpl ?? defaultWait;
65
+ const recoverManifest = (url, attempt)=>{
66
+ const fetchManifest = ()=>Promise.resolve().then(()=>fetchWithTimeout(fetchImpl, url, timeoutMs)).then((response)=>{
67
+ if (!response.ok) {
68
+ if (!RETRYABLE_HTTP_STATUSES.has(response.status) || attempt === attempts - 1) return;
69
+ return recoverManifest(url, attempt + 1);
70
+ }
71
+ return Promise.resolve().then(()=>response.json()).then((manifest)=>manifest, ()=>void 0);
72
+ }, (error)=>{
73
+ if (!isRetryableError(error) || attempt === attempts - 1) return;
74
+ return recoverManifest(url, attempt + 1);
75
+ });
76
+ if (attempt > 0 && retryDelayMs > 0) return waitImpl(retryDelayMs).then(fetchManifest);
77
+ return fetchManifest();
78
+ };
74
79
  return {
75
80
  name: 'modern-js-manifest-recovery-plugin',
76
- async errorLoadRemote (args) {
77
- if ('afterResolve' !== args.lifecycle || !isHttpManifestUrl(args.id) || !isRetryableError(args.error) || 'function' != typeof fetchImpl) return;
78
- for(let attempt = 0; attempt < attempts; attempt++){
79
- if (attempt > 0 && retryDelayMs > 0) await waitImpl(retryDelayMs);
80
- try {
81
- const response = await fetchWithTimeout(fetchImpl, args.id, timeoutMs);
82
- if (!response.ok) {
83
- if (!RETRYABLE_HTTP_STATUSES.has(response.status) || attempt === attempts - 1) return;
84
- continue;
85
- }
86
- try {
87
- return await response.json();
88
- } catch {
89
- break;
90
- }
91
- } catch (error) {
92
- if (!isRetryableError(error) || attempt === attempts - 1) break;
93
- }
94
- }
81
+ errorLoadRemote (args) {
82
+ if ('afterResolve' !== args.lifecycle || !isHttpManifestUrl(args.id) || !isRetryableError(args.error) || 'function' != typeof fetchImpl) return Promise.resolve(void 0);
83
+ return recoverManifest(args.id, 0);
95
84
  }
96
85
  };
97
86
  };
@@ -41,6 +41,7 @@ async function generateRoutesForEntry(entrypoint, appContext) {
41
41
  }
42
42
  const generateCode = async (appContext, config, entrypoints, api, options = {})=>{
43
43
  const { internalDirectory, srcDirectory, internalSrcAlias, packageName } = appContext;
44
+ const includeRouteServerLoadersInSsrEntry = false !== options.includeRouteServerLoadersInSsrEntry || !isUseRsc(config);
44
45
  const hooks = api.getHooks();
45
46
  const generatedRoutesByEntry = {};
46
47
  const eagerRouteComponentFilesByEntry = new Map();
@@ -106,12 +107,14 @@ const generateCode = async (appContext, config, entrypoints, api, options = {})=
106
107
  if (entrypoint.nestedRoutesEntry && (isUseSSRBundle(config) || isUseRsc(config))) {
107
108
  const routesServerFile = getServerLoadersFile(internalDirectory, entryName);
108
109
  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);
110
+ if (includeRouteServerLoadersInSsrEntry) {
111
+ const routesForServerLoaderMatches = filterRoutesLoader(routes);
112
+ const code = __rspack_external__templates_mjs_ab577925.routesForServer({
113
+ routesForServerLoaderMatches
114
+ });
115
+ await fs.ensureFile(routesServerFile);
116
+ await fs.writeFile(routesServerFile, code);
117
+ } else await fs.remove(routesServerFile);
115
118
  const serverRoutesCode = await __rspack_external__templates_mjs_ab577925.fileSystemRoutes({
116
119
  metaName,
117
120
  routes: filtedRoutesForServer,
@@ -121,12 +124,15 @@ const generateCode = async (appContext, config, entrypoints, api, options = {})=
121
124
  internalDirectory,
122
125
  splitRouteChunks: config?.output?.splitRouteChunks,
123
126
  isRscClientBundle: false,
127
+ isolateRouteDataInRscLayer: isUseRsc(config) && options.isolateRouteDataInRscLayer,
124
128
  srcDirectory,
125
129
  internalSrcAlias: appContext.internalSrcAlias
126
130
  });
127
131
  await fs.outputFile(path.resolve(internalDirectory, `./${entryName}/${options.serverRoutesFileName || 'routes.server.js'}`), serverRoutesCode, 'utf8');
128
132
  }
129
- const serverLoaderCombined = __rspack_external__templates_mjs_ab577925.ssrLoaderCombinedModule(entrypoints, entrypoint, config, appContext);
133
+ const serverLoaderCombined = __rspack_external__templates_mjs_ab577925.ssrLoaderCombinedModule(entrypoints, entrypoint, config, appContext, {
134
+ includeRouteServerLoaders: includeRouteServerLoadersInSsrEntry
135
+ });
130
136
  if (serverLoaderCombined) {
131
137
  const serverLoaderFile = getServerCombinedModuleFile(internalDirectory, entryName);
132
138
  await fs.outputFile(serverLoaderFile, serverLoaderCombined);
@@ -89,7 +89,7 @@ async function hasUseClientDirective(componentPath, srcDirectory, internalSrcAli
89
89
  await fh?.close();
90
90
  }
91
91
  }
92
- const fileSystemRoutes = async ({ metaName, routes, ssrMode, nestedRoutesEntry, entryName, internalDirectory, splitRouteChunks = true, isRscClientBundle = false, hydrateRscClientRoutes = false, srcDirectory, internalSrcAlias })=>{
92
+ const fileSystemRoutes = async ({ metaName, routes, ssrMode, nestedRoutesEntry, entryName, internalDirectory, splitRouteChunks = true, isRscClientBundle = false, hydrateRscClientRoutes = false, isolateRouteDataInRscLayer = false, srcDirectory, internalSrcAlias })=>{
93
93
  const components = [];
94
94
  const loadings = [];
95
95
  const errors = [];
@@ -181,9 +181,9 @@ const fileSystemRoutes = async ({ metaName, routes, ssrMode, nestedRoutesEntry,
181
181
  component = `component_${components.length - 1}`;
182
182
  }
183
183
  const isClientComponent = 'nested' === route.type && Boolean(route._component) && Boolean(srcDirectory) && Boolean(internalSrcAlias) && await hasUseClientDirective(route._component, srcDirectory, internalSrcAlias);
184
- const shouldHydrateRscRoute = hydrateRscClientRoutes && isRscClientBundle && !isClientComponent && !route.loader && !route.data;
184
+ const shouldHydrateRscRoute = hydrateRscClientRoutes && isRscClientBundle && !isClientComponent && ('nested' !== route.type || !route.loader && !route.data);
185
185
  const shouldIncludeClientBundle = !isRscClientBundle || isClientComponent || shouldHydrateRscRoute;
186
- if (route.isRoot && route._component && shouldIncludeClientBundle) rootLayoutCode = `import RootLayout from '${route._component}'`;
186
+ if ('nested' === route.type && route.isRoot && route._component && shouldIncludeClientBundle) rootLayoutCode = `import RootLayout from '${route._component}'`;
187
187
  const finalRoute = {
188
188
  ...route,
189
189
  loading,
@@ -244,32 +244,30 @@ const fileSystemRoutes = async ({ metaName, routes, ssrMode, nestedRoutesEntry,
244
244
  const importComponentsCode = components.map((component, index)=>`import component_${index} from '${component}';\n`).join('');
245
245
  const importErrorComponentsCode = errors.map((error, index)=>`import error_${index} from '${error}';\n`).join('');
246
246
  let importLoadersCode = '';
247
- for (const [key, loaderInfo] of Object.entries(loadersMap))if (loaderInfo.inline) {
247
+ const isolatedRouteDataDirectory = path.join(internalDirectory, entryName, '__rsc_route_data__');
248
+ await fs.remove(isolatedRouteDataDirectory);
249
+ if (isolateRouteDataInRscLayer) await fs.ensureDir(isolatedRouteDataDirectory);
250
+ for (const [key, loaderInfo] of Object.entries(loadersMap)){
248
251
  const { route } = loaderInfo;
249
- if (route.action) importLoadersCode += `import { loader as ${key}, action as action_${loaderInfo.loaderId} } from "${slash(loaderInfo.filePath)}${getDataLoaderPath({
252
+ const loaderRequest = `${slash(loaderInfo.filePath)}${getDataLoaderPath({
250
253
  loaderId: key,
251
254
  clientData: loaderInfo.clientData,
252
- action: route.action,
255
+ action: route.action || false,
253
256
  inline: loaderInfo.inline,
254
257
  routeId: loaderInfo.routeId,
255
258
  inValidSSRRoute: loaderInfo.inValidSSRRoute
256
- })}";\n`;
257
- else importLoadersCode += `import { loader as ${key} } from "${slash(loaderInfo.filePath)}${getDataLoaderPath({
258
- loaderId: key,
259
- clientData: loaderInfo.clientData,
260
- action: false,
261
- inline: loaderInfo.inline,
262
- routeId: route.id,
263
- inValidSSRRoute: loaderInfo.inValidSSRRoute
264
- })}";\n`;
265
- } else importLoadersCode += `import ${key} from "${slash(loaderInfo.filePath)}${getDataLoaderPath({
266
- loaderId: key,
267
- clientData: loaderInfo.clientData,
268
- action: false,
269
- inline: loaderInfo.inline,
270
- routeId: loaderInfo.routeId,
271
- inValidSSRRoute: loaderInfo.inValidSSRRoute
272
- })}";\n`;
259
+ })}`;
260
+ let loaderImport = loaderRequest;
261
+ if (isolateRouteDataInRscLayer) {
262
+ const isolatedLoaderFile = path.join(isolatedRouteDataDirectory, `${key}.js`);
263
+ const isolatedLoaderCode = loaderInfo.inline ? route.action ? `export { loader, action } from ${JSON.stringify(loaderRequest)};` : `export { loader } from ${JSON.stringify(loaderRequest)};` : `export { default } from ${JSON.stringify(loaderRequest)};`;
264
+ await fs.outputFile(isolatedLoaderFile, isolatedLoaderCode, 'utf8');
265
+ loaderImport = `./__rsc_route_data__/${key}.js`;
266
+ }
267
+ if (loaderInfo.inline) if (route.action) importLoadersCode += `import { loader as ${key}, action as action_${loaderInfo.loaderId} } from "${loaderImport}";\n`;
268
+ else importLoadersCode += `import { loader as ${key} } from "${loaderImport}";\n`;
269
+ else importLoadersCode += `import ${key} from "${loaderImport}";\n`;
270
+ }
273
271
  let importConfigsCode = '';
274
272
  for (const [key, configPath] of Object.entries(configsMap))importConfigsCode += `import * as ${key} from "${slash(configPath)}";\n`;
275
273
  await fs.ensureFile(loadersMapFile);
@@ -295,7 +293,7 @@ const fileSystemRoutes = async ({ metaName, routes, ssrMode, nestedRoutesEntry,
295
293
  ${routeComponentsCode}
296
294
  `;
297
295
  };
298
- function ssrLoaderCombinedModule(entrypoints, entrypoint, config, appContext) {
296
+ function ssrLoaderCombinedModule(entrypoints, entrypoint, config, appContext, options = {}) {
299
297
  const { entryName, isMainEntry } = entrypoint;
300
298
  const { packageName } = appContext;
301
299
  const ssr = getEntryOptions(entryName, isMainEntry, config.server.ssr, config.server.ssrByEntries, packageName);
@@ -303,6 +301,17 @@ function ssrLoaderCombinedModule(entrypoints, entrypoint, config, appContext) {
303
301
  if (entrypoint.nestedRoutesEntry && (ssr || ssg)) {
304
302
  const serverLoaderRuntime = require.resolve('@modern-js/plugin-data-loader/runtime');
305
303
  const serverLoadersFile = './route-server-loaders.js';
304
+ const includeRouteServerLoaders = false !== options.includeRouteServerLoaders;
305
+ if (!includeRouteServerLoaders) {
306
+ if (!config.source.enableAsyncEntry) return `export * from "${slash(serverLoaderRuntime)}"`;
307
+ return `
308
+ async function loadModules() {
309
+ return import("${slash(serverLoaderRuntime)}");
310
+ }
311
+
312
+ export { loadModules };
313
+ `;
314
+ }
306
315
  const combinedModule = `export * from "${slash(serverLoaderRuntime)}"; export * from "${serverLoadersFile}"`;
307
316
  if (!config.source.enableAsyncEntry) return combinedModule;
308
317
  return `
@@ -22,6 +22,8 @@ async function handleGeneratorEntryCode(api, entrypoints, options = {}) {
22
22
  const enableRsc = resolvedConfig?.server?.rsc;
23
23
  const routesByEntry = await generateCode(appContext, resolvedConfig, entrypoints, api, {
24
24
  hydrateRscClientRoutes: normalizedOptions.hydrateRscClientRoutes,
25
+ includeRouteServerLoadersInSsrEntry: normalizedOptions.includeRouteServerLoadersInSsrEntry,
26
+ isolateRouteDataInRscLayer: normalizedOptions.isolateRouteDataInRscLayer,
25
27
  serverRoutesFileName: normalizedOptions.serverRoutesFileName
26
28
  });
27
29
  await Promise.all(entrypoints.map(async (entrypoint)=>{
@@ -1,10 +1,11 @@
1
1
  import { Fragment, jsx, jsxs } from "react/jsx-runtime";
2
2
  import { merge } from "@modern-js/runtime-utils/merge";
3
- import { RouterProvider, createBrowserRouter, createHashRouter, createRoutesFromElements, useHref, useLocation, useMatches } from "@modern-js/runtime-utils/router";
3
+ import { RouterProvider, createBrowserRouter, createHashRouter, createRoutesFromElements, useHref, useInRouterContext, useLocation, useMatches, useNavigate, useParams } from "@modern-js/runtime-utils/router";
4
4
  import { normalizePathname } from "@modern-js/runtime-utils/url";
5
5
  import * as __rspack_external_react from "react";
6
- import { InternalRuntimeContext, getGlobalIsRscClient, getGlobalLayoutApp, getGlobalRoutes } from "../../core/context/index.mjs";
6
+ import { InternalRuntimeContext, getGlobalEnableRsc, getGlobalIsRscClient, getGlobalLayoutApp, getGlobalRoutes } from "../../core/context/index.mjs";
7
7
  import { applyRouterRuntimeState } from "./lifecycle.mjs";
8
+ import { Link } from "./PrefetchLink.mjs";
8
9
  import { routerProviderRegistryHooks } from "./provider.mjs";
9
10
  import { createClientRouterFromPayload } from "./rsc-router.mjs";
10
11
  import { createRouteObjectsFromConfig, deserializeErrors, renderRoutes, urlJoin } from "./utils.mjs";
@@ -38,9 +39,13 @@ const routerPlugin = (userConfig = {})=>({
38
39
  }
39
40
  }
40
41
  context.router = {
42
+ Link: Link,
41
43
  useMatches: useMatches,
42
44
  useLocation: useLocation,
43
- useHref: useHref
45
+ useHref: useHref,
46
+ useInRouterContext: useInRouterContext,
47
+ useNavigate: useNavigate,
48
+ useParams: useParams
44
49
  };
45
50
  Object.defineProperty(context, 'routes', {
46
51
  get () {
@@ -64,7 +69,7 @@ const routerPlugin = (userConfig = {})=>({
64
69
  };
65
70
  let cachedRouter = null;
66
71
  const RouterWrapper = (props)=>{
67
- const routerResult = useRouterCreation(process.env.MODERN_ENABLE_RSC ? {
72
+ const routerResult = useRouterCreation(("u" > typeof __MODERN_ENABLE_RSC__ ? __MODERN_ENABLE_RSC__ : true === getGlobalEnableRsc()) ? {
68
73
  ...props,
69
74
  rscPayload: props?.rscPayload
70
75
  } : props, {
@@ -121,15 +126,15 @@ function useRouterCreation(props, options) {
121
126
  const baseUrl = selectBasePath(location.pathname).replace(/^\/*/, '/');
122
127
  const _basename = '/' === baseUrl ? urlJoin(baseUrl, runtimeContext._internalRouterBaseName || basename || '') : baseUrl;
123
128
  const { unstable_getBlockNavState: getBlockNavState } = runtimeContext;
124
- const rscPayload = process.env.MODERN_ENABLE_RSC && props?.rscPayload ? safeUse(props.rscPayload) : null;
125
- let hydrationData = process.env.MODERN_ENABLE_RSC ? window._ROUTER_DATA || rscPayload : window._ROUTER_DATA;
129
+ const rscPayload = ("u" > typeof __MODERN_ENABLE_RSC__ ? __MODERN_ENABLE_RSC__ : true === getGlobalEnableRsc()) && props?.rscPayload ? safeUse(props.rscPayload) : null;
130
+ 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;
126
131
  return (0, __rspack_external_react.useMemo)(()=>{
127
132
  if (hydrationData?.errors) hydrationData = {
128
133
  ...hydrationData,
129
134
  errors: deserializeErrors(hydrationData.errors)
130
135
  };
131
136
  let routes = null;
132
- routes = process.env.MODERN_ENABLE_RSC && getGlobalIsRscClient() ? createRoutes ? createRoutes() : createRouteObjectsFromConfig({
137
+ routes = ("u" > typeof __MODERN_ENABLE_RSC__ ? __MODERN_ENABLE_RSC__ : true === getGlobalEnableRsc()) && getGlobalIsRscClient() ? createRoutes ? createRoutes() : createRouteObjectsFromConfig({
133
138
  routesConfig: finalRouteConfig
134
139
  }) : createRoutes ? createRoutes() : createRoutesFromElements(renderRoutes({
135
140
  routesConfig: finalRouteConfig,
@@ -137,7 +142,7 @@ function useRouterCreation(props, options) {
137
142
  }));
138
143
  if (!routes) routes = [];
139
144
  const hooks = api.getHooks();
140
- if (process.env.MODERN_ENABLE_RSC && rscPayload) try {
145
+ if (("u" > typeof __MODERN_ENABLE_RSC__ ? __MODERN_ENABLE_RSC__ : true === getGlobalEnableRsc()) && rscPayload) try {
141
146
  const router = createClientRouterFromPayload(rscPayload, routes, _basename);
142
147
  return {
143
148
  router,
@@ -1,7 +1,7 @@
1
1
  import { Fragment, jsx, jsxs } from "react/jsx-runtime";
2
2
  import { merge } from "@modern-js/runtime-utils/merge";
3
3
  import { createRequestContext } from "@modern-js/runtime-utils/node";
4
- import { StaticRouterProvider, createRoutesFromElements, createStaticHandler, createStaticRouter } from "@modern-js/runtime-utils/router";
4
+ import { StaticRouterProvider, createRoutesFromElements, createStaticHandler, createStaticRouter, useInRouterContext, useLocation, useNavigate, useParams } from "@modern-js/runtime-utils/router";
5
5
  import { time } from "@modern-js/runtime-utils/time";
6
6
  import { LOADER_REPORTER_NAME } from "@modern-js/utils/universal/constants";
7
7
  import { useContext } from "react";
@@ -9,6 +9,7 @@ import { InternalRuntimeContext, getGlobalEnableRsc, getGlobalLayoutApp, getGlob
9
9
  import { setServerPayload } from "../../core/context/serverPayload/index.server.mjs";
10
10
  import DeferredDataScripts_node from "./DeferredDataScripts.node.mjs";
11
11
  import { applyRouterRuntimeState, createRouterServerSnapshot } from "./lifecycle.mjs";
12
+ import { Link } from "./PrefetchLink.mjs";
12
13
  import { routerProviderRegistryHooks } from "./provider.mjs";
13
14
  import { RSCStaticRouter, createServerPayload, handleRSCRedirect, prepareRSCRoutes } from "./rsc-router.mjs";
14
15
  import { createRouteObjectsFromConfig, renderRoutes, urlJoin } from "./utils.mjs";
@@ -46,6 +47,13 @@ const routerPlugin = (userConfig = {})=>({
46
47
  setup: (api)=>{
47
48
  let finalRouteConfig = {};
48
49
  api.onBeforeRender(async (context, interrupt)=>{
50
+ context.router = {
51
+ Link: Link,
52
+ useInRouterContext: useInRouterContext,
53
+ useLocation: useLocation,
54
+ useNavigate: useNavigate,
55
+ useParams: useParams
56
+ };
49
57
  const pluginConfig = api.getRuntimeConfig();
50
58
  const { basename = '', routesConfig, createRoutes } = merge(pluginConfig.router || {}, userConfig);
51
59
  finalRouteConfig = {
@@ -134,10 +142,8 @@ const routerPlugin = (userConfig = {})=>({
134
142
  const enableRsc = getGlobalEnableRsc();
135
143
  return (props)=>{
136
144
  const context = useContext(InternalRuntimeContext);
137
- const { routerContext, ssrContext, routes } = context;
138
- const { nonce, mode, useJsonScript } = ssrContext;
145
+ const { routerContext, routes } = context;
139
146
  const { basename } = routerContext;
140
- const remixRouter = createStaticRouter(routes, routerContext);
141
147
  if (enableRsc) return App ? /*#__PURE__*/ jsx(App, {
142
148
  children: /*#__PURE__*/ jsx(RSCStaticRouter, {
143
149
  basename: basename
@@ -146,6 +152,8 @@ const routerPlugin = (userConfig = {})=>({
146
152
  basename: basename
147
153
  });
148
154
  {
155
+ const { nonce, mode, useJsonScript } = context.ssrContext;
156
+ const remixRouter = createStaticRouter(routes, routerContext);
149
157
  const routerWrapper = /*#__PURE__*/ jsxs(Fragment, {
150
158
  children: [
151
159
  /*#__PURE__*/ jsx(StaticRouterProvider, {
@@ -16,7 +16,7 @@ function createRouterProviderRealm(registrations) {
16
16
  const providers = new Map();
17
17
  let defaultProvider;
18
18
  for (const registration of registrations){
19
- if (!registration.name) throw new Error('[@modern-js/runtime] A router provider realm cannot contain an unnamed provider.');
19
+ if (0 === registration.name.length) throw new Error('[@modern-js/runtime] A router provider realm cannot contain an unnamed provider.');
20
20
  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.`);
21
21
  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.`);
22
22
  providers.set(registration.name, registration.factory);
@@ -26,7 +26,7 @@ function createRouterProviderRealm(registrations) {
26
26
  ...providers.keys()
27
27
  ]);
28
28
  return Object.freeze({
29
- ...defaultProvider ? {
29
+ ...void 0 !== defaultProvider ? {
30
30
  defaultProvider
31
31
  } : {},
32
32
  get: (name)=>providers.get(name),
@@ -0,0 +1,13 @@
1
+ const handleRSCRedirect = (headers, basename, status)=>{
2
+ const newHeaders = new Headers(headers);
3
+ let redirectUrl = headers.get('Location');
4
+ if ('/' !== basename) redirectUrl = redirectUrl.replace(basename, '');
5
+ newHeaders.set('X-Modernjs-Redirect', redirectUrl);
6
+ newHeaders.set('X-Modernjs-BaseUrl', basename);
7
+ newHeaders.delete('Location');
8
+ return new Response(null, {
9
+ status,
10
+ headers: newHeaders
11
+ });
12
+ };
13
+ export { handleRSCRedirect };
@@ -1,4 +1,5 @@
1
1
  import { ROUTE_MODULES } from "@modern-js/utils/universal/constants";
2
+ const isRouteErrorResponse = (error)=>null !== error && 'object' == typeof error && 'number' == typeof error.status && 'string' == typeof error.statusText && 'boolean' == typeof error.internal && 'data' in error;
2
3
  const isObjectLike = (value)=>'object' == typeof value && null !== value || 'function' == typeof value;
3
4
  const isRouteComponent = (value)=>'function' == typeof value || isObjectLike(value) && '$$typeof' in value;
4
5
  const getRouteModules = ()=>{
@@ -51,4 +52,4 @@ const handleRouteModuleError = (error)=>{
51
52
  console.error(error);
52
53
  return null;
53
54
  };
54
- export { createShouldRevalidate, handleRouteModule, handleRouteModuleError, resolveRouteComponent };
55
+ export { createShouldRevalidate, handleRouteModule, handleRouteModuleError, isRouteErrorResponse, resolveRouteComponent };
@@ -85,18 +85,6 @@ const createServerPayload = (routerContext, routes)=>{
85
85
  })
86
86
  };
87
87
  };
88
- const handleRSCRedirect = (headers, basename, status)=>{
89
- const newHeaders = new Headers(headers);
90
- let redirectUrl = headers.get('Location');
91
- if ('/' !== basename) redirectUrl = redirectUrl.replace(basename, '');
92
- newHeaders.set('X-Modernjs-Redirect', redirectUrl);
93
- newHeaders.set('X-Modernjs-BaseUrl', basename);
94
- newHeaders.delete('Location');
95
- return new Response(null, {
96
- status: status,
97
- headers: newHeaders
98
- });
99
- };
100
88
  const prepareRSCRoutes = async (routes)=>{
101
89
  const isLazyComponent = (component)=>null != component && 'object' == typeof component && '_init' in component && '_payload' in component;
102
90
  const processRoutes = async (routesList)=>{
@@ -325,4 +313,5 @@ const RSCStaticRouter = ({ basename })=>{
325
313
  children: createRSCStaticRouterComponent(payload, basename)
326
314
  });
327
315
  };
328
- export { RSCStaticRouter, createClientRouterFromPayload, createServerPayload, handleRSCRedirect, prepareRSCRoutes };
316
+ export { handleRSCRedirect } from "./redirect.mjs";
317
+ export { RSCStaticRouter, createClientRouterFromPayload, createServerPayload, prepareRSCRoutes };
@@ -1,9 +1,10 @@
1
1
  import { jsx } from "react/jsx-runtime";
2
2
  import { renderNestedRoute } from "@modern-js/runtime-utils/browser";
3
- import { Route, UNSAFE_ErrorResponseImpl, isRouteErrorResponse } from "@modern-js/runtime-utils/router";
3
+ import { Route, UNSAFE_ErrorResponseImpl } from "@modern-js/runtime-utils/router";
4
4
  import react from "react";
5
5
  import { DefaultNotFound } from "./DefaultNotFound.mjs";
6
6
  import DeferredDataScripts from "./DeferredDataScripts.mjs";
7
+ import { isRouteErrorResponse } from "./routerHelper.mjs";
7
8
  function getRouteComponents(routes, { globalApp, ssrMode, props }) {
8
9
  const Layout = ({ Component, ...props })=>{
9
10
  const GlobalLayout = globalApp;
@@ -108,6 +108,7 @@ const ssrBuilderPlugin = (modernAPI, outputModule, exportLoadablePath)=>({
108
108
  'process.env.MODERN_SSR_ENV': JSON.stringify(ssrEnv),
109
109
  'process.env.MODERN_ENABLE_HYDRATION': JSON.stringify(isUseSSRBundle(userConfig)),
110
110
  'process.env.MODERN_ENABLE_RSC': JSON.stringify(Boolean(userConfig.server?.rsc)),
111
+ __MODERN_ENABLE_RSC__: JSON.stringify(Boolean(userConfig.server?.rsc)),
111
112
  'process.env.MODERN_MF_APP_SSR': JSON.stringify(isModuleFederationAppSSR)
112
113
  }
113
114
  },
@@ -6,15 +6,23 @@ import { hydrateRoot } from "react-dom/client";
6
6
  import { RenderLevel } from "../constants.mjs";
7
7
  import { wrapRuntimeContextProvider } from "../react/wrapper.mjs";
8
8
  import { WithCallback } from "./withCallback.mjs";
9
- const isReact18 = ()=>'true' === process.env.IS_REACT18;
10
9
  const runtimeProcess = Reflect.get(globalThis, 'process');
10
+ const runtimeEnvironment = null !== runtimeProcess && 'object' == typeof runtimeProcess ? Reflect.get(runtimeProcess, 'env') : void 0;
11
+ const readRuntimeEnvironment = (name)=>{
12
+ if (null === runtimeEnvironment || 'object' != typeof runtimeEnvironment) return;
13
+ const value = Reflect.get(runtimeEnvironment, name);
14
+ return 'string' == typeof value ? value : void 0;
15
+ };
11
16
  const loadableReadyOptions = {
12
- chunkLoadingGlobal: runtimeProcess?.env?.MODERN_CHUNK_LOADING_GLOBAL || '__LOADABLE_LOADED_CHUNKS__'
17
+ chunkLoadingGlobal: (()=>{
18
+ const configured = readRuntimeEnvironment('MODERN_CHUNK_LOADING_GLOBAL');
19
+ return void 0 === configured || '' === configured ? '__LOADABLE_LOADED_CHUNKS__' : configured;
20
+ })()
13
21
  };
14
- async function hydrateWithReact(App, rootElement) {
15
- return hydrateRoot(rootElement, App, {
22
+ function hydrateWithReact(App, rootElement) {
23
+ return Promise.resolve(hydrateRoot(rootElement, App, {
16
24
  identifierPrefix: SSR_HYDRATION_ID_PREFIX
17
- });
25
+ }));
18
26
  }
19
27
  function hydrate_hydrateRoot(App, context, ModernRender, ModernHydrate) {
20
28
  const hydrateContext = {
@@ -27,9 +35,9 @@ function hydrate_hydrateRoot(App, context, ModernRender, ModernHydrate) {
27
35
  const callback = ()=>{
28
36
  delete hydrateContext._hydration;
29
37
  };
30
- const renderLevel = window?._SSR_DATA?.renderLevel || RenderLevel.CLIENT_RENDER;
31
- const renderMode = window?._SSR_DATA?.mode || 'string';
32
- if (isReact18() && 'stream' === renderMode) return streamSSRHydrate();
38
+ const renderLevel = window?._SSR_DATA?.renderLevel ?? RenderLevel.CLIENT_RENDER;
39
+ const renderMode = window?._SSR_DATA?.mode ?? 'string';
40
+ if ('stream' === renderMode) return streamSSRHydrate();
33
41
  function streamSSRHydrate() {
34
42
  if (renderLevel !== RenderLevel.SERVER_RENDER) return ModernRender(wrapRuntimeContextProvider(App, context));
35
43
  {
@@ -43,23 +51,23 @@ function hydrate_hydrateRoot(App, context, ModernRender, ModernHydrate) {
43
51
  return stringSSRHydrate();
44
52
  function stringSSRHydrate() {
45
53
  if (renderLevel === RenderLevel.CLIENT_RENDER) return ModernRender(wrapRuntimeContextProvider(App, context));
46
- if (renderLevel === RenderLevel.SERVER_RENDER) return new Promise((resolve)=>{
47
- isReact18() ? loadableReady(()=>{
54
+ {
55
+ if (renderLevel === RenderLevel.SERVER_RENDER) return loadableReady(()=>void 0, loadableReadyOptions).then(()=>{
48
56
  const SSRApp = ()=>/*#__PURE__*/ jsx(WithCallback, {
49
57
  callback: callback,
50
58
  children: App
51
59
  });
52
- ModernHydrate(wrapRuntimeContextProvider(/*#__PURE__*/ jsx(SSRApp, {}), hydrateContext)).then((root)=>{
53
- resolve(root);
54
- });
55
- }, loadableReadyOptions) : loadableReady(()=>{
56
- ModernHydrate(wrapRuntimeContextProvider(App, hydrateContext), callback).then((root)=>{
57
- resolve(root);
58
- });
59
- }, loadableReadyOptions);
60
- });
61
- console.warn(`unknow render level: ${renderLevel}, execute render()`);
62
- return ModernRender(wrapRuntimeContextProvider(App, context));
60
+ return ModernHydrate(wrapRuntimeContextProvider(/*#__PURE__*/ jsx(SSRApp, {}), hydrateContext));
61
+ });
62
+ const runtimeConsole = Reflect.get(globalThis, 'console');
63
+ if (null !== runtimeConsole && 'object' == typeof runtimeConsole) {
64
+ const warn = Reflect.get(runtimeConsole, 'warn');
65
+ if ('function' == typeof warn) Reflect.apply(warn, runtimeConsole, [
66
+ `unknow render level: ${renderLevel}, execute render()`
67
+ ]);
68
+ }
69
+ return ModernRender(wrapRuntimeContextProvider(App, context));
70
+ }
63
71
  }
64
72
  }
65
- export { hydrateWithReact, hydrate_hydrateRoot as hydrateRoot, isReact18 };
73
+ export { hydrateWithReact, hydrate_hydrateRoot as hydrateRoot };
@@ -4,39 +4,34 @@ import { HelmetProvider } from "react-helmet-async";
4
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;
7
+ function createRscSafeRequestContext(ssrContext) {
8
+ if (void 0 === ssrContext) return {
9
+ request: {},
10
+ response: {
11
+ locals: {}
12
+ }
13
+ };
14
+ const { request, response } = ssrContext;
14
15
  return {
15
- nonce: ssrContext.nonce,
16
- useJsonScript: ssrContext.useJsonScript,
17
- htmlModifiers: [],
18
- baseUrl: ssrContext.baseUrl,
19
- request: request ? {
16
+ request: {
20
17
  url: request.url,
21
18
  userAgent: request.userAgent,
22
19
  cookie: request.cookie,
23
20
  pathname: request.pathname,
24
- query: toRscSafeRecord(request.query),
25
- params: toRscSafeRecord(request.params),
26
- headers: toRscSafeRecord(request.headers),
21
+ query: {
22
+ ...request.query
23
+ },
24
+ params: {
25
+ ...request.params
26
+ },
27
+ headers: {
28
+ ...request.headers
29
+ },
27
30
  host: request.host,
28
31
  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 || {},
32
+ },
38
33
  response: {
39
- locals: ssrContext?.response?.locals || {}
34
+ locals: response.locals ?? {}
40
35
  }
41
36
  };
42
37
  }
@@ -52,14 +47,14 @@ function wrapRuntimeContextProvider(App, contextValue) {
52
47
  ...rest
53
48
  };
54
49
  stripRuntimeContextExtensions(runtimeContextValue);
55
- if (getGlobalEnableRsc() && !isBrowser) {
50
+ if (true === getGlobalEnableRsc() && false === isBrowser) {
56
51
  const rscSafeRequestContext = createRscSafeRequestContext(ssrContext);
57
52
  const rscInternalContextValue = {
58
53
  ...internalContextValue,
59
54
  context: rscSafeRequestContext,
60
- requestContext: rscSafeRequestContext,
61
- ssrContext: createRscSafeSsrContext(ssrContext)
55
+ requestContext: rscSafeRequestContext
62
56
  };
57
+ delete rscInternalContextValue.ssrContext;
63
58
  const rscRuntimeContextValue = {
64
59
  ...runtimeContextValue,
65
60
  context: rscSafeRequestContext,