@bleedingdev/modern-js-runtime 3.2.0-ultramodern.10 → 3.2.0-ultramodern.100

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 (97) hide show
  1. package/dist/cjs/boundary-debugger/index.js +299 -0
  2. package/dist/cjs/cli/ssr/index.js +5 -15
  3. package/dist/cjs/cli/template.server.js +1 -0
  4. package/dist/cjs/core/react/wrapper.js +9 -3
  5. package/dist/cjs/core/server/federatedCss.js +47 -0
  6. package/dist/cjs/core/server/helmet.js +8 -2
  7. package/dist/cjs/core/server/scriptOrder.js +59 -0
  8. package/dist/cjs/core/server/stream/afterTemplate.js +13 -5
  9. package/dist/cjs/core/server/stream/beforeTemplate.js +13 -20
  10. package/dist/cjs/core/server/stream/beforeTemplate.worker.js +98 -0
  11. package/dist/cjs/core/server/stream/createReadableStream.js +7 -2
  12. package/dist/cjs/core/server/stream/createReadableStream.worker.js +4 -2
  13. package/dist/cjs/core/server/stream/shared.js +3 -1
  14. package/dist/cjs/core/server/string/index.js +16 -9
  15. package/dist/cjs/core/server/string/loadable.js +74 -10
  16. package/dist/cjs/exports/head.js +196 -5
  17. package/dist/cjs/exports/loadable.js +34 -4
  18. package/dist/cjs/exports/tanstack-router.js +311 -54
  19. package/dist/cjs/router/cli/code/tanstackTypes.js +116 -51
  20. package/dist/cjs/router/cli/code/templates.js +15 -9
  21. package/dist/cjs/router/runtime/tanstack/hydrationBoundary.js +44 -0
  22. package/dist/cjs/router/runtime/tanstack/outlet.js +54 -0
  23. package/dist/cjs/router/runtime/tanstack/plugin.js +190 -88
  24. package/dist/cjs/router/runtime/tanstack/plugin.node.js +4 -14
  25. package/dist/cjs/router/runtime/tanstack/routeTree.js +64 -12
  26. package/dist/cjs/rsc/server.worker.js +58 -0
  27. package/dist/cjs/ssr/serverRender/renderToString/entry.js +9 -8
  28. package/dist/esm/boundary-debugger/index.mjs +263 -0
  29. package/dist/esm/cli/ssr/index.mjs +5 -15
  30. package/dist/esm/cli/template.server.mjs +1 -0
  31. package/dist/esm/core/react/wrapper.mjs +9 -3
  32. package/dist/esm/core/server/federatedCss.mjs +13 -0
  33. package/dist/esm/core/server/helmet.mjs +5 -2
  34. package/dist/esm/core/server/scriptOrder.mjs +25 -0
  35. package/dist/esm/core/server/stream/afterTemplate.mjs +14 -6
  36. package/dist/esm/core/server/stream/beforeTemplate.mjs +14 -11
  37. package/dist/esm/core/server/stream/beforeTemplate.worker.mjs +64 -0
  38. package/dist/esm/core/server/stream/createReadableStream.mjs +7 -2
  39. package/dist/esm/core/server/stream/createReadableStream.worker.mjs +4 -2
  40. package/dist/esm/core/server/stream/shared.mjs +3 -1
  41. package/dist/esm/core/server/string/index.mjs +17 -9
  42. package/dist/esm/core/server/string/loadable.mjs +70 -9
  43. package/dist/esm/exports/head.mjs +189 -4
  44. package/dist/esm/exports/loadable.mjs +20 -3
  45. package/dist/esm/exports/tanstack-router.mjs +2 -1
  46. package/dist/esm/router/cli/code/tanstackTypes.mjs +116 -51
  47. package/dist/esm/router/cli/code/templates.mjs +15 -9
  48. package/dist/esm/router/runtime/tanstack/hydrationBoundary.mjs +10 -0
  49. package/dist/esm/router/runtime/tanstack/outlet.mjs +17 -0
  50. package/dist/esm/router/runtime/tanstack/plugin.mjs +193 -91
  51. package/dist/esm/router/runtime/tanstack/plugin.node.mjs +5 -15
  52. package/dist/esm/router/runtime/tanstack/routeTree.mjs +65 -13
  53. package/dist/esm/rsc/server.worker.mjs +1 -0
  54. package/dist/esm/ssr/serverRender/renderToString/entry.mjs +9 -6
  55. package/dist/esm-node/boundary-debugger/index.mjs +264 -0
  56. package/dist/esm-node/cli/ssr/index.mjs +5 -15
  57. package/dist/esm-node/cli/template.server.mjs +1 -0
  58. package/dist/esm-node/core/react/wrapper.mjs +9 -3
  59. package/dist/esm-node/core/server/federatedCss.mjs +14 -0
  60. package/dist/esm-node/core/server/helmet.mjs +5 -2
  61. package/dist/esm-node/core/server/scriptOrder.mjs +26 -0
  62. package/dist/esm-node/core/server/stream/afterTemplate.mjs +14 -6
  63. package/dist/esm-node/core/server/stream/beforeTemplate.mjs +14 -11
  64. package/dist/esm-node/core/server/stream/beforeTemplate.worker.mjs +65 -0
  65. package/dist/esm-node/core/server/stream/createReadableStream.mjs +7 -2
  66. package/dist/esm-node/core/server/stream/createReadableStream.worker.mjs +4 -2
  67. package/dist/esm-node/core/server/stream/shared.mjs +3 -1
  68. package/dist/esm-node/core/server/string/index.mjs +17 -9
  69. package/dist/esm-node/core/server/string/loadable.mjs +70 -9
  70. package/dist/esm-node/exports/head.mjs +189 -4
  71. package/dist/esm-node/exports/loadable.mjs +20 -3
  72. package/dist/esm-node/exports/tanstack-router.mjs +2 -1
  73. package/dist/esm-node/router/cli/code/tanstackTypes.mjs +116 -51
  74. package/dist/esm-node/router/cli/code/templates.mjs +15 -9
  75. package/dist/esm-node/router/runtime/tanstack/hydrationBoundary.mjs +11 -0
  76. package/dist/esm-node/router/runtime/tanstack/outlet.mjs +18 -0
  77. package/dist/esm-node/router/runtime/tanstack/plugin.mjs +193 -91
  78. package/dist/esm-node/router/runtime/tanstack/plugin.node.mjs +5 -15
  79. package/dist/esm-node/router/runtime/tanstack/routeTree.mjs +65 -13
  80. package/dist/esm-node/rsc/server.worker.mjs +2 -0
  81. package/dist/esm-node/ssr/serverRender/renderToString/entry.mjs +9 -6
  82. package/dist/types/boundary-debugger/index.d.ts +28 -0
  83. package/dist/types/core/context/runtime.d.ts +4 -0
  84. package/dist/types/core/server/federatedCss.d.ts +5 -0
  85. package/dist/types/core/server/helmet.d.ts +5 -3
  86. package/dist/types/core/server/scriptOrder.d.ts +1 -0
  87. package/dist/types/core/server/stream/beforeTemplate.d.ts +1 -0
  88. package/dist/types/core/server/stream/beforeTemplate.worker.d.ts +10 -0
  89. package/dist/types/core/server/stream/shared.d.ts +8 -0
  90. package/dist/types/core/server/string/loadable.d.ts +11 -0
  91. package/dist/types/exports/head.d.ts +10 -3
  92. package/dist/types/exports/loadable.d.ts +8 -1
  93. package/dist/types/exports/tanstack-router.d.ts +3 -1
  94. package/dist/types/router/runtime/tanstack/hydrationBoundary.d.ts +2 -0
  95. package/dist/types/router/runtime/tanstack/outlet.d.ts +2 -0
  96. package/dist/types/rsc/server.worker.d.ts +1 -0
  97. package/package.json +24 -18
@@ -3,15 +3,18 @@ import { jsx } from "react/jsx-runtime";
3
3
  import { merge } from "@modern-js/runtime-utils/merge";
4
4
  import { normalizePathname } from "@modern-js/runtime-utils/url";
5
5
  import { RouterProvider, createBrowserHistory, createHashHistory, createRouter, useLocation, useMatches, useNavigate, useRouter } from "@tanstack/react-router";
6
- import { RouterClient } from "@tanstack/react-router/ssr/client";
6
+ import { hydrate } from "@tanstack/react-router/ssr/client";
7
+ import { useContext, useMemo } from "react";
7
8
  import { InternalRuntimeContext, getGlobalEnableRsc, getGlobalLayoutApp, getGlobalRoutes } from "../../../core/context/index.mjs";
8
9
  import { onAfterCreateRouter, onAfterHydrateRouter, onBeforeCreateRouter, onBeforeHydrateRouter } from "../hooks.mjs";
9
10
  import { applyRouterRuntimeState } from "../lifecycle.mjs";
10
11
  import { createRouteObjectsFromConfig, urlJoin } from "../utils.mjs";
11
12
  import { createModernBasepathRewrite } from "./basepathRewrite.mjs";
13
+ import { wrapTanstackSsrHydrationBoundary } from "./hydrationBoundary.mjs";
14
+ import { withModernRouteMatchContext } from "./outlet.mjs";
15
+ import { Link } from "./prefetchLink.mjs";
12
16
  import { createRouteTreeFromRouteObjects } from "./routeTree.mjs";
13
17
  import { getTanstackRscSerializationAdapters } from "./rsc/client.mjs";
14
- import * as __rspack_external_react from "react";
15
18
  const BLOCKING_SUBSCRIBE_SYMBOL = Symbol.for('@modern-js/plugin-runtime:tanstack-blocking-subscribe');
16
19
  const BLOCKING_STATE_SYMBOL = Symbol.for('@modern-js/plugin-runtime:tanstack-blocking-state');
17
20
  function normalizeBase(b) {
@@ -39,6 +42,85 @@ function wrapRouterSubscribeWithBlockState(router, getBlockNavState) {
39
42
  };
40
43
  target[BLOCKING_SUBSCRIBE_SYMBOL] = true;
41
44
  }
45
+ const routerHydrationRecords = new WeakMap();
46
+ const routeModulesKey = '_routeModules';
47
+ function pickRouteModuleComponent(routeModule, seen = new Set()) {
48
+ if ('function' == typeof routeModule || routeModule && 'object' == typeof routeModule && '$$typeof' in routeModule) return routeModule;
49
+ if (!routeModule || 'object' != typeof routeModule) return;
50
+ if (seen.has(routeModule)) return;
51
+ seen.add(routeModule);
52
+ const module = routeModule;
53
+ for (const candidate of [
54
+ module.default,
55
+ module.Component
56
+ ]){
57
+ const component = pickRouteModuleComponent(candidate, seen);
58
+ if (component) return component;
59
+ }
60
+ }
61
+ function getCachedRouteModule(routeId) {
62
+ if ("u" < typeof window) return;
63
+ return window[routeModulesKey]?.[routeId];
64
+ }
65
+ async function preloadHydratedRouteComponents(router) {
66
+ const preloadableRouter = router;
67
+ const routesById = preloadableRouter.routesById || {};
68
+ const matches = preloadableRouter.stores.matches.get();
69
+ await Promise.all(matches.map((match)=>{
70
+ if (!match.routeId) return;
71
+ const route = routesById[match.routeId];
72
+ const component = route?.options?.component;
73
+ const preload = component?.load || component?.preload;
74
+ if ('function' != typeof preload) return;
75
+ return Promise.resolve(preload.call(component)).then((routeModule)=>{
76
+ const modernRouteId = route?.options?.staticData?.modernRouteId;
77
+ const resolvedComponent = pickRouteModuleComponent(modernRouteId && getCachedRouteModule(modernRouteId) || routeModule);
78
+ if (resolvedComponent && modernRouteId) route.options.component = withModernRouteMatchContext(resolvedComponent, modernRouteId);
79
+ });
80
+ }));
81
+ }
82
+ function getTanstackSsrHydrationRecord(router) {
83
+ let hydrationRecord = routerHydrationRecords.get(router);
84
+ if (!hydrationRecord) {
85
+ hydrationRecord = {
86
+ promise: Promise.resolve(),
87
+ status: 'pending'
88
+ };
89
+ routerHydrationRecords.set(router, hydrationRecord);
90
+ try {
91
+ hydrationRecord.promise = hydrate(router).then(async (value)=>{
92
+ await preloadHydratedRouteComponents(router);
93
+ return value;
94
+ }).then((value)=>{
95
+ hydrationRecord.status = 'fulfilled';
96
+ return value;
97
+ }, (error)=>{
98
+ hydrationRecord.status = 'rejected';
99
+ hydrationRecord.error = error;
100
+ throw error;
101
+ });
102
+ } catch (error) {
103
+ hydrationRecord.status = 'rejected';
104
+ hydrationRecord.error = error;
105
+ hydrationRecord.promise = Promise.reject(error);
106
+ hydrationRecord.promise.catch(()=>{});
107
+ }
108
+ }
109
+ return hydrationRecord;
110
+ }
111
+ function getTanstackSsrHydrationPromise(router) {
112
+ return getTanstackSsrHydrationRecord(router).promise;
113
+ }
114
+ function hasTanstackSsrHydrationRecord(router) {
115
+ return routerHydrationRecords.has(router);
116
+ }
117
+ function ModernRouterClient({ router }) {
118
+ const hydrationRecord = getTanstackSsrHydrationRecord(router);
119
+ if ('rejected' === hydrationRecord.status) throw hydrationRecord.error;
120
+ return /*#__PURE__*/ jsx(RouterProvider, {
121
+ router: router
122
+ });
123
+ }
42
124
  function stripSyntheticNotFoundRoute(routes) {
43
125
  return routes.filter((route)=>!('*' === route.path && !route.id && !route.loader)).map((route)=>{
44
126
  if (!route.children?.length) return route;
@@ -57,9 +139,94 @@ const tanstackRouterPlugin = (userConfig = {})=>({
57
139
  onBeforeHydrateRouter: onBeforeHydrateRouter
58
140
  },
59
141
  setup: (api)=>{
60
- api.onBeforeRender((context)=>{
142
+ const hooks = api.getHooks();
143
+ let cachedRouteObjects;
144
+ let cachedRouteTree = null;
145
+ let cachedRouter = null;
146
+ let cachedRouterBasepath = null;
147
+ const getMergedConfig = ()=>{
61
148
  const pluginConfig = api.getRuntimeConfig();
62
- const mergedConfig = merge(pluginConfig.router || {}, userConfig);
149
+ return merge(pluginConfig.router || {}, userConfig);
150
+ };
151
+ const getRouteObjects = ()=>{
152
+ if (void 0 !== cachedRouteObjects) return cachedRouteObjects;
153
+ const mergedConfig = getMergedConfig();
154
+ const { routesConfig, createRoutes } = mergedConfig;
155
+ const finalRouteConfig = {
156
+ routes: getGlobalRoutes(),
157
+ globalApp: getGlobalLayoutApp(),
158
+ ...routesConfig
159
+ };
160
+ const routeObjects = createRoutes ? createRoutes() : createRouteObjectsFromConfig({
161
+ routesConfig: finalRouteConfig
162
+ }) || [];
163
+ const normalizedRouteObjects = createRoutes ? routeObjects : stripSyntheticNotFoundRoute(routeObjects);
164
+ cachedRouteObjects = hooks.modifyRoutes.call(normalizedRouteObjects);
165
+ return cachedRouteObjects;
166
+ };
167
+ const getRouteTree = ()=>{
168
+ if (cachedRouteTree) return cachedRouteTree;
169
+ const routeObjects = getRouteObjects();
170
+ if (!routeObjects.length) return null;
171
+ cachedRouteTree = createRouteTreeFromRouteObjects(routeObjects);
172
+ return cachedRouteTree;
173
+ };
174
+ const selectBasePath = (pathname)=>{
175
+ const { serverBase = [] } = getMergedConfig();
176
+ const match = serverBase.find((baseUrl)=>isSegmentPrefix(pathname, baseUrl));
177
+ return match || '/';
178
+ };
179
+ const getClientBasename = (runtimeContext)=>{
180
+ const { basename = '' } = getMergedConfig();
181
+ const baseUrl = selectBasePath(location.pathname).replace(/^\/*/, '/');
182
+ return '/' === baseUrl ? urlJoin(baseUrl, runtimeContext._internalRouterBaseName || basename || '') : baseUrl;
183
+ };
184
+ const getRouter = (runtimeContext, _basename)=>{
185
+ const routeTree = getRouteTree();
186
+ if (!routeTree) return null;
187
+ const lifecycleContext = {
188
+ framework: 'tanstack',
189
+ phase: 'client-create',
190
+ routes: getRouteObjects(),
191
+ runtimeContext,
192
+ basename: _basename
193
+ };
194
+ hooks.onBeforeCreateRouter.call(lifecycleContext);
195
+ if (cachedRouter && cachedRouterBasepath === _basename) {
196
+ wrapRouterSubscribeWithBlockState(cachedRouter, runtimeContext.unstable_getBlockNavState);
197
+ hooks.onAfterCreateRouter.call({
198
+ ...lifecycleContext,
199
+ router: cachedRouter,
200
+ runtimeContext
201
+ });
202
+ return cachedRouter;
203
+ }
204
+ const mergedConfig = getMergedConfig();
205
+ const { supportHtml5History = true } = mergedConfig;
206
+ const history = supportHtml5History ? createBrowserHistory() : createHashHistory();
207
+ const rewrite = createModernBasepathRewrite(_basename);
208
+ const serializationAdapters = getGlobalEnableRsc() ? getTanstackRscSerializationAdapters() : void 0;
209
+ cachedRouter = createRouter({
210
+ routeTree,
211
+ basepath: '/',
212
+ rewrite,
213
+ history,
214
+ context: {},
215
+ ...serializationAdapters ? {
216
+ serializationAdapters
217
+ } : {}
218
+ });
219
+ cachedRouterBasepath = _basename;
220
+ wrapRouterSubscribeWithBlockState(cachedRouter, runtimeContext.unstable_getBlockNavState);
221
+ hooks.onAfterCreateRouter.call({
222
+ ...lifecycleContext,
223
+ router: cachedRouter,
224
+ runtimeContext
225
+ });
226
+ return cachedRouter;
227
+ };
228
+ api.onBeforeRender(async (context)=>{
229
+ const mergedConfig = getMergedConfig();
63
230
  if ("u" > typeof window && window._SSR_DATA && mergedConfig.unstable_reloadOnURLMismatch) {
64
231
  const { ssrContext } = context;
65
232
  const currentPathname = normalizePathname(window.location.pathname);
@@ -71,96 +238,32 @@ const tanstackRouterPlugin = (userConfig = {})=>({
71
238
  }
72
239
  }
73
240
  context.router = {
241
+ Link: Link,
74
242
  useMatches: useMatches,
75
243
  useLocation: useLocation,
76
244
  useNavigate: useNavigate,
77
245
  useRouter: useRouter
78
246
  };
247
+ const hasSSRBootstrap = "u" > typeof window && Boolean(window.$_TSR);
248
+ if (hasSSRBootstrap && getRouteObjects().length) {
249
+ const runtimeContext = context;
250
+ const router = getRouter(runtimeContext, getClientBasename(runtimeContext));
251
+ if (router) await getTanstackSsrHydrationPromise(router);
252
+ }
79
253
  });
80
254
  api.wrapRoot((App)=>{
81
- const mergedConfig = merge(api.getRuntimeConfig().router || {}, userConfig);
82
- const { serverBase = [], supportHtml5History = true, basename = '', routesConfig, createRoutes } = mergedConfig;
83
- const finalRouteConfig = {
84
- routes: getGlobalRoutes(),
85
- globalApp: getGlobalLayoutApp(),
86
- ...routesConfig
87
- };
88
- if (!finalRouteConfig.routes && !createRoutes) return App;
89
- const hooks = api.getHooks();
90
- let cachedRouteObjects;
91
- const getRouteObjects = ()=>{
92
- if (void 0 !== cachedRouteObjects) return cachedRouteObjects;
93
- const routeObjects = createRoutes ? createRoutes() : createRouteObjectsFromConfig({
94
- routesConfig: finalRouteConfig
95
- }) || [];
96
- const normalizedRouteObjects = createRoutes ? routeObjects : stripSyntheticNotFoundRoute(routeObjects);
97
- cachedRouteObjects = hooks.modifyRoutes.call(normalizedRouteObjects);
98
- return cachedRouteObjects;
99
- };
100
- const selectBasePath = (pathname)=>{
101
- const match = serverBase.find((baseUrl)=>isSegmentPrefix(pathname, baseUrl));
102
- return match || '/';
103
- };
104
- let cachedRouteTree = null;
105
- let cachedRouter = null;
106
- let cachedRouterBasepath = null;
255
+ if (!getRouteObjects().length) return App;
107
256
  const RouterWrapper = ()=>{
108
- const runtimeContext = (0, __rspack_external_react.useContext)(InternalRuntimeContext);
109
- const baseUrl = selectBasePath(location.pathname).replace(/^\/*/, '/');
110
- const _basename = '/' === baseUrl ? urlJoin(baseUrl, runtimeContext._internalRouterBaseName || basename || '') : baseUrl;
111
- const routeTree = (0, __rspack_external_react.useMemo)(()=>{
112
- if (cachedRouteTree) return cachedRouteTree;
113
- const routeObjects = getRouteObjects();
114
- if (!routeObjects.length) return null;
115
- cachedRouteTree = createRouteTreeFromRouteObjects(routeObjects);
116
- return cachedRouteTree;
117
- }, []);
257
+ const runtimeContext = useContext(InternalRuntimeContext);
258
+ const _basename = getClientBasename(runtimeContext);
259
+ const routeTree = useMemo(()=>getRouteTree(), []);
118
260
  if (!routeTree) return App ? /*#__PURE__*/ jsx(App, {}) : null;
119
- const router = (0, __rspack_external_react.useMemo)(()=>{
120
- const lifecycleContext = {
121
- framework: 'tanstack',
122
- phase: 'client-create',
123
- routes: getRouteObjects(),
124
- runtimeContext,
125
- basename: _basename
126
- };
127
- hooks.onBeforeCreateRouter.call(lifecycleContext);
128
- if (cachedRouter && cachedRouterBasepath === _basename) {
129
- wrapRouterSubscribeWithBlockState(cachedRouter, runtimeContext.unstable_getBlockNavState);
130
- hooks.onAfterCreateRouter.call({
131
- ...lifecycleContext,
132
- router: cachedRouter,
133
- runtimeContext
134
- });
135
- return cachedRouter;
136
- }
137
- const history = supportHtml5History ? createBrowserHistory() : createHashHistory();
138
- const rewrite = createModernBasepathRewrite(_basename);
139
- const serializationAdapters = getGlobalEnableRsc() ? getTanstackRscSerializationAdapters() : void 0;
140
- cachedRouter = createRouter({
141
- routeTree,
142
- basepath: '/',
143
- rewrite,
144
- history,
145
- context: {},
146
- ...serializationAdapters ? {
147
- serializationAdapters
148
- } : {}
149
- });
150
- cachedRouterBasepath = _basename;
151
- wrapRouterSubscribeWithBlockState(cachedRouter, runtimeContext.unstable_getBlockNavState);
152
- hooks.onAfterCreateRouter.call({
153
- ...lifecycleContext,
154
- router: cachedRouter,
155
- runtimeContext
156
- });
157
- return cachedRouter;
158
- }, [
261
+ const router = useMemo(()=>getRouter(runtimeContext, _basename), [
159
262
  _basename,
160
263
  routeTree,
161
- supportHtml5History,
162
264
  runtimeContext
163
265
  ]);
266
+ if (!router) return App ? /*#__PURE__*/ jsx(App, {}) : null;
164
267
  const runtimeState = applyRouterRuntimeState(runtimeContext, {
165
268
  framework: 'tanstack',
166
269
  basename: _basename,
@@ -174,30 +277,29 @@ const tanstackRouterPlugin = (userConfig = {})=>({
174
277
  basename: _basename,
175
278
  router
176
279
  };
177
- const hasSSRBootstrap = "u" > typeof window && Boolean(window.$_TSR);
178
- if (hasSSRBootstrap) hooks.onBeforeHydrateRouter.call({
280
+ const hasSSRBootstrap = "u" > typeof window && (Boolean(window.$_TSR) || hasTanstackSsrHydrationRecord(router));
281
+ const needsRouterClient = hasSSRBootstrap;
282
+ if (needsRouterClient) hooks.onBeforeHydrateRouter.call({
179
283
  ...lifecycleContext,
180
284
  phase: 'hydrate',
181
285
  router,
182
286
  runtimeContext: runtimeState
183
287
  });
184
- const RouterContent = hasSSRBootstrap ? /*#__PURE__*/ jsx(__rspack_external_react.Suspense, {
185
- fallback: null,
186
- children: /*#__PURE__*/ jsx(RouterClient, {
187
- router: router
188
- })
288
+ const RouterContent = needsRouterClient ? /*#__PURE__*/ jsx(ModernRouterClient, {
289
+ router: router
189
290
  }) : /*#__PURE__*/ jsx(RouterProvider, {
190
291
  router: router
191
292
  });
192
- if (hasSSRBootstrap) hooks.onAfterHydrateRouter.call({
293
+ const HydratableRouterContent = wrapTanstackSsrHydrationBoundary(RouterContent, hasSSRBootstrap);
294
+ if (needsRouterClient) hooks.onAfterHydrateRouter.call({
193
295
  ...lifecycleContext,
194
296
  phase: 'hydrate',
195
297
  router,
196
298
  runtimeContext: runtimeState
197
299
  });
198
300
  return App ? /*#__PURE__*/ jsx(App, {
199
- children: RouterContent
200
- }) : RouterContent;
301
+ children: HydratableRouterContent
302
+ }) : HydratableRouterContent;
201
303
  };
202
304
  return RouterWrapper;
203
305
  });
@@ -6,11 +6,12 @@ import { time } from "@modern-js/runtime-utils/time";
6
6
  import { LOADER_REPORTER_NAME } from "@modern-js/utils/universal/constants";
7
7
  import { RouterProvider, createMemoryHistory, createRouter } from "@tanstack/react-router";
8
8
  import { attachRouterServerSsrUtils } from "@tanstack/react-router/ssr/server";
9
- import { Suspense, useContext } from "react";
9
+ import { useContext } from "react";
10
10
  import { InternalRuntimeContext, getGlobalEnableRsc, getGlobalLayoutApp, getGlobalRoutes } from "../../../core/context/index.mjs";
11
11
  import { applyRouterServerPrepareResult, createRouterServerSnapshot } from "../lifecycle.mjs";
12
12
  import { createRouteObjectsFromConfig, urlJoin } from "../utils.mjs";
13
13
  import { createModernBasepathRewrite } from "./basepathRewrite.mjs";
14
+ import { wrapTanstackSsrHydrationBoundary } from "./hydrationBoundary.mjs";
14
15
  import { createRouteTreeFromRouteObjects, getModernRouteIdsFromMatches } from "./routeTree.mjs";
15
16
  function isPreloadableRouteComponent(component) {
16
17
  if (!component || 'function' != typeof component) return false;
@@ -38,13 +39,6 @@ async function preloadMatchedRouteComponents(tanstackRouter) {
38
39
  ]);
39
40
  }));
40
41
  }
41
- async function waitForRouterSerialization(tanstackRouter) {
42
- const serverSsr = tanstackRouter.serverSsr;
43
- if (!serverSsr || 'function' != typeof serverSsr.onSerializationFinished || serverSsr.isSerializationFinished?.()) return;
44
- await new Promise((resolve)=>{
45
- serverSsr.onSerializationFinished?.(resolve);
46
- });
47
- }
48
42
  function htmlEscapeAttr(value) {
49
43
  return value.replace(/&/g, '&amp;').replace(/"/g, '&quot;');
50
44
  }
@@ -190,7 +184,6 @@ const tanstackRouterPlugin = (userConfig = {})=>({
190
184
  await preloadMatchedRouteComponents(serverRouter);
191
185
  context.ssrContext?.response.status(tanstackRouter.state.statusCode);
192
186
  await serverRouter.serverSsr?.dehydrate?.();
193
- await waitForRouterSerialization(serverRouter);
194
187
  const ssrScriptTags = serverRouter.serverSsr?.takeBufferedScripts?.();
195
188
  const hydrationScripts = routerManagedTagsToHtml(ssrScriptTags);
196
189
  const matchedRouteIds = getModernRouteIdsFromMatches(serverRouter);
@@ -228,12 +221,9 @@ const tanstackRouterPlugin = (userConfig = {})=>({
228
221
  if (!router) return App ? /*#__PURE__*/ jsx(App, {
229
222
  ...props
230
223
  }) : null;
231
- const routerWrapper = /*#__PURE__*/ jsx(Suspense, {
232
- fallback: null,
233
- children: /*#__PURE__*/ jsx(RouterProvider, {
234
- router: router
235
- })
236
- });
224
+ const routerWrapper = wrapTanstackSsrHydrationBoundary(/*#__PURE__*/ jsx(RouterProvider, {
225
+ router: router
226
+ }), true);
237
227
  return App ? /*#__PURE__*/ jsx(App, {
238
228
  children: routerWrapper
239
229
  }) : routerWrapper;
@@ -1,12 +1,18 @@
1
1
  import "node:module";
2
- import { createRootRoute, createRoute, notFound, redirect } from "@tanstack/react-router";
2
+ import { createRootRoute, createRoute, notFound, redirect, rootRouteId } from "@tanstack/react-router";
3
+ import { createElement } from "react";
3
4
  import { DefaultNotFound } from "../DefaultNotFound.mjs";
5
+ import { withModernRouteMatchContext } from "./outlet.mjs";
4
6
  function createTanstackRoute(options) {
5
7
  return createRoute(options);
6
8
  }
7
9
  function createTanstackRootRoute(options) {
8
10
  return createRootRoute(options);
9
11
  }
12
+ function wrapRouteComponentWithModernContext(route, component, routeId) {
13
+ const routeMatchId = routeId || route.id;
14
+ if (component && routeMatchId) route.options.component = withModernRouteMatchContext(component, routeMatchId);
15
+ }
10
16
  function toTanstackPath(pathname) {
11
17
  return pathname.split('/').map((segment)=>{
12
18
  if (!segment) return segment;
@@ -44,6 +50,40 @@ function isModernDeferredData(value) {
44
50
  function normalizeModernLoaderResult(result) {
45
51
  return isModernDeferredData(result) ? result.data : result;
46
52
  }
53
+ function pickRouteModuleComponent(routeModule, seen = new Set()) {
54
+ if ('function' == typeof routeModule || routeModule && 'object' == typeof routeModule && '$$typeof' in routeModule) return routeModule;
55
+ if (!routeModule || 'object' != typeof routeModule) return;
56
+ if (seen.has(routeModule)) return;
57
+ seen.add(routeModule);
58
+ const module = routeModule;
59
+ for (const candidate of [
60
+ module.default,
61
+ module.Component
62
+ ]){
63
+ const component = pickRouteModuleComponent(candidate, seen);
64
+ if (component) return component;
65
+ }
66
+ }
67
+ function createServerLazyImportComponent(lazyImport, fallbackComponent) {
68
+ if ("u" > typeof document) return fallbackComponent;
69
+ let resolvedComponent;
70
+ let pendingLoad;
71
+ const load = async ()=>{
72
+ if (resolvedComponent) return resolvedComponent;
73
+ const routeModule = await lazyImport();
74
+ const component = pickRouteModuleComponent(routeModule);
75
+ if (component) resolvedComponent = component;
76
+ return resolvedComponent;
77
+ };
78
+ const Component = (props)=>{
79
+ if (resolvedComponent) return createElement(resolvedComponent, props);
80
+ pendingLoad ||= load();
81
+ throw pendingLoad;
82
+ };
83
+ Component.load = load;
84
+ Component.preload = load;
85
+ return Component;
86
+ }
47
87
  function throwTanstackRedirect(location) {
48
88
  const target = location || '/';
49
89
  try {
@@ -112,7 +152,7 @@ function wrapModernLoader(modernRoute, modernLoader, revalidationState) {
112
152
  const signal = ctx?.abortController?.signal || ctx?.signal || new AbortController().signal;
113
153
  const baseRequest = ctx?.context?.request instanceof Request ? ctx.context.request : void 0;
114
154
  const href = 'string' == typeof ctx?.location ? ctx.location : ctx?.location?.publicHref || ctx?.location?.href || ctx?.location?.url?.href || '';
115
- const request = baseRequest ? new Request(baseRequest, {
155
+ const request = void 0 !== baseRequest ? new Request(baseRequest, {
116
156
  signal
117
157
  }) : createModernRequest(href, signal);
118
158
  const params = mapParamsForModernLoader({
@@ -175,7 +215,7 @@ function wrapRouteObjectLoader(route, revalidationState) {
175
215
  const signal = ctx?.abortController?.signal || ctx?.signal || new AbortController().signal;
176
216
  const baseRequest = ctx?.context?.request instanceof Request ? ctx.context.request : void 0;
177
217
  const href = 'string' == typeof ctx?.location ? ctx.location : ctx?.location?.publicHref || ctx?.location?.href || ctx?.location?.url?.href || '';
178
- const request = baseRequest ? new Request(baseRequest, {
218
+ const request = void 0 !== baseRequest ? new Request(baseRequest, {
179
219
  signal
180
220
  }) : createModernRequest(href, signal);
181
221
  const params = mapParamsForRouteObjectLoader({
@@ -210,10 +250,18 @@ function wrapRouteObjectLoader(route, revalidationState) {
210
250
  }
211
251
  function toRouteComponent(routeObject) {
212
252
  const route = routeObject;
253
+ const lazyImport = 'function' == typeof route.lazyImport ? route.lazyImport : void 0;
254
+ const fallbackComponent = route.Component ? route.Component : route.element ? ()=>route.element : void 0;
255
+ if (lazyImport && fallbackComponent) return createServerLazyImportComponent(lazyImport, fallbackComponent);
213
256
  if (route.Component) return route.Component;
214
257
  const element = route.element;
215
258
  if (element) return ()=>element;
216
259
  }
260
+ function toModernRouteComponent(route) {
261
+ const component = route.component || void 0;
262
+ if ('function' == typeof route.lazyImport && component) return createServerLazyImportComponent(route.lazyImport, component);
263
+ return component;
264
+ }
217
265
  function toErrorComponent(routeObject) {
218
266
  const route = routeObject;
219
267
  if (route.ErrorBoundary) return route.ErrorBoundary;
@@ -251,12 +299,12 @@ function createRouteFromRouteObject(opts) {
251
299
  const shouldRevalidate = modernRouteObject.shouldRevalidate;
252
300
  const shouldReload = createModernShouldReload(shouldRevalidate, revalidationState);
253
301
  const stableFallbackId = routeObject.id || modernRouteObject.file || routeObject.path || 'pathless';
302
+ const component = toRouteComponent(routeObject);
254
303
  const base = {
255
304
  getParentRoute: ()=>parent,
256
- component: toRouteComponent(routeObject),
305
+ component,
257
306
  pendingComponent: toPendingComponent(routeObject),
258
307
  errorComponent: toErrorComponent(routeObject),
259
- wrapInSuspense: true,
260
308
  staticData: createRouteStaticData({
261
309
  modernRouteId: routeObject.id,
262
310
  modernRouteAction: modernRouteObject.action,
@@ -275,6 +323,7 @@ function createRouteFromRouteObject(opts) {
275
323
  if (isRouteObjectPathlessLayout(routeObject)) base.id = stableFallbackId;
276
324
  else base.path = routeObject.index ? '/' : toTanstackPath(routeObject.path || '');
277
325
  const route = createTanstackRoute(base);
326
+ wrapRouteComponentWithModernContext(route, component, routeObject.id);
278
327
  const children = routeObject.children;
279
328
  if (children && children.length > 0) {
280
329
  const childRoutes = children.map((child)=>createRouteFromRouteObject({
@@ -293,7 +342,7 @@ function createRouteFromModernRoute(opts) {
293
342
  const stableFallbackId = modernId || route._component || route.filename || route.data || ('function' == typeof route.loader ? route.id : void 0);
294
343
  const pendingComponent = route.loading || route.pendingComponent;
295
344
  const errorComponent = route.error || route.errorComponent;
296
- const component = route.component;
345
+ const component = toModernRouteComponent(route);
297
346
  const modernLoader = route.loader;
298
347
  const modernAction = route.action;
299
348
  const modernShouldRevalidate = route.shouldRevalidate;
@@ -305,7 +354,6 @@ function createRouteFromModernRoute(opts) {
305
354
  component: component || void 0,
306
355
  pendingComponent: pendingComponent || void 0,
307
356
  errorComponent: errorComponent || void 0,
308
- wrapInSuspense: true,
309
357
  staticData: createRouteStaticData({
310
358
  modernRouteId: modernId,
311
359
  modernRouteAction: modernAction,
@@ -327,6 +375,7 @@ function createRouteFromModernRoute(opts) {
327
375
  base.path = isIndexRoute ? '/' : toTanstackPath(rawPath || '');
328
376
  }
329
377
  const tanstackRoute = createTanstackRoute(base);
378
+ wrapRouteComponentWithModernContext(tanstackRoute, component, modernId);
330
379
  const children = route.children;
331
380
  if (children && children.length > 0) {
332
381
  const childRoutes = children.map((child)=>createRouteFromModernRoute({
@@ -339,7 +388,7 @@ function createRouteFromModernRoute(opts) {
339
388
  }
340
389
  function createRouteTreeFromModernRoutes(routes) {
341
390
  const rootModern = routes.find((r)=>r && 'nested' === r.type && r.isRoot);
342
- const rootComponent = rootModern?.component;
391
+ const rootComponent = rootModern ? toModernRouteComponent(rootModern) : void 0;
343
392
  const pendingComponent = rootModern?.loading;
344
393
  const errorComponent = rootModern?.error;
345
394
  const rootLoader = rootModern?.loader;
@@ -352,7 +401,6 @@ function createRouteTreeFromModernRoutes(routes) {
352
401
  component: rootComponent || void 0,
353
402
  pendingComponent: pendingComponent || void 0,
354
403
  errorComponent: errorComponent || void 0,
355
- wrapInSuspense: true,
356
404
  notFoundComponent: DefaultNotFound,
357
405
  staticData: createRouteStaticData({
358
406
  modernRouteId: rootModernId,
@@ -370,6 +418,7 @@ function createRouteTreeFromModernRoutes(routes) {
370
418
  if (rootShouldReload) rootRouteOptions.shouldReload = rootShouldReload;
371
419
  if (rootModern?.inValidSSRRoute) rootRouteOptions.ssr = false;
372
420
  const rootRoute = createTanstackRootRoute(rootRouteOptions);
421
+ if (rootComponent) rootRoute.options.component = withModernRouteMatchContext(rootComponent, rootRouteId);
373
422
  const topLevel = rootModern ? rootModern.children || [] : routes;
374
423
  const childRoutes = topLevel.map((child)=>createRouteFromModernRoute({
375
424
  parent: rootRoute,
@@ -386,11 +435,11 @@ function createRouteTreeFromRouteObjects(routes) {
386
435
  const rootRevalidationState = {};
387
436
  const rootShouldRevalidate = rootLikeRoute?.shouldRevalidate;
388
437
  const rootShouldReload = createModernShouldReload(rootShouldRevalidate, rootRevalidationState);
438
+ const rootComponent = rootLikeRoute ? toRouteComponent(rootLikeRoute) : void 0;
389
439
  const rootRouteOptions = {
390
- component: rootLikeRoute ? toRouteComponent(rootLikeRoute) : void 0,
440
+ component: rootComponent,
391
441
  pendingComponent: rootLikeRoute ? toPendingComponent(rootLikeRoute) : void 0,
392
442
  errorComponent: rootLikeRoute ? toErrorComponent(rootLikeRoute) : void 0,
393
- wrapInSuspense: true,
394
443
  notFoundComponent: DefaultNotFound,
395
444
  staticData: createRouteStaticData({
396
445
  modernRouteId: rootLikeRoute?.id,
@@ -408,6 +457,7 @@ function createRouteTreeFromRouteObjects(routes) {
408
457
  if (rootShouldReload) rootRouteOptions.shouldReload = rootShouldReload;
409
458
  if (rootLikeRoute?.inValidSSRRoute) rootRouteOptions.ssr = false;
410
459
  const rootRoute = createTanstackRootRoute(rootRouteOptions);
460
+ if (rootComponent) rootRoute.options.component = withModernRouteMatchContext(rootComponent, rootRouteId);
411
461
  const topLevel = rootLikeRoute ? [
412
462
  ...rootLikeRoute.children || [],
413
463
  ...routes.filter((route)=>route !== rootLikeRoute)
@@ -421,9 +471,11 @@ function createRouteTreeFromRouteObjects(routes) {
421
471
  }
422
472
  function getModernRouteIdsFromMatches(router) {
423
473
  const matches = router.state.matches || [];
474
+ const routesById = router.routesById;
424
475
  const ids = matches.map((match)=>{
425
- const route = match.route;
426
- return route?.options?.staticData?.modernRouteId;
476
+ const normalizedMatch = match;
477
+ const routeId = 'string' == typeof normalizedMatch.routeId ? normalizedMatch.routeId : void 0;
478
+ return normalizedMatch.route?.options?.staticData?.modernRouteId ?? (routeId ? routesById?.[routeId]?.options?.staticData?.modernRouteId : void 0);
427
479
  }).filter((id)=>'string' == typeof id);
428
480
  return Array.from(new Set(ids));
429
481
  }
@@ -0,0 +1,2 @@
1
+ import "node:module";
2
+ export * from "@modern-js/render/rsc-worker";
@@ -2,10 +2,10 @@ import "node:module";
2
2
  import { sanitizeSSRPayload, serializeJson } from "@modern-js/runtime-utils/node";
3
3
  import { time } from "@modern-js/runtime-utils/time";
4
4
  import react from "react";
5
- import react_helmet from "react-helmet";
5
+ import { HelmetProvider } from "react-helmet-async";
6
+ import { getHelmetData, helmetReplace } from "../../../core/server/helmet.mjs";
6
7
  import { serializeErrors } from "../../../router/runtime/utils.mjs";
7
8
  import prefetch from "../../prefetch";
8
- import helmet from "../helmet";
9
9
  import { SSRErrors, SSRTimings } from "../tracker";
10
10
  import { RenderLevel } from "../types.mjs";
11
11
  import { ROUTER_DATA_JSON_ID, SSR_DATA_JSON_ID, attributesToString } from "../utils";
@@ -61,8 +61,8 @@ class Entry {
61
61
  createReplaceSSRDataScript(ssrDataScripts),
62
62
  ...this.htmlModifiers
63
63
  ]);
64
- const helmetData = react_helmet.renderStatic();
65
- return helmetData ? helmet(html, helmetData) : html;
64
+ const helmetData = getHelmetData(context);
65
+ return helmetData ? helmetReplace(html, helmetData) : html;
66
66
  }
67
67
  async prefetch(context) {
68
68
  let prefetchData;
@@ -83,11 +83,14 @@ class Entry {
83
83
  const end = time();
84
84
  const { ssrContext } = context;
85
85
  try {
86
- const App = react.createElement(this.App, {
86
+ const helmetContext = context._helmetContext ??= {};
87
+ const App = react.createElement(HelmetProvider, {
88
+ context: helmetContext
89
+ }, react.createElement(this.App, {
87
90
  context: Object.assign(context, {
88
91
  ssr: true
89
92
  })
90
- });
93
+ }));
91
94
  html = await createRender(App).addCollector(createStyledCollector(this.result)).addCollector(createLoadableCollector({
92
95
  stats: ssrContext.loadableStats,
93
96
  result: this.result,