@bleedingdev/modern-js-runtime 3.4.0-ultramodern.2 → 3.4.0-ultramodern.20

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 (36) hide show
  1. package/dist/cjs/cli/index.js +5 -2
  2. package/dist/cjs/cli/template.server.js +12 -1
  3. package/dist/cjs/core/server/stream/beforeTemplate.js +2 -2
  4. package/dist/cjs/core/server/stream/beforeTemplate.worker.js +2 -2
  5. package/dist/cjs/core/server/string/loadable.js +2 -6
  6. package/dist/cjs/router/cli/code/templates.js +8 -8
  7. package/dist/cjs/router/cli/index.js +7 -7
  8. package/dist/cjs/router/cli/nestedRoutesSpec.js +114 -0
  9. package/dist/cjs/router/runtime/routerHelper.js +48 -6
  10. package/dist/cjs/router/runtime/rsc-router.js +4 -3
  11. package/dist/esm/cli/index.mjs +2 -2
  12. package/dist/esm/cli/template.server.mjs +12 -1
  13. package/dist/esm/core/server/stream/beforeTemplate.mjs +2 -2
  14. package/dist/esm/core/server/stream/beforeTemplate.worker.mjs +2 -2
  15. package/dist/esm/core/server/string/loadable.mjs +2 -6
  16. package/dist/esm/router/cli/code/templates.mjs +9 -9
  17. package/dist/esm/router/cli/index.mjs +4 -7
  18. package/dist/esm/router/cli/nestedRoutesSpec.mjs +66 -0
  19. package/dist/esm/router/runtime/routerHelper.mjs +44 -5
  20. package/dist/esm/router/runtime/rsc-router.mjs +4 -3
  21. package/dist/esm-node/cli/index.mjs +2 -2
  22. package/dist/esm-node/cli/template.server.mjs +12 -1
  23. package/dist/esm-node/core/server/stream/beforeTemplate.mjs +2 -2
  24. package/dist/esm-node/core/server/stream/beforeTemplate.worker.mjs +2 -2
  25. package/dist/esm-node/core/server/string/loadable.mjs +2 -6
  26. package/dist/esm-node/router/cli/code/templates.mjs +9 -9
  27. package/dist/esm-node/router/cli/index.mjs +4 -7
  28. package/dist/esm-node/router/cli/nestedRoutesSpec.mjs +67 -0
  29. package/dist/esm-node/router/runtime/routerHelper.mjs +44 -5
  30. package/dist/esm-node/router/runtime/rsc-router.mjs +4 -3
  31. package/dist/types/cli/index.d.ts +1 -1
  32. package/dist/types/core/server/string/loadable.d.ts +0 -1
  33. package/dist/types/router/cli/index.d.ts +1 -0
  34. package/dist/types/router/cli/nestedRoutesSpec.d.ts +1 -0
  35. package/dist/types/router/runtime/routerHelper.d.ts +3 -2
  36. package/package.json +9 -9
@@ -50,7 +50,8 @@ __webpack_require__.d(__webpack_exports__, {
50
50
  makeLegalIdentifier: ()=>makeLegalIdentifier_js_namespaceObject.makeLegalIdentifier,
51
51
  routerPlugin: ()=>external_router_cli_index_js_namespaceObject.routerPlugin,
52
52
  runtimePlugin: ()=>runtimePlugin,
53
- ssrPlugin: ()=>external_ssr_index_js_namespaceObject.ssrPlugin
53
+ ssrPlugin: ()=>external_ssr_index_js_namespaceObject.ssrPlugin,
54
+ updateNestedRoutesSpec: ()=>external_router_cli_index_js_namespaceObject.updateNestedRoutesSpec
54
55
  });
55
56
  const utils_namespaceObject = require("@modern-js/utils");
56
57
  const external_path_namespaceObject = require("path");
@@ -160,6 +161,7 @@ exports.makeLegalIdentifier = __webpack_exports__.makeLegalIdentifier;
160
161
  exports.routerPlugin = __webpack_exports__.routerPlugin;
161
162
  exports.runtimePlugin = __webpack_exports__.runtimePlugin;
162
163
  exports.ssrPlugin = __webpack_exports__.ssrPlugin;
164
+ exports.updateNestedRoutesSpec = __webpack_exports__.updateNestedRoutesSpec;
163
165
  for(var __rspack_i in __webpack_exports__)if (-1 === [
164
166
  "default",
165
167
  "documentPlugin",
@@ -174,7 +176,8 @@ for(var __rspack_i in __webpack_exports__)if (-1 === [
174
176
  "makeLegalIdentifier",
175
177
  "routerPlugin",
176
178
  "runtimePlugin",
177
- "ssrPlugin"
179
+ "ssrPlugin",
180
+ "updateNestedRoutesSpec"
178
181
  ].indexOf(__rspack_i)) exports[__rspack_i] = __webpack_exports__[__rspack_i];
179
182
  Object.defineProperty(exports, '__esModule', {
180
183
  value: true
@@ -57,7 +57,7 @@ import {
57
57
  createRequestHandler,
58
58
  } from '@#metaName/runtime/ssr/server';
59
59
  import { RSCServerSlot } from '@#metaName/runtime/rsc/client';
60
- import { renderRsc } from '@#metaName/runtime/rsc/server';
60
+ import { renderCSRWithRSC, renderRsc } from '@#metaName/runtime/rsc/server';
61
61
  export { handleAction } from '@#metaName/runtime/rsc/server';
62
62
 
63
63
  const handleRequest = async (request, ServerRoot, options) => {
@@ -84,6 +84,17 @@ export const requestHandler = createRequestHandler(handleRequest, {
84
84
  enableRsc: true
85
85
  });
86
86
 
87
+ const handleCSRRender = async (request, ServerRoot, options) => {
88
+ return renderCSRWithRSC({
89
+ html: options.html,
90
+ rscRoot: options.rscRoot,
91
+ });
92
+ }
93
+
94
+ export const renderRscStreamHandler = createRequestHandler(handleCSRRender, {
95
+ enableRsc: true
96
+ });
97
+
87
98
  const handleRSCRequest = async (request, ServerRoot, options) => {
88
99
  const { serverPayload } = options;
89
100
  const stream = renderRsc({
@@ -66,8 +66,8 @@ async function buildShellBeforeTemplate(beforeAppTemplate, options) {
66
66
  return (0, external_utils_js_namespaceObject.safeReplace)(template, external_constants_js_namespaceObject.CHUNK_CSS_PLACEHOLDER, css);
67
67
  async function getCssChunks() {
68
68
  const { routeManifest, routerContext, routes } = runtimeContext;
69
- if (!routeManifest) return '';
70
- const { routeAssets } = routeManifest;
69
+ const routeAssets = routeManifest?.routeAssets;
70
+ if (!routeAssets) return '';
71
71
  let matchedRouteManifests = [];
72
72
  const matchedRouteIds = (0, lifecycle_js_namespaceObject.getRouterMatchedRouteIds)(runtimeContext);
73
73
  if (matchedRouteIds?.length) matchedRouteManifests = matchedRouteIds.map((routeId)=>routeAssets[routeId]).filter(Boolean);
@@ -60,8 +60,8 @@ async function buildShellBeforeTemplate(beforeAppTemplate, options) {
60
60
  return (0, external_utils_js_namespaceObject.safeReplace)(template, external_constants_js_namespaceObject.CHUNK_CSS_PLACEHOLDER, css);
61
61
  async function getCssChunks() {
62
62
  const { routeManifest, routerContext, routes } = runtimeContext;
63
- if (!routeManifest) return '';
64
- const { routeAssets } = routeManifest;
63
+ const routeAssets = routeManifest?.routeAssets;
64
+ if (!routeAssets) return '';
65
65
  let matchedRouteManifests = [];
66
66
  const matchedRouteIds = (0, lifecycle_js_namespaceObject.getRouterMatchedRouteIds)(runtimeContext);
67
67
  if (matchedRouteIds?.length) matchedRouteManifests = matchedRouteIds.map((routeId)=>routeAssets[routeId]).filter(Boolean);
@@ -61,10 +61,6 @@ const readAsset = async (chunk)=>{
61
61
  return fs.readFile(filepath, 'utf-8');
62
62
  };
63
63
  class LoadableCollector {
64
- get existsAssets() {
65
- const { routeManifest, entryName } = this.options;
66
- return routeManifest?.routeAssets?.[entryName]?.assets;
67
- }
68
64
  getMatchedRouteChunks() {
69
65
  const { routeManifest, runtimeContext } = this.options;
70
66
  if (!routeManifest) return [];
@@ -131,7 +127,7 @@ class LoadableCollector {
131
127
  const matchs = template.matchAll(jsScriptRegExp);
132
128
  const existedScript = [];
133
129
  for (const match of matchs)existedScript.push(match[1]);
134
- const scripts = await Promise.all(chunks.filter((chunk)=>!existedScript.includes(chunk.url) && !this.existsAssets?.includes(chunk.path)).map(async (chunk)=>{
130
+ const scripts = await Promise.all(chunks.filter((chunk)=>!existedScript.includes(chunk.url)).map(async (chunk)=>{
135
131
  const script = `<script${attributes} src="${chunk.url}"></script>`;
136
132
  if ((0, external_utils_js_namespaceObject.checkIsNode)() && checkIsInline(chunk, inlineStyles)) return readAsset(chunk).then((content)=>`<script>${content}</script>`).catch((_)=>script);
137
133
  return script;
@@ -142,7 +138,7 @@ class LoadableCollector {
142
138
  const { template, chunkSet, config, moduleFederationCssAssets } = this.options;
143
139
  const { inlineStyles } = config;
144
140
  const atrributes = (0, external_utils_js_namespaceObject.attributesToString)(this.generateAttributes());
145
- const emittedChunks = chunks.filter((chunk)=>!(0, external_utils_js_namespaceObject.hasStylesheetLink)(template, chunk.url) && !this.existsAssets?.includes(chunk.path));
141
+ const emittedChunks = chunks.filter((chunk)=>!(0, external_utils_js_namespaceObject.hasStylesheetLink)(template, chunk.url));
146
142
  const css = await Promise.all(emittedChunks.map(async (chunk)=>{
147
143
  const link = `<link${atrributes} href="${chunk.url}" rel="stylesheet" />`;
148
144
  if ((0, external_utils_js_namespaceObject.checkIsNode)() && checkIsInline(chunk, inlineStyles)) return readAsset(chunk).then((content)=>`<style>${content}</style>`).catch((_)=>link);
@@ -214,14 +214,14 @@ const fileSystemRoutes = async ({ metaName, routes, ssrMode, nestedRoutesEntry,
214
214
  routeId: route.id,
215
215
  webpackChunkName: true
216
216
  });
217
- component = 'string' === ssrMode ? `loadable(${lazyImport})` : `lazy(${lazyImport})`;
217
+ component = 'string' === ssrMode ? `loadable(${lazyImport}, { resolveComponent: resolveRouteComponent })` : `lazy(${lazyImport})`;
218
218
  } else {
219
219
  components.push(route._component);
220
220
  component = `component_${components.length - 1}`;
221
221
  }
222
222
  } else if (route._component) if (splitRouteChunks) {
223
223
  lazyImport = `() => import('${route._component}')`;
224
- component = `loadable(${lazyImport})`;
224
+ component = `loadable(${lazyImport}, { resolveComponent: resolveRouteComponent })`;
225
225
  } else {
226
226
  components.push(route._component);
227
227
  component = `component_${components.length - 1}`;
@@ -269,7 +269,7 @@ const fileSystemRoutes = async ({ metaName, routes, ssrMode, nestedRoutesEntry,
269
269
  const newRouteStr = regs.reduce((acc, reg)=>acc.replace(reg, '$1$2'), routeStr).replace(/"(RootLayout)"/g, '$1').replace(/\\"/g, '"');
270
270
  routeComponentsCode += `${newRouteStr},`;
271
271
  } else {
272
- const component = `loadable(() => import('${route._component}'))`;
272
+ const component = `loadable(() => import('${route._component}'), { resolveComponent: resolveRouteComponent })`;
273
273
  const finalRoute = {
274
274
  ...route,
275
275
  component
@@ -319,7 +319,7 @@ const fileSystemRoutes = async ({ metaName, routes, ssrMode, nestedRoutesEntry,
319
319
  await utils_namespaceObject.fs.ensureFile(loadersMapFile);
320
320
  await utils_namespaceObject.fs.writeJSON(loadersMapFile, loadersMap);
321
321
  const importRuntimeRouterCode = `
322
- import { createShouldRevalidate, handleRouteModule, handleRouteModuleError} from '@${metaName}/runtime/routerHelper';
322
+ import { createShouldRevalidate, handleRouteModule, handleRouteModuleError, resolveRouteComponent } from '@${metaName}/runtime/routerHelper';
323
323
  `;
324
324
  const routeModulesCode = `
325
325
  if(typeof document !== 'undefined'){
@@ -341,19 +341,19 @@ const fileSystemRoutes = async ({ metaName, routes, ssrMode, nestedRoutesEntry,
341
341
  };
342
342
  function ssrLoaderCombinedModule(entrypoints, entrypoint, config, appContext) {
343
343
  const { entryName, isMainEntry } = entrypoint;
344
- const { packageName, internalDirectory } = appContext;
344
+ const { packageName } = appContext;
345
345
  const ssr = (0, utils_namespaceObject.getEntryOptions)(entryName, isMainEntry, config.server.ssr, config.server.ssrByEntries, packageName);
346
346
  const ssg = (0, utils_namespaceObject.isSSGEntry)(config, entryName, entrypoints);
347
347
  if (entrypoint.nestedRoutesEntry && (ssr || ssg)) {
348
348
  const serverLoaderRuntime = require.resolve('@modern-js/plugin-data-loader/runtime');
349
- const serverLoadersFile = (0, external_utils_js_namespaceObject.getServerLoadersFile)(internalDirectory, entryName);
350
- const combinedModule = `export * from "${(0, utils_namespaceObject.slash)(serverLoaderRuntime)}"; export * from "${(0, utils_namespaceObject.slash)(serverLoadersFile)}"`;
349
+ const serverLoadersFile = './route-server-loaders.js';
350
+ const combinedModule = `export * from "${(0, utils_namespaceObject.slash)(serverLoaderRuntime)}"; export * from "${serverLoadersFile}"`;
351
351
  if (!config.source.enableAsyncEntry) return combinedModule;
352
352
  return `
353
353
  async function loadModules() {
354
354
  const [moduleA, moduleB] = await Promise.all([
355
355
  import("${(0, utils_namespaceObject.slash)(serverLoaderRuntime)}"),
356
- import("${(0, utils_namespaceObject.slash)(serverLoadersFile)}")
356
+ import("${serverLoadersFile}")
357
357
  ]);
358
358
 
359
359
  return {
@@ -45,7 +45,8 @@ __webpack_require__.d(__webpack_exports__, {
45
45
  handleGeneratorEntryCode: ()=>external_handler_js_namespaceObject.handleGeneratorEntryCode,
46
46
  handleModifyEntrypoints: ()=>external_handler_js_namespaceObject.handleModifyEntrypoints,
47
47
  isRouteEntry: ()=>external_entry_js_namespaceObject.isRouteEntry,
48
- routerPlugin: ()=>routerPlugin
48
+ routerPlugin: ()=>routerPlugin,
49
+ updateNestedRoutesSpec: ()=>external_nestedRoutesSpec_js_namespaceObject.updateNestedRoutesSpec
49
50
  });
50
51
  const external_node_path_namespaceObject = require("node:path");
51
52
  var external_node_path_default = /*#__PURE__*/ __webpack_require__.n(external_node_path_namespaceObject);
@@ -53,6 +54,7 @@ const utils_namespaceObject = require("@modern-js/utils");
53
54
  const external_constants_js_namespaceObject = require("./constants.js");
54
55
  const external_entry_js_namespaceObject = require("./entry.js");
55
56
  const external_handler_js_namespaceObject = require("./handler.js");
57
+ const external_nestedRoutesSpec_js_namespaceObject = require("./nestedRoutesSpec.js");
56
58
  function isBuiltInRouteEntrypoint(entrypoint) {
57
59
  const entrypointRoutesOwner = (0, external_entry_js_namespaceObject.getEntrypointRoutesOwner)(entrypoint);
58
60
  if (entrypointRoutesOwner) return entrypointRoutesOwner === external_entry_js_namespaceObject.BUILT_IN_ROUTES_OWNER;
@@ -137,11 +139,7 @@ const routerPlugin = ()=>({
137
139
  if (isBuiltInRouteEntrypoint(entrypoint)) {
138
140
  const { distDirectory } = api.getAppContext();
139
141
  const nestedRoutesSpecPath = external_node_path_default().resolve(distDirectory, utils_namespaceObject.NESTED_ROUTE_SPEC_FILE);
140
- const existingNestedRoutes = await utils_namespaceObject.fs.pathExists(nestedRoutesSpecPath) ? await utils_namespaceObject.fs.readJSON(nestedRoutesSpecPath) : {};
141
- await utils_namespaceObject.fs.outputJSON(nestedRoutesSpecPath, {
142
- ...existingNestedRoutes,
143
- ...nestedRoutesForServer
144
- });
142
+ await (0, external_nestedRoutesSpec_js_namespaceObject.updateNestedRoutesSpec)(nestedRoutesSpecPath, nestedRoutesForServer);
145
143
  }
146
144
  return {
147
145
  entrypoint,
@@ -160,6 +158,7 @@ exports.handleGeneratorEntryCode = __webpack_exports__.handleGeneratorEntryCode;
160
158
  exports.handleModifyEntrypoints = __webpack_exports__.handleModifyEntrypoints;
161
159
  exports.isRouteEntry = __webpack_exports__.isRouteEntry;
162
160
  exports.routerPlugin = __webpack_exports__.routerPlugin;
161
+ exports.updateNestedRoutesSpec = __webpack_exports__.updateNestedRoutesSpec;
163
162
  for(var __rspack_i in __webpack_exports__)if (-1 === [
164
163
  "BUILT_IN_ROUTES_OWNER",
165
164
  "default",
@@ -169,7 +168,8 @@ for(var __rspack_i in __webpack_exports__)if (-1 === [
169
168
  "handleGeneratorEntryCode",
170
169
  "handleModifyEntrypoints",
171
170
  "isRouteEntry",
172
- "routerPlugin"
171
+ "routerPlugin",
172
+ "updateNestedRoutesSpec"
173
173
  ].indexOf(__rspack_i)) exports[__rspack_i] = __webpack_exports__[__rspack_i];
174
174
  Object.defineProperty(exports, '__esModule', {
175
175
  value: true
@@ -0,0 +1,114 @@
1
+ "use strict";
2
+ var __webpack_require__ = {};
3
+ (()=>{
4
+ __webpack_require__.n = (module)=>{
5
+ var getter = module && module.__esModule ? ()=>module['default'] : ()=>module;
6
+ __webpack_require__.d(getter, {
7
+ a: getter
8
+ });
9
+ return getter;
10
+ };
11
+ })();
12
+ (()=>{
13
+ __webpack_require__.d = (exports1, getters, values)=>{
14
+ var define = (defs, kind)=>{
15
+ for(var key in defs)if (__webpack_require__.o(defs, key) && !__webpack_require__.o(exports1, key)) Object.defineProperty(exports1, key, {
16
+ enumerable: true,
17
+ [kind]: defs[key]
18
+ });
19
+ };
20
+ define(getters, "get");
21
+ define(values, "value");
22
+ };
23
+ })();
24
+ (()=>{
25
+ __webpack_require__.o = (obj, prop)=>Object.prototype.hasOwnProperty.call(obj, prop);
26
+ })();
27
+ (()=>{
28
+ __webpack_require__.r = (exports1)=>{
29
+ if ("u" > typeof Symbol && Symbol.toStringTag) Object.defineProperty(exports1, Symbol.toStringTag, {
30
+ value: 'Module'
31
+ });
32
+ Object.defineProperty(exports1, '__esModule', {
33
+ value: true
34
+ });
35
+ };
36
+ })();
37
+ var __webpack_exports__ = {};
38
+ __webpack_require__.r(__webpack_exports__);
39
+ __webpack_require__.d(__webpack_exports__, {
40
+ updateNestedRoutesSpec: ()=>updateNestedRoutesSpec
41
+ });
42
+ const external_node_path_namespaceObject = require("node:path");
43
+ var external_node_path_default = /*#__PURE__*/ __webpack_require__.n(external_node_path_namespaceObject);
44
+ const promises_namespaceObject = require("node:timers/promises");
45
+ const utils_namespaceObject = require("@modern-js/utils");
46
+ const lockPollIntervalMs = 25;
47
+ const staleLockAgeMs = 120000;
48
+ const pendingUpdates = new Map();
49
+ let tempFileCounter = 0;
50
+ async function acquireSpecLock(specPath) {
51
+ const lockDir = `${specPath}.lock`;
52
+ await utils_namespaceObject.fs.ensureDir(external_node_path_default().dirname(specPath));
53
+ while(true){
54
+ try {
55
+ await utils_namespaceObject.fs.mkdir(lockDir);
56
+ return async ()=>{
57
+ await utils_namespaceObject.fs.remove(lockDir);
58
+ };
59
+ } catch (error) {
60
+ if ('EEXIST' !== error.code) throw error;
61
+ }
62
+ try {
63
+ const stat = await utils_namespaceObject.fs.stat(lockDir);
64
+ if (performance.timeOrigin + performance.now() - stat.mtimeMs > staleLockAgeMs) {
65
+ await utils_namespaceObject.fs.remove(lockDir);
66
+ continue;
67
+ }
68
+ } catch (error) {
69
+ if ('ENOENT' !== error.code) throw error;
70
+ continue;
71
+ }
72
+ await (0, promises_namespaceObject.setTimeout)(lockPollIntervalMs);
73
+ }
74
+ }
75
+ async function writeJSONAtomically(filePath, value) {
76
+ const directory = external_node_path_default().dirname(filePath);
77
+ const tempPath = external_node_path_default().join(directory, `.${external_node_path_default().basename(filePath)}.${process.pid}.${tempFileCounter += 1}.tmp`);
78
+ try {
79
+ await utils_namespaceObject.fs.writeFile(tempPath, `${JSON.stringify(value)}\n`);
80
+ await utils_namespaceObject.fs.rename(tempPath, filePath);
81
+ } catch (error) {
82
+ await utils_namespaceObject.fs.remove(tempPath).catch(()=>{});
83
+ throw error;
84
+ }
85
+ }
86
+ async function updateNestedRoutesSpec(specPath, nextRoutes) {
87
+ const resolvedSpecPath = external_node_path_default().resolve(specPath);
88
+ const previousUpdate = pendingUpdates.get(resolvedSpecPath) ?? Promise.resolve();
89
+ const currentUpdate = previousUpdate.catch(()=>void 0).then(async ()=>{
90
+ const releaseLock = await acquireSpecLock(resolvedSpecPath);
91
+ try {
92
+ const existingRoutes = await utils_namespaceObject.fs.pathExists(resolvedSpecPath) ? await utils_namespaceObject.fs.readJSON(resolvedSpecPath) : {};
93
+ await writeJSONAtomically(resolvedSpecPath, {
94
+ ...existingRoutes,
95
+ ...nextRoutes
96
+ });
97
+ } finally{
98
+ await releaseLock();
99
+ }
100
+ });
101
+ pendingUpdates.set(resolvedSpecPath, currentUpdate);
102
+ try {
103
+ await currentUpdate;
104
+ } finally{
105
+ if (pendingUpdates.get(resolvedSpecPath) === currentUpdate) pendingUpdates.delete(resolvedSpecPath);
106
+ }
107
+ }
108
+ exports.updateNestedRoutesSpec = __webpack_exports__.updateNestedRoutesSpec;
109
+ for(var __rspack_i in __webpack_exports__)if (-1 === [
110
+ "updateNestedRoutesSpec"
111
+ ].indexOf(__rspack_i)) exports[__rspack_i] = __webpack_exports__[__rspack_i];
112
+ Object.defineProperty(exports, '__esModule', {
113
+ value: true
114
+ });
@@ -30,17 +30,57 @@ __webpack_require__.r(__webpack_exports__);
30
30
  __webpack_require__.d(__webpack_exports__, {
31
31
  createShouldRevalidate: ()=>createShouldRevalidate,
32
32
  handleRouteModule: ()=>handleRouteModule,
33
- handleRouteModuleError: ()=>handleRouteModuleError
33
+ handleRouteModuleError: ()=>handleRouteModuleError,
34
+ resolveRouteComponent: ()=>resolveRouteComponent
34
35
  });
35
36
  const constants_namespaceObject = require("@modern-js/utils/universal/constants");
37
+ const isObjectLike = (value)=>'object' == typeof value && null !== value || 'function' == typeof value;
38
+ const isRouteComponent = (value)=>'function' == typeof value || isObjectLike(value) && '$$typeof' in value;
39
+ const getRouteModules = ()=>{
40
+ if ("u" < typeof window) return;
41
+ return window[constants_namespaceObject.ROUTE_MODULES];
42
+ };
43
+ const storeRouteModule = (routeModule, routeId)=>{
44
+ if ("u" < typeof document) return;
45
+ const routeModules = getRouteModules();
46
+ if (void 0 !== routeModules) routeModules[routeId] = routeModule;
47
+ };
48
+ const unwrapRspackAsyncModule = (routeModule)=>{
49
+ if (!isObjectLike(routeModule)) return routeModule;
50
+ const rspackExportsSymbol = Object.getOwnPropertySymbols(routeModule).find((symbol)=>'rspack exports' === symbol.description);
51
+ if (void 0 !== rspackExportsSymbol) return routeModule[rspackExportsSymbol];
52
+ if ('__webpack_exports__' in routeModule) return routeModule.__webpack_exports__;
53
+ return routeModule;
54
+ };
36
55
  const createShouldRevalidate = (routeId)=>(arg)=>{
37
- const routeModule = "u" > typeof window ? window?.[constants_namespaceObject.ROUTE_MODULES]?.[routeId] : void 0;
38
- if (routeModule && 'function' == typeof routeModule.shouldRevalidate) return routeModule.shouldRevalidate(arg);
56
+ const routeModule = getRouteModules()?.[routeId];
57
+ if (isObjectLike(routeModule)) {
58
+ const shouldRevalidate = routeModule.shouldRevalidate;
59
+ if ('function' == typeof shouldRevalidate) return shouldRevalidate(arg);
60
+ }
39
61
  return arg.defaultShouldRevalidate;
40
62
  };
63
+ const pickRouteModuleComponent = (routeModule, seen = new Set())=>{
64
+ const unwrappedRouteModule = unwrapRspackAsyncModule(routeModule);
65
+ if (isRouteComponent(unwrappedRouteModule)) return unwrappedRouteModule;
66
+ if (!isObjectLike(unwrappedRouteModule) || seen.has(unwrappedRouteModule)) return;
67
+ seen.add(unwrappedRouteModule);
68
+ const componentModule = unwrappedRouteModule;
69
+ for (const candidate of [
70
+ componentModule.default,
71
+ componentModule.Component
72
+ ]){
73
+ const component = pickRouteModuleComponent(candidate, seen);
74
+ if (void 0 !== component) return component;
75
+ }
76
+ };
77
+ const resolveRouteComponent = (routeModule)=>pickRouteModuleComponent(routeModule) ?? routeModule;
41
78
  const handleRouteModule = (routeModule, routeId)=>{
42
- if ("u" > typeof document) window[constants_namespaceObject.ROUTE_MODULES][routeId] = routeModule;
43
- return routeModule;
79
+ storeRouteModule(routeModule, routeId);
80
+ const component = pickRouteModuleComponent(routeModule);
81
+ return void 0 !== component ? {
82
+ default: component
83
+ } : routeModule;
44
84
  };
45
85
  const handleRouteModuleError = (error)=>{
46
86
  console.error(error);
@@ -49,10 +89,12 @@ const handleRouteModuleError = (error)=>{
49
89
  exports.createShouldRevalidate = __webpack_exports__.createShouldRevalidate;
50
90
  exports.handleRouteModule = __webpack_exports__.handleRouteModule;
51
91
  exports.handleRouteModuleError = __webpack_exports__.handleRouteModuleError;
92
+ exports.resolveRouteComponent = __webpack_exports__.resolveRouteComponent;
52
93
  for(var __rspack_i in __webpack_exports__)if (-1 === [
53
94
  "createShouldRevalidate",
54
95
  "handleRouteModule",
55
- "handleRouteModuleError"
96
+ "handleRouteModuleError",
97
+ "resolveRouteComponent"
56
98
  ].indexOf(__rspack_i)) exports[__rspack_i] = __webpack_exports__[__rspack_i];
57
99
  Object.defineProperty(exports, '__esModule', {
58
100
  value: true
@@ -90,10 +90,10 @@ const createServerPayload = (routerContext, routes)=>{
90
90
  routes: routerContext.matches.map((match, index, matches)=>{
91
91
  const route = match.route;
92
92
  const element = route.element;
93
+ const Component = route.Component;
93
94
  const parentMatch = index > 0 ? matches[index - 1] : void 0;
94
95
  let processedElement;
95
- if (element) {
96
- const ElementComponent = element.type;
96
+ if (element || Component) {
97
97
  const elementProps = {
98
98
  loaderData: routerContext?.loaderData?.[route.id],
99
99
  actionData: routerContext?.actionData?.[route.id],
@@ -106,7 +106,8 @@ const createServerPayload = (routerContext, routes)=>{
106
106
  handle: m.route.handle
107
107
  }))
108
108
  };
109
- const routeElement = /*#__PURE__*/ external_react_default().createElement(ElementComponent, elementProps);
109
+ const RouteComponent = Component;
110
+ const routeElement = element ? /*#__PURE__*/ external_react_default().cloneElement(element, elementProps) : /*#__PURE__*/ external_react_default().createElement(RouteComponent, elementProps);
110
111
  processedElement = index === cssInjectionIndex ? /*#__PURE__*/ external_react_default().createElement(external_react_default().Fragment, null, /*#__PURE__*/ external_react_default().createElement(external_CSSLinks_js_namespaceObject.CSSLinks, {
111
112
  cssFiles
112
113
  }), routeElement) : routeElement;
@@ -1,7 +1,7 @@
1
1
  import { cleanRequireCache, isReact18 as utils_isReact18 } from "@modern-js/utils";
2
2
  import path_0 from "path";
3
3
  import { documentPlugin } from "../document/cli/index.mjs";
4
- import { getEntrypointRoutesDir, getEntrypointRoutesOwner, handleFileChange, handleGeneratorEntryCode, handleModifyEntrypoints, isRouteEntry, routerPlugin } from "../router/cli/index.mjs";
4
+ import { getEntrypointRoutesDir, getEntrypointRoutesOwner, handleFileChange, handleGeneratorEntryCode, handleModifyEntrypoints, isRouteEntry, routerPlugin, updateNestedRoutesSpec } from "../router/cli/index.mjs";
5
5
  import { builderPluginAlias } from "./alias.mjs";
6
6
  import { generateCode } from "./code.mjs";
7
7
  import { ENTRY_BOOTSTRAP_FILE_NAME, ENTRY_POINT_FILE_NAME } from "./constants.mjs";
@@ -92,4 +92,4 @@ const cli = runtimePlugin;
92
92
  export { makeLegalIdentifier } from "../router/cli/code/makeLegalIdentifier.mjs";
93
93
  export { getPathWithoutExt } from "../router/cli/code/utils.mjs";
94
94
  export default cli;
95
- export { documentPlugin, getEntrypointRoutesDir, getEntrypointRoutesOwner, handleFileChange, handleGeneratorEntryCode, handleModifyEntrypoints, isRouteEntry, isRuntimeEntry, routerPlugin, runtimePlugin, ssrPlugin };
95
+ export { documentPlugin, getEntrypointRoutesDir, getEntrypointRoutesOwner, handleFileChange, handleGeneratorEntryCode, handleModifyEntrypoints, isRouteEntry, isRuntimeEntry, routerPlugin, runtimePlugin, ssrPlugin, updateNestedRoutesSpec };
@@ -24,7 +24,7 @@ import {
24
24
  createRequestHandler,
25
25
  } from '@#metaName/runtime/ssr/server';
26
26
  import { RSCServerSlot } from '@#metaName/runtime/rsc/client';
27
- import { renderRsc } from '@#metaName/runtime/rsc/server';
27
+ import { renderCSRWithRSC, renderRsc } from '@#metaName/runtime/rsc/server';
28
28
  export { handleAction } from '@#metaName/runtime/rsc/server';
29
29
 
30
30
  const handleRequest = async (request, ServerRoot, options) => {
@@ -51,6 +51,17 @@ export const requestHandler = createRequestHandler(handleRequest, {
51
51
  enableRsc: true
52
52
  });
53
53
 
54
+ const handleCSRRender = async (request, ServerRoot, options) => {
55
+ return renderCSRWithRSC({
56
+ html: options.html,
57
+ rscRoot: options.rscRoot,
58
+ });
59
+ }
60
+
61
+ export const renderRscStreamHandler = createRequestHandler(handleCSRRender, {
62
+ enableRsc: true
63
+ });
64
+
54
65
  const handleRSCRequest = async (request, ServerRoot, options) => {
55
66
  const { serverPayload } = options;
56
67
  const stream = renderRsc({
@@ -34,8 +34,8 @@ async function buildShellBeforeTemplate(beforeAppTemplate, options) {
34
34
  return safeReplace(template, CHUNK_CSS_PLACEHOLDER, css);
35
35
  async function getCssChunks() {
36
36
  const { routeManifest, routerContext, routes } = runtimeContext;
37
- if (!routeManifest) return '';
38
- const { routeAssets } = routeManifest;
37
+ const routeAssets = routeManifest?.routeAssets;
38
+ if (!routeAssets) return '';
39
39
  let matchedRouteManifests = [];
40
40
  const matchedRouteIds = getRouterMatchedRouteIds(runtimeContext);
41
41
  if (matchedRouteIds?.length) matchedRouteManifests = matchedRouteIds.map((routeId)=>routeAssets[routeId]).filter(Boolean);
@@ -28,8 +28,8 @@ async function buildShellBeforeTemplate(beforeAppTemplate, options) {
28
28
  return safeReplace(template, CHUNK_CSS_PLACEHOLDER, css);
29
29
  async function getCssChunks() {
30
30
  const { routeManifest, routerContext, routes } = runtimeContext;
31
- if (!routeManifest) return '';
32
- const { routeAssets } = routeManifest;
31
+ const routeAssets = routeManifest?.routeAssets;
32
+ if (!routeAssets) return '';
33
33
  let matchedRouteManifests = [];
34
34
  const matchedRouteIds = getRouterMatchedRouteIds(runtimeContext);
35
35
  if (matchedRouteIds?.length) matchedRouteManifests = matchedRouteIds.map((routeId)=>routeAssets[routeId]).filter(Boolean);
@@ -28,10 +28,6 @@ const readAsset = async (chunk)=>{
28
28
  return fs.readFile(filepath, 'utf-8');
29
29
  };
30
30
  class LoadableCollector {
31
- get existsAssets() {
32
- const { routeManifest, entryName } = this.options;
33
- return routeManifest?.routeAssets?.[entryName]?.assets;
34
- }
35
31
  getMatchedRouteChunks() {
36
32
  const { routeManifest, runtimeContext } = this.options;
37
33
  if (!routeManifest) return [];
@@ -98,7 +94,7 @@ class LoadableCollector {
98
94
  const matchs = template.matchAll(jsScriptRegExp);
99
95
  const existedScript = [];
100
96
  for (const match of matchs)existedScript.push(match[1]);
101
- const scripts = await Promise.all(chunks.filter((chunk)=>!existedScript.includes(chunk.url) && !this.existsAssets?.includes(chunk.path)).map(async (chunk)=>{
97
+ const scripts = await Promise.all(chunks.filter((chunk)=>!existedScript.includes(chunk.url)).map(async (chunk)=>{
102
98
  const script = `<script${attributes} src="${chunk.url}"></script>`;
103
99
  if (checkIsNode() && checkIsInline(chunk, inlineStyles)) return readAsset(chunk).then((content)=>`<script>${content}</script>`).catch((_)=>script);
104
100
  return script;
@@ -109,7 +105,7 @@ class LoadableCollector {
109
105
  const { template, chunkSet, config, moduleFederationCssAssets } = this.options;
110
106
  const { inlineStyles } = config;
111
107
  const atrributes = attributesToString(this.generateAttributes());
112
- const emittedChunks = chunks.filter((chunk)=>!hasStylesheetLink(template, chunk.url) && !this.existsAssets?.includes(chunk.path));
108
+ const emittedChunks = chunks.filter((chunk)=>!hasStylesheetLink(template, chunk.url));
113
109
  const css = await Promise.all(emittedChunks.map(async (chunk)=>{
114
110
  const link = `<link${atrributes} href="${chunk.url}" rel="stylesheet" />`;
115
111
  if (checkIsNode() && checkIsInline(chunk, inlineStyles)) return readAsset(chunk).then((content)=>`<style>${content}</style>`).catch((_)=>link);
@@ -3,7 +3,7 @@ import { JS_EXTENSIONS, findExists, formatImportPath, fs, getEntryOptions, isSSG
3
3
  import { ROUTE_MODULES } from "@modern-js/utils/universal/constants";
4
4
  import path from "path";
5
5
  import { APP_INIT_EXPORTED, TEMP_LOADERS_DIR } from "../constants.mjs";
6
- import { getPathWithoutExt, getServerLoadersFile, parseModule, replaceWithAlias } from "./utils.mjs";
6
+ import { getPathWithoutExt, parseModule, replaceWithAlias } from "./utils.mjs";
7
7
  const routesForServer = ({ routesForServerLoaderMatches })=>{
8
8
  const loaders = [];
9
9
  const actions = [];
@@ -169,14 +169,14 @@ const fileSystemRoutes = async ({ metaName, routes, ssrMode, nestedRoutesEntry,
169
169
  routeId: route.id,
170
170
  webpackChunkName: true
171
171
  });
172
- component = 'string' === ssrMode ? `loadable(${lazyImport})` : `lazy(${lazyImport})`;
172
+ component = 'string' === ssrMode ? `loadable(${lazyImport}, { resolveComponent: resolveRouteComponent })` : `lazy(${lazyImport})`;
173
173
  } else {
174
174
  components.push(route._component);
175
175
  component = `component_${components.length - 1}`;
176
176
  }
177
177
  } else if (route._component) if (splitRouteChunks) {
178
178
  lazyImport = `() => import('${route._component}')`;
179
- component = `loadable(${lazyImport})`;
179
+ component = `loadable(${lazyImport}, { resolveComponent: resolveRouteComponent })`;
180
180
  } else {
181
181
  components.push(route._component);
182
182
  component = `component_${components.length - 1}`;
@@ -224,7 +224,7 @@ const fileSystemRoutes = async ({ metaName, routes, ssrMode, nestedRoutesEntry,
224
224
  const newRouteStr = regs.reduce((acc, reg)=>acc.replace(reg, '$1$2'), routeStr).replace(/"(RootLayout)"/g, '$1').replace(/\\"/g, '"');
225
225
  routeComponentsCode += `${newRouteStr},`;
226
226
  } else {
227
- const component = `loadable(() => import('${route._component}'))`;
227
+ const component = `loadable(() => import('${route._component}'), { resolveComponent: resolveRouteComponent })`;
228
228
  const finalRoute = {
229
229
  ...route,
230
230
  component
@@ -274,7 +274,7 @@ const fileSystemRoutes = async ({ metaName, routes, ssrMode, nestedRoutesEntry,
274
274
  await fs.ensureFile(loadersMapFile);
275
275
  await fs.writeJSON(loadersMapFile, loadersMap);
276
276
  const importRuntimeRouterCode = `
277
- import { createShouldRevalidate, handleRouteModule, handleRouteModuleError} from '@${metaName}/runtime/routerHelper';
277
+ import { createShouldRevalidate, handleRouteModule, handleRouteModuleError, resolveRouteComponent } from '@${metaName}/runtime/routerHelper';
278
278
  `;
279
279
  const routeModulesCode = `
280
280
  if(typeof document !== 'undefined'){
@@ -296,19 +296,19 @@ const fileSystemRoutes = async ({ metaName, routes, ssrMode, nestedRoutesEntry,
296
296
  };
297
297
  function ssrLoaderCombinedModule(entrypoints, entrypoint, config, appContext) {
298
298
  const { entryName, isMainEntry } = entrypoint;
299
- const { packageName, internalDirectory } = appContext;
299
+ const { packageName } = appContext;
300
300
  const ssr = getEntryOptions(entryName, isMainEntry, config.server.ssr, config.server.ssrByEntries, packageName);
301
301
  const ssg = isSSGEntry(config, entryName, entrypoints);
302
302
  if (entrypoint.nestedRoutesEntry && (ssr || ssg)) {
303
303
  const serverLoaderRuntime = require.resolve('@modern-js/plugin-data-loader/runtime');
304
- const serverLoadersFile = getServerLoadersFile(internalDirectory, entryName);
305
- const combinedModule = `export * from "${slash(serverLoaderRuntime)}"; export * from "${slash(serverLoadersFile)}"`;
304
+ const serverLoadersFile = './route-server-loaders.js';
305
+ const combinedModule = `export * from "${slash(serverLoaderRuntime)}"; export * from "${serverLoadersFile}"`;
306
306
  if (!config.source.enableAsyncEntry) return combinedModule;
307
307
  return `
308
308
  async function loadModules() {
309
309
  const [moduleA, moduleB] = await Promise.all([
310
310
  import("${slash(serverLoaderRuntime)}"),
311
- import("${slash(serverLoadersFile)}")
311
+ import("${serverLoadersFile}")
312
312
  ]);
313
313
 
314
314
  return {
@@ -1,8 +1,9 @@
1
1
  import node_path from "node:path";
2
- import { NESTED_ROUTE_SPEC_FILE, filterRoutesForServer, fs } from "@modern-js/utils";
2
+ import { NESTED_ROUTE_SPEC_FILE, filterRoutesForServer } from "@modern-js/utils";
3
3
  import { NESTED_ROUTES_DIR } from "./constants.mjs";
4
4
  import { BUILT_IN_ROUTES_OWNER, getEntrypointRoutesDir, getEntrypointRoutesOwner, isRouteEntry } from "./entry.mjs";
5
5
  import { handleFileChange, handleGeneratorEntryCode, handleModifyEntrypoints } from "./handler.mjs";
6
+ import { updateNestedRoutesSpec } from "./nestedRoutesSpec.mjs";
6
7
  function isBuiltInRouteEntrypoint(entrypoint) {
7
8
  const entrypointRoutesOwner = getEntrypointRoutesOwner(entrypoint);
8
9
  if (entrypointRoutesOwner) return entrypointRoutesOwner === BUILT_IN_ROUTES_OWNER;
@@ -87,11 +88,7 @@ const routerPlugin = ()=>({
87
88
  if (isBuiltInRouteEntrypoint(entrypoint)) {
88
89
  const { distDirectory } = api.getAppContext();
89
90
  const nestedRoutesSpecPath = node_path.resolve(distDirectory, NESTED_ROUTE_SPEC_FILE);
90
- const existingNestedRoutes = await fs.pathExists(nestedRoutesSpecPath) ? await fs.readJSON(nestedRoutesSpecPath) : {};
91
- await fs.outputJSON(nestedRoutesSpecPath, {
92
- ...existingNestedRoutes,
93
- ...nestedRoutesForServer
94
- });
91
+ await updateNestedRoutesSpec(nestedRoutesSpecPath, nestedRoutesForServer);
95
92
  }
96
93
  return {
97
94
  entrypoint,
@@ -102,4 +99,4 @@ const routerPlugin = ()=>({
102
99
  });
103
100
  const cli = routerPlugin;
104
101
  export default cli;
105
- export { BUILT_IN_ROUTES_OWNER, getEntrypointRoutesDir, getEntrypointRoutesOwner, handleFileChange, handleGeneratorEntryCode, handleModifyEntrypoints, isRouteEntry, routerPlugin };
102
+ export { BUILT_IN_ROUTES_OWNER, getEntrypointRoutesDir, getEntrypointRoutesOwner, handleFileChange, handleGeneratorEntryCode, handleModifyEntrypoints, isRouteEntry, routerPlugin, updateNestedRoutesSpec };
@@ -0,0 +1,66 @@
1
+ import node_path from "node:path";
2
+ import { setTimeout as promises_setTimeout } from "node:timers/promises";
3
+ import { fs } from "@modern-js/utils";
4
+ const lockPollIntervalMs = 25;
5
+ const staleLockAgeMs = 120000;
6
+ const pendingUpdates = new Map();
7
+ let tempFileCounter = 0;
8
+ async function acquireSpecLock(specPath) {
9
+ const lockDir = `${specPath}.lock`;
10
+ await fs.ensureDir(node_path.dirname(specPath));
11
+ while(true){
12
+ try {
13
+ await fs.mkdir(lockDir);
14
+ return async ()=>{
15
+ await fs.remove(lockDir);
16
+ };
17
+ } catch (error) {
18
+ if ('EEXIST' !== error.code) throw error;
19
+ }
20
+ try {
21
+ const stat = await fs.stat(lockDir);
22
+ if (performance.timeOrigin + performance.now() - stat.mtimeMs > staleLockAgeMs) {
23
+ await fs.remove(lockDir);
24
+ continue;
25
+ }
26
+ } catch (error) {
27
+ if ('ENOENT' !== error.code) throw error;
28
+ continue;
29
+ }
30
+ await promises_setTimeout(lockPollIntervalMs);
31
+ }
32
+ }
33
+ async function writeJSONAtomically(filePath, value) {
34
+ const directory = node_path.dirname(filePath);
35
+ const tempPath = node_path.join(directory, `.${node_path.basename(filePath)}.${process.pid}.${tempFileCounter += 1}.tmp`);
36
+ try {
37
+ await fs.writeFile(tempPath, `${JSON.stringify(value)}\n`);
38
+ await fs.rename(tempPath, filePath);
39
+ } catch (error) {
40
+ await fs.remove(tempPath).catch(()=>{});
41
+ throw error;
42
+ }
43
+ }
44
+ async function updateNestedRoutesSpec(specPath, nextRoutes) {
45
+ const resolvedSpecPath = node_path.resolve(specPath);
46
+ const previousUpdate = pendingUpdates.get(resolvedSpecPath) ?? Promise.resolve();
47
+ const currentUpdate = previousUpdate.catch(()=>void 0).then(async ()=>{
48
+ const releaseLock = await acquireSpecLock(resolvedSpecPath);
49
+ try {
50
+ const existingRoutes = await fs.pathExists(resolvedSpecPath) ? await fs.readJSON(resolvedSpecPath) : {};
51
+ await writeJSONAtomically(resolvedSpecPath, {
52
+ ...existingRoutes,
53
+ ...nextRoutes
54
+ });
55
+ } finally{
56
+ await releaseLock();
57
+ }
58
+ });
59
+ pendingUpdates.set(resolvedSpecPath, currentUpdate);
60
+ try {
61
+ await currentUpdate;
62
+ } finally{
63
+ if (pendingUpdates.get(resolvedSpecPath) === currentUpdate) pendingUpdates.delete(resolvedSpecPath);
64
+ }
65
+ }
66
+ export { updateNestedRoutesSpec };
@@ -1,15 +1,54 @@
1
1
  import { ROUTE_MODULES } from "@modern-js/utils/universal/constants";
2
+ const isObjectLike = (value)=>'object' == typeof value && null !== value || 'function' == typeof value;
3
+ const isRouteComponent = (value)=>'function' == typeof value || isObjectLike(value) && '$$typeof' in value;
4
+ const getRouteModules = ()=>{
5
+ if ("u" < typeof window) return;
6
+ return window[ROUTE_MODULES];
7
+ };
8
+ const storeRouteModule = (routeModule, routeId)=>{
9
+ if ("u" < typeof document) return;
10
+ const routeModules = getRouteModules();
11
+ if (void 0 !== routeModules) routeModules[routeId] = routeModule;
12
+ };
13
+ const unwrapRspackAsyncModule = (routeModule)=>{
14
+ if (!isObjectLike(routeModule)) return routeModule;
15
+ const rspackExportsSymbol = Object.getOwnPropertySymbols(routeModule).find((symbol)=>'rspack exports' === symbol.description);
16
+ if (void 0 !== rspackExportsSymbol) return routeModule[rspackExportsSymbol];
17
+ if ('__webpack_exports__' in routeModule) return routeModule.__webpack_exports__;
18
+ return routeModule;
19
+ };
2
20
  const createShouldRevalidate = (routeId)=>(arg)=>{
3
- const routeModule = "u" > typeof window ? window?.[ROUTE_MODULES]?.[routeId] : void 0;
4
- if (routeModule && 'function' == typeof routeModule.shouldRevalidate) return routeModule.shouldRevalidate(arg);
21
+ const routeModule = getRouteModules()?.[routeId];
22
+ if (isObjectLike(routeModule)) {
23
+ const shouldRevalidate = routeModule.shouldRevalidate;
24
+ if ('function' == typeof shouldRevalidate) return shouldRevalidate(arg);
25
+ }
5
26
  return arg.defaultShouldRevalidate;
6
27
  };
28
+ const pickRouteModuleComponent = (routeModule, seen = new Set())=>{
29
+ const unwrappedRouteModule = unwrapRspackAsyncModule(routeModule);
30
+ if (isRouteComponent(unwrappedRouteModule)) return unwrappedRouteModule;
31
+ if (!isObjectLike(unwrappedRouteModule) || seen.has(unwrappedRouteModule)) return;
32
+ seen.add(unwrappedRouteModule);
33
+ const componentModule = unwrappedRouteModule;
34
+ for (const candidate of [
35
+ componentModule.default,
36
+ componentModule.Component
37
+ ]){
38
+ const component = pickRouteModuleComponent(candidate, seen);
39
+ if (void 0 !== component) return component;
40
+ }
41
+ };
42
+ const resolveRouteComponent = (routeModule)=>pickRouteModuleComponent(routeModule) ?? routeModule;
7
43
  const handleRouteModule = (routeModule, routeId)=>{
8
- if ("u" > typeof document) window[ROUTE_MODULES][routeId] = routeModule;
9
- return routeModule;
44
+ storeRouteModule(routeModule, routeId);
45
+ const component = pickRouteModuleComponent(routeModule);
46
+ return void 0 !== component ? {
47
+ default: component
48
+ } : routeModule;
10
49
  };
11
50
  const handleRouteModuleError = (error)=>{
12
51
  console.error(error);
13
52
  return null;
14
53
  };
15
- export { createShouldRevalidate, handleRouteModule, handleRouteModuleError };
54
+ export { createShouldRevalidate, handleRouteModule, handleRouteModuleError, resolveRouteComponent };
@@ -44,10 +44,10 @@ const createServerPayload = (routerContext, routes)=>{
44
44
  routes: routerContext.matches.map((match, index, matches)=>{
45
45
  const route = match.route;
46
46
  const element = route.element;
47
+ const Component = route.Component;
47
48
  const parentMatch = index > 0 ? matches[index - 1] : void 0;
48
49
  let processedElement;
49
- if (element) {
50
- const ElementComponent = element.type;
50
+ if (element || Component) {
51
51
  const elementProps = {
52
52
  loaderData: routerContext?.loaderData?.[route.id],
53
53
  actionData: routerContext?.actionData?.[route.id],
@@ -60,7 +60,8 @@ const createServerPayload = (routerContext, routes)=>{
60
60
  handle: m.route.handle
61
61
  }))
62
62
  };
63
- const routeElement = /*#__PURE__*/ react.createElement(ElementComponent, elementProps);
63
+ const RouteComponent = Component;
64
+ const routeElement = element ? /*#__PURE__*/ react.cloneElement(element, elementProps) : /*#__PURE__*/ react.createElement(RouteComponent, elementProps);
64
65
  processedElement = index === cssInjectionIndex ? /*#__PURE__*/ react.createElement(react.Fragment, null, /*#__PURE__*/ react.createElement(CSSLinks, {
65
66
  cssFiles
66
67
  }), routeElement) : routeElement;
@@ -3,7 +3,7 @@ const require = /*#__PURE__*/ __rslib_shim_module__.createRequire(/*#__PURE__*/
3
3
  import { cleanRequireCache, isReact18 as utils_isReact18 } from "@modern-js/utils";
4
4
  import path_0 from "path";
5
5
  import { documentPlugin } from "../document/cli/index.mjs";
6
- import { getEntrypointRoutesDir, getEntrypointRoutesOwner, handleFileChange, handleGeneratorEntryCode, handleModifyEntrypoints, isRouteEntry, routerPlugin } from "../router/cli/index.mjs";
6
+ import { getEntrypointRoutesDir, getEntrypointRoutesOwner, handleFileChange, handleGeneratorEntryCode, handleModifyEntrypoints, isRouteEntry, routerPlugin, updateNestedRoutesSpec } from "../router/cli/index.mjs";
7
7
  import { builderPluginAlias } from "./alias.mjs";
8
8
  import { generateCode } from "./code.mjs";
9
9
  import { ENTRY_BOOTSTRAP_FILE_NAME, ENTRY_POINT_FILE_NAME } from "./constants.mjs";
@@ -94,4 +94,4 @@ const cli = runtimePlugin;
94
94
  export { makeLegalIdentifier } from "../router/cli/code/makeLegalIdentifier.mjs";
95
95
  export { getPathWithoutExt } from "../router/cli/code/utils.mjs";
96
96
  export default cli;
97
- export { documentPlugin, getEntrypointRoutesDir, getEntrypointRoutesOwner, handleFileChange, handleGeneratorEntryCode, handleModifyEntrypoints, isRouteEntry, isRuntimeEntry, routerPlugin, runtimePlugin, ssrPlugin };
97
+ export { documentPlugin, getEntrypointRoutesDir, getEntrypointRoutesOwner, handleFileChange, handleGeneratorEntryCode, handleModifyEntrypoints, isRouteEntry, isRuntimeEntry, routerPlugin, runtimePlugin, ssrPlugin, updateNestedRoutesSpec };
@@ -25,7 +25,7 @@ import {
25
25
  createRequestHandler,
26
26
  } from '@#metaName/runtime/ssr/server';
27
27
  import { RSCServerSlot } from '@#metaName/runtime/rsc/client';
28
- import { renderRsc } from '@#metaName/runtime/rsc/server';
28
+ import { renderCSRWithRSC, renderRsc } from '@#metaName/runtime/rsc/server';
29
29
  export { handleAction } from '@#metaName/runtime/rsc/server';
30
30
 
31
31
  const handleRequest = async (request, ServerRoot, options) => {
@@ -52,6 +52,17 @@ export const requestHandler = createRequestHandler(handleRequest, {
52
52
  enableRsc: true
53
53
  });
54
54
 
55
+ const handleCSRRender = async (request, ServerRoot, options) => {
56
+ return renderCSRWithRSC({
57
+ html: options.html,
58
+ rscRoot: options.rscRoot,
59
+ });
60
+ }
61
+
62
+ export const renderRscStreamHandler = createRequestHandler(handleCSRRender, {
63
+ enableRsc: true
64
+ });
65
+
55
66
  const handleRSCRequest = async (request, ServerRoot, options) => {
56
67
  const { serverPayload } = options;
57
68
  const stream = renderRsc({
@@ -38,8 +38,8 @@ async function buildShellBeforeTemplate(beforeAppTemplate, options) {
38
38
  return safeReplace(template, CHUNK_CSS_PLACEHOLDER, css);
39
39
  async function getCssChunks() {
40
40
  const { routeManifest, routerContext, routes } = runtimeContext;
41
- if (!routeManifest) return '';
42
- const { routeAssets } = routeManifest;
41
+ const routeAssets = routeManifest?.routeAssets;
42
+ if (!routeAssets) return '';
43
43
  let matchedRouteManifests = [];
44
44
  const matchedRouteIds = getRouterMatchedRouteIds(runtimeContext);
45
45
  if (matchedRouteIds?.length) matchedRouteManifests = matchedRouteIds.map((routeId)=>routeAssets[routeId]).filter(Boolean);
@@ -29,8 +29,8 @@ async function buildShellBeforeTemplate(beforeAppTemplate, options) {
29
29
  return safeReplace(template, CHUNK_CSS_PLACEHOLDER, css);
30
30
  async function getCssChunks() {
31
31
  const { routeManifest, routerContext, routes } = runtimeContext;
32
- if (!routeManifest) return '';
33
- const { routeAssets } = routeManifest;
32
+ const routeAssets = routeManifest?.routeAssets;
33
+ if (!routeAssets) return '';
34
34
  let matchedRouteManifests = [];
35
35
  const matchedRouteIds = getRouterMatchedRouteIds(runtimeContext);
36
36
  if (matchedRouteIds?.length) matchedRouteManifests = matchedRouteIds.map((routeId)=>routeAssets[routeId]).filter(Boolean);
@@ -32,10 +32,6 @@ const readAsset = async (chunk)=>{
32
32
  return fs.readFile(filepath, 'utf-8');
33
33
  };
34
34
  class LoadableCollector {
35
- get existsAssets() {
36
- const { routeManifest, entryName } = this.options;
37
- return routeManifest?.routeAssets?.[entryName]?.assets;
38
- }
39
35
  getMatchedRouteChunks() {
40
36
  const { routeManifest, runtimeContext } = this.options;
41
37
  if (!routeManifest) return [];
@@ -102,7 +98,7 @@ class LoadableCollector {
102
98
  const matchs = template.matchAll(jsScriptRegExp);
103
99
  const existedScript = [];
104
100
  for (const match of matchs)existedScript.push(match[1]);
105
- const scripts = await Promise.all(chunks.filter((chunk)=>!existedScript.includes(chunk.url) && !this.existsAssets?.includes(chunk.path)).map(async (chunk)=>{
101
+ const scripts = await Promise.all(chunks.filter((chunk)=>!existedScript.includes(chunk.url)).map(async (chunk)=>{
106
102
  const script = `<script${attributes} src="${chunk.url}"></script>`;
107
103
  if (checkIsNode() && checkIsInline(chunk, inlineStyles)) return readAsset(chunk).then((content)=>`<script>${content}</script>`).catch((_)=>script);
108
104
  return script;
@@ -113,7 +109,7 @@ class LoadableCollector {
113
109
  const { template, chunkSet, config, moduleFederationCssAssets } = this.options;
114
110
  const { inlineStyles } = config;
115
111
  const atrributes = attributesToString(this.generateAttributes());
116
- const emittedChunks = chunks.filter((chunk)=>!hasStylesheetLink(template, chunk.url) && !this.existsAssets?.includes(chunk.path));
112
+ const emittedChunks = chunks.filter((chunk)=>!hasStylesheetLink(template, chunk.url));
117
113
  const css = await Promise.all(emittedChunks.map(async (chunk)=>{
118
114
  const link = `<link${atrributes} href="${chunk.url}" rel="stylesheet" />`;
119
115
  if (checkIsNode() && checkIsInline(chunk, inlineStyles)) return readAsset(chunk).then((content)=>`<style>${content}</style>`).catch((_)=>link);
@@ -5,7 +5,7 @@ import { JS_EXTENSIONS, findExists, formatImportPath, fs, getEntryOptions, isSSG
5
5
  import { ROUTE_MODULES } from "@modern-js/utils/universal/constants";
6
6
  import path from "path";
7
7
  import { APP_INIT_EXPORTED, TEMP_LOADERS_DIR } from "../constants.mjs";
8
- import { getPathWithoutExt, getServerLoadersFile, parseModule, replaceWithAlias } from "./utils.mjs";
8
+ import { getPathWithoutExt, parseModule, replaceWithAlias } from "./utils.mjs";
9
9
  const routesForServer = ({ routesForServerLoaderMatches })=>{
10
10
  const loaders = [];
11
11
  const actions = [];
@@ -171,14 +171,14 @@ const fileSystemRoutes = async ({ metaName, routes, ssrMode, nestedRoutesEntry,
171
171
  routeId: route.id,
172
172
  webpackChunkName: true
173
173
  });
174
- component = 'string' === ssrMode ? `loadable(${lazyImport})` : `lazy(${lazyImport})`;
174
+ component = 'string' === ssrMode ? `loadable(${lazyImport}, { resolveComponent: resolveRouteComponent })` : `lazy(${lazyImport})`;
175
175
  } else {
176
176
  components.push(route._component);
177
177
  component = `component_${components.length - 1}`;
178
178
  }
179
179
  } else if (route._component) if (splitRouteChunks) {
180
180
  lazyImport = `() => import('${route._component}')`;
181
- component = `loadable(${lazyImport})`;
181
+ component = `loadable(${lazyImport}, { resolveComponent: resolveRouteComponent })`;
182
182
  } else {
183
183
  components.push(route._component);
184
184
  component = `component_${components.length - 1}`;
@@ -226,7 +226,7 @@ const fileSystemRoutes = async ({ metaName, routes, ssrMode, nestedRoutesEntry,
226
226
  const newRouteStr = regs.reduce((acc, reg)=>acc.replace(reg, '$1$2'), routeStr).replace(/"(RootLayout)"/g, '$1').replace(/\\"/g, '"');
227
227
  routeComponentsCode += `${newRouteStr},`;
228
228
  } else {
229
- const component = `loadable(() => import('${route._component}'))`;
229
+ const component = `loadable(() => import('${route._component}'), { resolveComponent: resolveRouteComponent })`;
230
230
  const finalRoute = {
231
231
  ...route,
232
232
  component
@@ -276,7 +276,7 @@ const fileSystemRoutes = async ({ metaName, routes, ssrMode, nestedRoutesEntry,
276
276
  await fs.ensureFile(loadersMapFile);
277
277
  await fs.writeJSON(loadersMapFile, loadersMap);
278
278
  const importRuntimeRouterCode = `
279
- import { createShouldRevalidate, handleRouteModule, handleRouteModuleError} from '@${metaName}/runtime/routerHelper';
279
+ import { createShouldRevalidate, handleRouteModule, handleRouteModuleError, resolveRouteComponent } from '@${metaName}/runtime/routerHelper';
280
280
  `;
281
281
  const routeModulesCode = `
282
282
  if(typeof document !== 'undefined'){
@@ -298,19 +298,19 @@ const fileSystemRoutes = async ({ metaName, routes, ssrMode, nestedRoutesEntry,
298
298
  };
299
299
  function ssrLoaderCombinedModule(entrypoints, entrypoint, config, appContext) {
300
300
  const { entryName, isMainEntry } = entrypoint;
301
- const { packageName, internalDirectory } = appContext;
301
+ const { packageName } = appContext;
302
302
  const ssr = getEntryOptions(entryName, isMainEntry, config.server.ssr, config.server.ssrByEntries, packageName);
303
303
  const ssg = isSSGEntry(config, entryName, entrypoints);
304
304
  if (entrypoint.nestedRoutesEntry && (ssr || ssg)) {
305
305
  const serverLoaderRuntime = require.resolve('@modern-js/plugin-data-loader/runtime');
306
- const serverLoadersFile = getServerLoadersFile(internalDirectory, entryName);
307
- const combinedModule = `export * from "${slash(serverLoaderRuntime)}"; export * from "${slash(serverLoadersFile)}"`;
306
+ const serverLoadersFile = './route-server-loaders.js';
307
+ const combinedModule = `export * from "${slash(serverLoaderRuntime)}"; export * from "${serverLoadersFile}"`;
308
308
  if (!config.source.enableAsyncEntry) return combinedModule;
309
309
  return `
310
310
  async function loadModules() {
311
311
  const [moduleA, moduleB] = await Promise.all([
312
312
  import("${slash(serverLoaderRuntime)}"),
313
- import("${slash(serverLoadersFile)}")
313
+ import("${serverLoadersFile}")
314
314
  ]);
315
315
 
316
316
  return {
@@ -1,9 +1,10 @@
1
1
  import "node:module";
2
2
  import node_path from "node:path";
3
- import { NESTED_ROUTE_SPEC_FILE, filterRoutesForServer, fs } from "@modern-js/utils";
3
+ import { NESTED_ROUTE_SPEC_FILE, filterRoutesForServer } from "@modern-js/utils";
4
4
  import { NESTED_ROUTES_DIR } from "./constants.mjs";
5
5
  import { BUILT_IN_ROUTES_OWNER, getEntrypointRoutesDir, getEntrypointRoutesOwner, isRouteEntry } from "./entry.mjs";
6
6
  import { handleFileChange, handleGeneratorEntryCode, handleModifyEntrypoints } from "./handler.mjs";
7
+ import { updateNestedRoutesSpec } from "./nestedRoutesSpec.mjs";
7
8
  import { fileURLToPath as __rspack_fileURLToPath } from "node:url";
8
9
  import { dirname as __rspack_dirname } from "node:path";
9
10
  var cli_dirname = __rspack_dirname(__rspack_fileURLToPath(import.meta.url));
@@ -91,11 +92,7 @@ const routerPlugin = ()=>({
91
92
  if (isBuiltInRouteEntrypoint(entrypoint)) {
92
93
  const { distDirectory } = api.getAppContext();
93
94
  const nestedRoutesSpecPath = node_path.resolve(distDirectory, NESTED_ROUTE_SPEC_FILE);
94
- const existingNestedRoutes = await fs.pathExists(nestedRoutesSpecPath) ? await fs.readJSON(nestedRoutesSpecPath) : {};
95
- await fs.outputJSON(nestedRoutesSpecPath, {
96
- ...existingNestedRoutes,
97
- ...nestedRoutesForServer
98
- });
95
+ await updateNestedRoutesSpec(nestedRoutesSpecPath, nestedRoutesForServer);
99
96
  }
100
97
  return {
101
98
  entrypoint,
@@ -106,4 +103,4 @@ const routerPlugin = ()=>({
106
103
  });
107
104
  const cli = routerPlugin;
108
105
  export default cli;
109
- export { BUILT_IN_ROUTES_OWNER, getEntrypointRoutesDir, getEntrypointRoutesOwner, handleFileChange, handleGeneratorEntryCode, handleModifyEntrypoints, isRouteEntry, routerPlugin };
106
+ export { BUILT_IN_ROUTES_OWNER, getEntrypointRoutesDir, getEntrypointRoutesOwner, handleFileChange, handleGeneratorEntryCode, handleModifyEntrypoints, isRouteEntry, routerPlugin, updateNestedRoutesSpec };
@@ -0,0 +1,67 @@
1
+ import "node:module";
2
+ import node_path from "node:path";
3
+ import { setTimeout as promises_setTimeout } from "node:timers/promises";
4
+ import { fs } from "@modern-js/utils";
5
+ const lockPollIntervalMs = 25;
6
+ const staleLockAgeMs = 120000;
7
+ const pendingUpdates = new Map();
8
+ let tempFileCounter = 0;
9
+ async function acquireSpecLock(specPath) {
10
+ const lockDir = `${specPath}.lock`;
11
+ await fs.ensureDir(node_path.dirname(specPath));
12
+ while(true){
13
+ try {
14
+ await fs.mkdir(lockDir);
15
+ return async ()=>{
16
+ await fs.remove(lockDir);
17
+ };
18
+ } catch (error) {
19
+ if ('EEXIST' !== error.code) throw error;
20
+ }
21
+ try {
22
+ const stat = await fs.stat(lockDir);
23
+ if (performance.timeOrigin + performance.now() - stat.mtimeMs > staleLockAgeMs) {
24
+ await fs.remove(lockDir);
25
+ continue;
26
+ }
27
+ } catch (error) {
28
+ if ('ENOENT' !== error.code) throw error;
29
+ continue;
30
+ }
31
+ await promises_setTimeout(lockPollIntervalMs);
32
+ }
33
+ }
34
+ async function writeJSONAtomically(filePath, value) {
35
+ const directory = node_path.dirname(filePath);
36
+ const tempPath = node_path.join(directory, `.${node_path.basename(filePath)}.${process.pid}.${tempFileCounter += 1}.tmp`);
37
+ try {
38
+ await fs.writeFile(tempPath, `${JSON.stringify(value)}\n`);
39
+ await fs.rename(tempPath, filePath);
40
+ } catch (error) {
41
+ await fs.remove(tempPath).catch(()=>{});
42
+ throw error;
43
+ }
44
+ }
45
+ async function updateNestedRoutesSpec(specPath, nextRoutes) {
46
+ const resolvedSpecPath = node_path.resolve(specPath);
47
+ const previousUpdate = pendingUpdates.get(resolvedSpecPath) ?? Promise.resolve();
48
+ const currentUpdate = previousUpdate.catch(()=>void 0).then(async ()=>{
49
+ const releaseLock = await acquireSpecLock(resolvedSpecPath);
50
+ try {
51
+ const existingRoutes = await fs.pathExists(resolvedSpecPath) ? await fs.readJSON(resolvedSpecPath) : {};
52
+ await writeJSONAtomically(resolvedSpecPath, {
53
+ ...existingRoutes,
54
+ ...nextRoutes
55
+ });
56
+ } finally{
57
+ await releaseLock();
58
+ }
59
+ });
60
+ pendingUpdates.set(resolvedSpecPath, currentUpdate);
61
+ try {
62
+ await currentUpdate;
63
+ } finally{
64
+ if (pendingUpdates.get(resolvedSpecPath) === currentUpdate) pendingUpdates.delete(resolvedSpecPath);
65
+ }
66
+ }
67
+ export { updateNestedRoutesSpec };
@@ -1,16 +1,55 @@
1
1
  import "node:module";
2
2
  import { ROUTE_MODULES } from "@modern-js/utils/universal/constants";
3
+ const isObjectLike = (value)=>'object' == typeof value && null !== value || 'function' == typeof value;
4
+ const isRouteComponent = (value)=>'function' == typeof value || isObjectLike(value) && '$$typeof' in value;
5
+ const getRouteModules = ()=>{
6
+ if ("u" < typeof window) return;
7
+ return window[ROUTE_MODULES];
8
+ };
9
+ const storeRouteModule = (routeModule, routeId)=>{
10
+ if ("u" < typeof document) return;
11
+ const routeModules = getRouteModules();
12
+ if (void 0 !== routeModules) routeModules[routeId] = routeModule;
13
+ };
14
+ const unwrapRspackAsyncModule = (routeModule)=>{
15
+ if (!isObjectLike(routeModule)) return routeModule;
16
+ const rspackExportsSymbol = Object.getOwnPropertySymbols(routeModule).find((symbol)=>'rspack exports' === symbol.description);
17
+ if (void 0 !== rspackExportsSymbol) return routeModule[rspackExportsSymbol];
18
+ if ('__webpack_exports__' in routeModule) return routeModule.__webpack_exports__;
19
+ return routeModule;
20
+ };
3
21
  const createShouldRevalidate = (routeId)=>(arg)=>{
4
- const routeModule = "u" > typeof window ? window?.[ROUTE_MODULES]?.[routeId] : void 0;
5
- if (routeModule && 'function' == typeof routeModule.shouldRevalidate) return routeModule.shouldRevalidate(arg);
22
+ const routeModule = getRouteModules()?.[routeId];
23
+ if (isObjectLike(routeModule)) {
24
+ const shouldRevalidate = routeModule.shouldRevalidate;
25
+ if ('function' == typeof shouldRevalidate) return shouldRevalidate(arg);
26
+ }
6
27
  return arg.defaultShouldRevalidate;
7
28
  };
29
+ const pickRouteModuleComponent = (routeModule, seen = new Set())=>{
30
+ const unwrappedRouteModule = unwrapRspackAsyncModule(routeModule);
31
+ if (isRouteComponent(unwrappedRouteModule)) return unwrappedRouteModule;
32
+ if (!isObjectLike(unwrappedRouteModule) || seen.has(unwrappedRouteModule)) return;
33
+ seen.add(unwrappedRouteModule);
34
+ const componentModule = unwrappedRouteModule;
35
+ for (const candidate of [
36
+ componentModule.default,
37
+ componentModule.Component
38
+ ]){
39
+ const component = pickRouteModuleComponent(candidate, seen);
40
+ if (void 0 !== component) return component;
41
+ }
42
+ };
43
+ const resolveRouteComponent = (routeModule)=>pickRouteModuleComponent(routeModule) ?? routeModule;
8
44
  const handleRouteModule = (routeModule, routeId)=>{
9
- if ("u" > typeof document) window[ROUTE_MODULES][routeId] = routeModule;
10
- return routeModule;
45
+ storeRouteModule(routeModule, routeId);
46
+ const component = pickRouteModuleComponent(routeModule);
47
+ return void 0 !== component ? {
48
+ default: component
49
+ } : routeModule;
11
50
  };
12
51
  const handleRouteModuleError = (error)=>{
13
52
  console.error(error);
14
53
  return null;
15
54
  };
16
- export { createShouldRevalidate, handleRouteModule, handleRouteModuleError };
55
+ export { createShouldRevalidate, handleRouteModule, handleRouteModuleError, resolveRouteComponent };
@@ -45,10 +45,10 @@ const createServerPayload = (routerContext, routes)=>{
45
45
  routes: routerContext.matches.map((match, index, matches)=>{
46
46
  const route = match.route;
47
47
  const element = route.element;
48
+ const Component = route.Component;
48
49
  const parentMatch = index > 0 ? matches[index - 1] : void 0;
49
50
  let processedElement;
50
- if (element) {
51
- const ElementComponent = element.type;
51
+ if (element || Component) {
52
52
  const elementProps = {
53
53
  loaderData: routerContext?.loaderData?.[route.id],
54
54
  actionData: routerContext?.actionData?.[route.id],
@@ -61,7 +61,8 @@ const createServerPayload = (routerContext, routes)=>{
61
61
  handle: m.route.handle
62
62
  }))
63
63
  };
64
- const routeElement = /*#__PURE__*/ react.createElement(ElementComponent, elementProps);
64
+ const RouteComponent = Component;
65
+ const routeElement = element ? /*#__PURE__*/ react.cloneElement(element, elementProps) : /*#__PURE__*/ react.createElement(RouteComponent, elementProps);
65
66
  processedElement = index === cssInjectionIndex ? /*#__PURE__*/ react.createElement(react.Fragment, null, /*#__PURE__*/ react.createElement(CSSLinks, {
66
67
  cssFiles
67
68
  }), routeElement) : routeElement;
@@ -2,7 +2,7 @@ import type { AppTools, CliPlugin } from '@modern-js/app-tools';
2
2
  import { documentPlugin } from '../document/cli';
3
3
  import { routerPlugin } from '../router/cli';
4
4
  import { ssrPlugin } from './ssr';
5
- export { getEntrypointRoutesDir, getEntrypointRoutesOwner, handleFileChange, handleGeneratorEntryCode, handleModifyEntrypoints, isRouteEntry, } from '../router/cli';
5
+ export { getEntrypointRoutesDir, getEntrypointRoutesOwner, handleFileChange, handleGeneratorEntryCode, handleModifyEntrypoints, isRouteEntry, updateNestedRoutesSpec, } from '../router/cli';
6
6
  export { makeLegalIdentifier } from '../router/cli/code/makeLegalIdentifier';
7
7
  export { getPathWithoutExt } from '../router/cli/code/utils';
8
8
  export { isRuntimeEntry } from './entry';
@@ -30,7 +30,6 @@ export declare class LoadableCollector implements Collector {
30
30
  private options;
31
31
  private extractor?;
32
32
  constructor(options: LoadableCollectorOptions);
33
- private get existsAssets();
34
33
  private getMatchedRouteChunks;
35
34
  collect(comopnent: ReactElement): ReactElement;
36
35
  effect(): Promise<void>;
@@ -1,5 +1,6 @@
1
1
  import type { AppTools, CliPlugin } from '@modern-js/app-tools';
2
2
  export { BUILT_IN_ROUTES_OWNER, getEntrypointRoutesDir, getEntrypointRoutesOwner, isRouteEntry, } from './entry';
3
3
  export { handleFileChange, handleGeneratorEntryCode, handleModifyEntrypoints, } from './handler';
4
+ export { updateNestedRoutesSpec } from './nestedRoutesSpec';
4
5
  export declare const routerPlugin: () => CliPlugin<AppTools>;
5
6
  export default routerPlugin;
@@ -0,0 +1 @@
1
+ export declare function updateNestedRoutesSpec(specPath: string, nextRoutes: Record<string, unknown>): Promise<void>;
@@ -1,5 +1,6 @@
1
1
  import type { ShouldRevalidateFunction } from '@modern-js/runtime-utils/router';
2
- import type Module from 'module';
2
+ import type { ElementType } from 'react';
3
3
  export declare const createShouldRevalidate: (routeId: string) => ShouldRevalidateFunction;
4
- export declare const handleRouteModule: (routeModule: Module, routeId: string) => Module;
4
+ export declare const resolveRouteComponent: (routeModule: unknown) => ElementType<Record<string, unknown>>;
5
+ export declare const handleRouteModule: (routeModule: unknown, routeId: string) => unknown;
5
6
  export declare const handleRouteModuleError: (error: Error) => null;
package/package.json CHANGED
@@ -17,7 +17,7 @@
17
17
  "modern",
18
18
  "modern.js"
19
19
  ],
20
- "version": "3.4.0-ultramodern.2",
20
+ "version": "3.4.0-ultramodern.20",
21
21
  "engines": {
22
22
  "node": ">=20"
23
23
  },
@@ -240,12 +240,12 @@
240
240
  "react-helmet": "^6.1.0",
241
241
  "react-helmet-async": "3.0.0",
242
242
  "react-is": "^19.2.7",
243
- "@modern-js/plugin-data-loader": "npm:@bleedingdev/modern-js-plugin-data-loader@3.4.0-ultramodern.2",
244
- "@modern-js/runtime-utils": "npm:@bleedingdev/modern-js-runtime-utils@3.4.0-ultramodern.2",
245
- "@modern-js/render": "npm:@bleedingdev/modern-js-render@3.4.0-ultramodern.2",
246
- "@modern-js/plugin": "npm:@bleedingdev/modern-js-plugin@3.4.0-ultramodern.2",
247
- "@modern-js/types": "npm:@bleedingdev/modern-js-types@3.4.0-ultramodern.2",
248
- "@modern-js/utils": "npm:@bleedingdev/modern-js-utils@3.4.0-ultramodern.2"
243
+ "@modern-js/plugin": "npm:@bleedingdev/modern-js-plugin@3.4.0-ultramodern.20",
244
+ "@modern-js/plugin-data-loader": "npm:@bleedingdev/modern-js-plugin-data-loader@3.4.0-ultramodern.20",
245
+ "@modern-js/render": "npm:@bleedingdev/modern-js-render@3.4.0-ultramodern.20",
246
+ "@modern-js/types": "npm:@bleedingdev/modern-js-types@3.4.0-ultramodern.20",
247
+ "@modern-js/runtime-utils": "npm:@bleedingdev/modern-js-runtime-utils@3.4.0-ultramodern.20",
248
+ "@modern-js/utils": "npm:@bleedingdev/modern-js-utils@3.4.0-ultramodern.20"
249
249
  },
250
250
  "peerDependencies": {
251
251
  "react": "^19.2.7",
@@ -265,8 +265,8 @@
265
265
  "react-dom": "^19.2.7",
266
266
  "ts-node": "^10.9.2",
267
267
  "typescript": "^6.0.3",
268
- "@modern-js/app-tools": "npm:@bleedingdev/modern-js-app-tools@3.4.0-ultramodern.2",
269
- "@scripts/rstest-config": "2.66.0"
268
+ "@scripts/rstest-config": "2.66.0",
269
+ "@modern-js/app-tools": "npm:@bleedingdev/modern-js-app-tools@3.4.0-ultramodern.20"
270
270
  },
271
271
  "sideEffects": false,
272
272
  "publishConfig": {