@bleedingdev/modern-js-plugin-tanstack 3.2.0-ultramodern.12 → 3.2.0-ultramodern.120

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 (87) hide show
  1. package/dist/cjs/cli/index.js +47 -9
  2. package/dist/cjs/cli/routeSplitting.js +87 -0
  3. package/dist/cjs/cli/tanstackTypes.js +230 -63
  4. package/dist/cjs/cli.js +12 -8
  5. package/dist/cjs/runtime/DefaultNotFound.js +9 -5
  6. package/dist/cjs/runtime/basepathRewrite.js +12 -8
  7. package/dist/cjs/runtime/dataMutation.js +9 -5
  8. package/dist/cjs/runtime/hooks.js +9 -5
  9. package/dist/cjs/runtime/hydrationBoundary.js +48 -0
  10. package/dist/cjs/runtime/index.js +330 -74
  11. package/dist/cjs/runtime/lifecycle.js +15 -11
  12. package/dist/cjs/runtime/outlet.js +58 -0
  13. package/dist/cjs/runtime/plugin.js +203 -98
  14. package/dist/cjs/runtime/plugin.node.js +38 -16
  15. package/dist/cjs/runtime/plugin.worker.js +53 -0
  16. package/dist/cjs/runtime/prefetchLink.js +10 -6
  17. package/dist/cjs/runtime/routeTree.js +81 -17
  18. package/dist/cjs/runtime/rsc/ClientSlot.js +9 -5
  19. package/dist/cjs/runtime/rsc/CompositeComponent.js +9 -5
  20. package/dist/cjs/runtime/rsc/ReplayableStream.js +14 -9
  21. package/dist/cjs/runtime/rsc/RscNodeRenderer.js +9 -5
  22. package/dist/cjs/runtime/rsc/SlotContext.js +9 -5
  23. package/dist/cjs/runtime/rsc/client.js +9 -5
  24. package/dist/cjs/runtime/rsc/createRscProxy.js +9 -5
  25. package/dist/cjs/runtime/rsc/index.js +9 -5
  26. package/dist/cjs/runtime/rsc/payloadRouter.js +9 -5
  27. package/dist/cjs/runtime/rsc/server.js +9 -5
  28. package/dist/cjs/runtime/rsc/slotUsageSanitizer.js +9 -5
  29. package/dist/cjs/runtime/rsc/symbols.js +20 -15
  30. package/dist/cjs/runtime/types.js +31 -1
  31. package/dist/cjs/runtime/utils.js +9 -5
  32. package/dist/cjs/runtime.js +9 -5
  33. package/dist/esm/cli/index.mjs +28 -6
  34. package/dist/esm/cli/routeSplitting.mjs +43 -0
  35. package/dist/esm/cli/tanstackTypes.mjs +219 -59
  36. package/dist/esm/runtime/hydrationBoundary.mjs +10 -0
  37. package/dist/esm/runtime/index.mjs +3 -2
  38. package/dist/esm/runtime/outlet.mjs +17 -0
  39. package/dist/esm/runtime/plugin.mjs +197 -96
  40. package/dist/esm/runtime/plugin.node.mjs +30 -12
  41. package/dist/esm/runtime/plugin.worker.mjs +1 -0
  42. package/dist/esm/runtime/prefetchLink.mjs +1 -1
  43. package/dist/esm/runtime/routeTree.mjs +73 -13
  44. package/dist/esm/runtime/types.mjs +7 -0
  45. package/dist/esm-node/cli/index.mjs +28 -6
  46. package/dist/esm-node/cli/routeSplitting.mjs +44 -0
  47. package/dist/esm-node/cli/tanstackTypes.mjs +219 -59
  48. package/dist/esm-node/runtime/hydrationBoundary.mjs +11 -0
  49. package/dist/esm-node/runtime/index.mjs +3 -2
  50. package/dist/esm-node/runtime/outlet.mjs +18 -0
  51. package/dist/esm-node/runtime/plugin.mjs +197 -96
  52. package/dist/esm-node/runtime/plugin.node.mjs +30 -12
  53. package/dist/esm-node/runtime/plugin.worker.mjs +2 -0
  54. package/dist/esm-node/runtime/prefetchLink.mjs +1 -1
  55. package/dist/esm-node/runtime/routeTree.mjs +73 -13
  56. package/dist/esm-node/runtime/types.mjs +7 -0
  57. package/dist/types/cli/index.d.ts +7 -1
  58. package/dist/types/cli/routeSplitting.d.ts +29 -0
  59. package/dist/types/cli/tanstackTypes.d.ts +9 -0
  60. package/dist/types/runtime/hooks.d.ts +9 -24
  61. package/dist/types/runtime/hydrationBoundary.d.ts +2 -0
  62. package/dist/types/runtime/index.d.ts +5 -2
  63. package/dist/types/runtime/outlet.d.ts +2 -0
  64. package/dist/types/runtime/plugin.d.ts +1 -1
  65. package/dist/types/runtime/plugin.node.d.ts +1 -1
  66. package/dist/types/runtime/plugin.worker.d.ts +1 -0
  67. package/dist/types/runtime/types.d.ts +7 -0
  68. package/package.json +20 -20
  69. package/src/cli/index.ts +59 -2
  70. package/src/cli/routeSplitting.ts +81 -0
  71. package/src/cli/tanstackTypes.ts +347 -67
  72. package/src/runtime/hydrationBoundary.tsx +12 -0
  73. package/src/runtime/index.tsx +107 -2
  74. package/src/runtime/outlet.tsx +48 -0
  75. package/src/runtime/plugin.node.tsx +58 -8
  76. package/src/runtime/plugin.tsx +372 -157
  77. package/src/runtime/plugin.worker.tsx +4 -0
  78. package/src/runtime/prefetchLink.tsx +1 -1
  79. package/src/runtime/routeTree.ts +194 -23
  80. package/src/runtime/ssr-shim.d.ts +1 -3
  81. package/src/runtime/types.ts +13 -0
  82. package/tests/router/cli.test.ts +315 -0
  83. package/tests/router/fastDefaults.test.ts +25 -0
  84. package/tests/router/hydrationBoundary.test.tsx +23 -0
  85. package/tests/router/prefetchLink.test.tsx +43 -7
  86. package/tests/router/routeTree.test.ts +416 -1
  87. package/tests/router/tanstackTypes.test.ts +415 -1
@@ -4,14 +4,18 @@ import { InternalRuntimeContext, getGlobalEnableRsc, getGlobalLayoutApp, getGlob
4
4
  import { merge } from "@modern-js/runtime-utils/merge";
5
5
  import { normalizePathname } from "@modern-js/runtime-utils/url";
6
6
  import { RouterProvider, createBrowserHistory, createHashHistory, createRouter, useLocation, useMatches, useNavigate, useRouter } from "@tanstack/react-router";
7
- import { RouterClient } from "@tanstack/react-router/ssr/client";
7
+ import { hydrate } from "@tanstack/react-router/ssr/client";
8
+ import { useContext, useMemo } from "react";
8
9
  import { createModernBasepathRewrite } from "./basepathRewrite.mjs";
9
10
  import { modifyRoutes, onAfterCreateRouter, onAfterHydrateRouter, onBeforeCreateRouter, onBeforeCreateRoutes, onBeforeHydrateRouter } from "./hooks.mjs";
11
+ import { wrapTanstackSsrHydrationBoundary } from "./hydrationBoundary.mjs";
10
12
  import { applyRouterRuntimeState } from "./lifecycle.mjs";
13
+ import { withModernRouteMatchContext } from "./outlet.mjs";
14
+ import { Link } from "./prefetchLink.mjs";
11
15
  import { createRouteTreeFromRouteObjects } from "./routeTree.mjs";
12
16
  import { getTanstackRscSerializationAdapters } from "./rsc/client.mjs";
17
+ import { getModernTanstackRouterFastDefaults } from "./types.mjs";
13
18
  import { createRouteObjectsFromConfig, urlJoin } from "./utils.mjs";
14
- import * as __rspack_external_react from "react";
15
19
  const BLOCKING_SUBSCRIBE_SYMBOL = Symbol.for('@modern-js/plugin-tanstack:blocking-subscribe');
16
20
  const BLOCKING_STATE_SYMBOL = Symbol.for('@modern-js/plugin-tanstack:blocking-state');
17
21
  function normalizeBase(b) {
@@ -39,6 +43,82 @@ function wrapRouterSubscribeWithBlockState(router, getBlockNavState) {
39
43
  };
40
44
  target[BLOCKING_SUBSCRIBE_SYMBOL] = true;
41
45
  }
46
+ const routerHydrationRecords = new WeakMap();
47
+ const routeModulesKey = '_routeModules';
48
+ function pickRouteModuleComponent(routeModule, seen = new Set()) {
49
+ if ('function' == typeof routeModule || routeModule && 'object' == typeof routeModule && '$$typeof' in routeModule) return routeModule;
50
+ if (!routeModule || 'object' != typeof routeModule) return;
51
+ if (seen.has(routeModule)) return;
52
+ seen.add(routeModule);
53
+ const module = routeModule;
54
+ for (const candidate of [
55
+ module.default,
56
+ module.Component
57
+ ]){
58
+ const component = pickRouteModuleComponent(candidate, seen);
59
+ if (component) return component;
60
+ }
61
+ }
62
+ function getCachedRouteModule(routeId) {
63
+ if ("u" < typeof window) return;
64
+ return window[routeModulesKey]?.[routeId];
65
+ }
66
+ function preloadHydratedRouteComponents(router) {
67
+ const preloadableRouter = router;
68
+ const routesById = preloadableRouter.routesById || {};
69
+ const matches = preloadableRouter.stores.matches.get();
70
+ return Promise.all(matches.map((match)=>{
71
+ if (void 0 === match.routeId || '' === match.routeId) return;
72
+ const route = routesById[match.routeId];
73
+ const component = route?.options?.component;
74
+ const preload = component?.load || component?.preload;
75
+ if ('function' != typeof preload) return;
76
+ return Promise.resolve(preload.call(component)).then((routeModule)=>{
77
+ const modernRouteId = route?.options?.staticData?.modernRouteId;
78
+ const cachedRouteModule = 'string' == typeof modernRouteId && '' !== modernRouteId ? getCachedRouteModule(modernRouteId) : void 0;
79
+ const resolvedComponent = pickRouteModuleComponent(cachedRouteModule ?? routeModule);
80
+ if (void 0 !== resolvedComponent && 'string' == typeof modernRouteId && '' !== modernRouteId) route.options.component = withModernRouteMatchContext(resolvedComponent, modernRouteId);
81
+ });
82
+ })).then(()=>void 0);
83
+ }
84
+ function getTanstackSsrHydrationRecord(router) {
85
+ const existingHydrationRecord = routerHydrationRecords.get(router);
86
+ if (void 0 !== existingHydrationRecord) return existingHydrationRecord;
87
+ const hydrationRecord = {
88
+ promise: Promise.resolve(),
89
+ status: 'pending'
90
+ };
91
+ routerHydrationRecords.set(router, hydrationRecord);
92
+ try {
93
+ hydrationRecord.promise = hydrate(router).then((value)=>preloadHydratedRouteComponents(router).then(()=>value)).then((value)=>{
94
+ hydrationRecord.status = 'fulfilled';
95
+ return value;
96
+ }, (error)=>{
97
+ hydrationRecord.status = 'rejected';
98
+ hydrationRecord.error = error;
99
+ throw error;
100
+ });
101
+ } catch (error) {
102
+ hydrationRecord.status = 'rejected';
103
+ hydrationRecord.error = error;
104
+ hydrationRecord.promise = Promise.reject(error);
105
+ hydrationRecord.promise.catch(()=>{});
106
+ }
107
+ return hydrationRecord;
108
+ }
109
+ function getTanstackSsrHydrationPromise(router) {
110
+ return getTanstackSsrHydrationRecord(router).promise;
111
+ }
112
+ function hasTanstackSsrHydrationRecord(router) {
113
+ return routerHydrationRecords.has(router);
114
+ }
115
+ function ModernRouterClient({ router }) {
116
+ const hydrationRecord = getTanstackSsrHydrationRecord(router);
117
+ if ('rejected' === hydrationRecord.status) throw hydrationRecord.error;
118
+ return /*#__PURE__*/ jsx(RouterProvider, {
119
+ router: router
120
+ });
121
+ }
42
122
  function stripSyntheticNotFoundRoute(routes) {
43
123
  return routes.filter((route)=>!('*' === route.path && !route.id && !route.loader)).map((route)=>{
44
124
  if (!route.children?.length) return route;
@@ -60,112 +140,134 @@ const tanstackRouterPlugin = (userConfig = {})=>{
60
140
  onBeforeHydrateRouter: onBeforeHydrateRouter
61
141
  },
62
142
  setup: (api)=>{
63
- api.onBeforeRender((context)=>{
143
+ const hooks = api.getHooks();
144
+ let cachedRouteObjects;
145
+ let cachedRouteTree = null;
146
+ let cachedRouter = null;
147
+ let cachedRouterBasepath = null;
148
+ const getMergedConfig = ()=>{
64
149
  const pluginConfig = api.getRuntimeConfig();
65
- const mergedConfig = merge(pluginConfig.router || {}, userConfig);
66
- if ("u" > typeof window && window._SSR_DATA && mergedConfig.unstable_reloadOnURLMismatch) {
150
+ return merge(pluginConfig.router || {}, userConfig);
151
+ };
152
+ const getRouteObjects = ()=>{
153
+ if (void 0 !== cachedRouteObjects) return cachedRouteObjects;
154
+ const mergedConfig = getMergedConfig();
155
+ const { routesConfig, createRoutes } = mergedConfig;
156
+ const finalRouteConfig = {
157
+ routes: getGlobalRoutes(),
158
+ globalApp: getGlobalLayoutApp(),
159
+ ...routesConfig
160
+ };
161
+ const routeObjects = createRoutes ? createRoutes() : createRouteObjectsFromConfig({
162
+ routesConfig: finalRouteConfig
163
+ }) || [];
164
+ const normalizedRouteObjects = createRoutes ? routeObjects : stripSyntheticNotFoundRoute(routeObjects);
165
+ cachedRouteObjects = hooks.modifyRoutes.call(normalizedRouteObjects);
166
+ return cachedRouteObjects;
167
+ };
168
+ const getRouteTree = ()=>{
169
+ if (cachedRouteTree) return cachedRouteTree;
170
+ const routeObjects = getRouteObjects();
171
+ if (!routeObjects.length) return null;
172
+ cachedRouteTree = createRouteTreeFromRouteObjects(routeObjects, {
173
+ rscPayloadRouter: getGlobalEnableRsc()
174
+ });
175
+ return cachedRouteTree;
176
+ };
177
+ const selectBasePath = (pathname)=>{
178
+ const { serverBase = [] } = getMergedConfig();
179
+ const match = serverBase.find((baseUrl)=>isSegmentPrefix(pathname, baseUrl));
180
+ return match || '/';
181
+ };
182
+ const getClientBasename = (runtimeContext)=>{
183
+ const { basename = '' } = getMergedConfig();
184
+ const baseUrl = selectBasePath(location.pathname).replace(/^\/*/, '/');
185
+ return '/' === baseUrl ? urlJoin(baseUrl, runtimeContext._internalRouterBaseName || basename || '') : baseUrl;
186
+ };
187
+ const getRouter = (runtimeContext, _basename)=>{
188
+ const routeTree = getRouteTree();
189
+ if (!routeTree) return null;
190
+ const lifecycleContext = {
191
+ framework: 'tanstack',
192
+ phase: 'client-create',
193
+ routes: getRouteObjects(),
194
+ runtimeContext,
195
+ basename: _basename
196
+ };
197
+ hooks.onBeforeCreateRouter.call(lifecycleContext);
198
+ if (cachedRouter && cachedRouterBasepath === _basename) {
199
+ wrapRouterSubscribeWithBlockState(cachedRouter, runtimeContext.unstable_getBlockNavState);
200
+ hooks.onAfterCreateRouter.call({
201
+ ...lifecycleContext,
202
+ router: cachedRouter,
203
+ runtimeContext
204
+ });
205
+ return cachedRouter;
206
+ }
207
+ const mergedConfig = getMergedConfig();
208
+ const { supportHtml5History = true } = mergedConfig;
209
+ const history = supportHtml5History ? createBrowserHistory() : createHashHistory();
210
+ const rewrite = createModernBasepathRewrite(_basename);
211
+ const serializationAdapters = getGlobalEnableRsc() ? getTanstackRscSerializationAdapters() : void 0;
212
+ cachedRouter = createRouter({
213
+ ...getModernTanstackRouterFastDefaults(mergedConfig),
214
+ routeTree,
215
+ basepath: '/',
216
+ rewrite,
217
+ history,
218
+ context: {},
219
+ ...serializationAdapters ? {
220
+ serializationAdapters
221
+ } : {}
222
+ });
223
+ cachedRouterBasepath = _basename;
224
+ wrapRouterSubscribeWithBlockState(cachedRouter, runtimeContext.unstable_getBlockNavState);
225
+ hooks.onAfterCreateRouter.call({
226
+ ...lifecycleContext,
227
+ router: cachedRouter,
228
+ runtimeContext
229
+ });
230
+ return cachedRouter;
231
+ };
232
+ api.onBeforeRender((context)=>{
233
+ const mergedConfig = getMergedConfig();
234
+ if ("u" > typeof window && void 0 !== window._SSR_DATA && mergedConfig.unstable_reloadOnURLMismatch) {
67
235
  const { ssrContext } = context;
68
236
  const currentPathname = normalizePathname(window.location.pathname);
69
- const initialPathname = ssrContext?.request?.pathname && normalizePathname(ssrContext.request.pathname);
70
- if (initialPathname && initialPathname !== currentPathname) {
237
+ const initialPathname = 'string' == typeof ssrContext?.request?.pathname ? normalizePathname(ssrContext.request.pathname) : void 0;
238
+ if (void 0 !== initialPathname && '' !== initialPathname && initialPathname !== currentPathname) {
71
239
  const errorMsg = `The initial URL ${initialPathname} and the URL ${currentPathname} to be hydrated do not match, reload.`;
72
240
  console.error(errorMsg);
73
241
  window.location.reload();
74
242
  }
75
243
  }
76
244
  context.router = {
245
+ Link: Link,
77
246
  useMatches: useMatches,
78
247
  useLocation: useLocation,
79
248
  useNavigate: useNavigate,
80
249
  useRouter: useRouter
81
250
  };
251
+ const hasSSRBootstrap = "u" > typeof window && Boolean(window.$_TSR);
252
+ if (hasSSRBootstrap && getRouteObjects().length > 0) {
253
+ const runtimeContext = context;
254
+ const router = getRouter(runtimeContext, getClientBasename(runtimeContext));
255
+ if (null != router) return getTanstackSsrHydrationPromise(router).then(()=>void 0);
256
+ }
82
257
  });
83
258
  api.wrapRoot((App)=>{
84
- const mergedConfig = merge(api.getRuntimeConfig().router || {}, userConfig);
85
- const { serverBase = [], supportHtml5History = true, basename = '', routesConfig, createRoutes } = mergedConfig;
86
- const finalRouteConfig = {
87
- routes: getGlobalRoutes(),
88
- globalApp: getGlobalLayoutApp(),
89
- ...routesConfig
90
- };
91
- if (!finalRouteConfig.routes && !createRoutes) return App;
92
- const hooks = api.getHooks();
93
- let cachedRouteObjects;
94
- const getRouteObjects = ()=>{
95
- if (void 0 !== cachedRouteObjects) return cachedRouteObjects;
96
- const routeObjects = createRoutes ? createRoutes() : createRouteObjectsFromConfig({
97
- routesConfig: finalRouteConfig
98
- }) || [];
99
- const normalizedRouteObjects = createRoutes ? routeObjects : stripSyntheticNotFoundRoute(routeObjects);
100
- cachedRouteObjects = hooks.modifyRoutes.call(normalizedRouteObjects);
101
- return cachedRouteObjects;
102
- };
103
- const selectBasePath = (pathname)=>{
104
- const match = serverBase.find((baseUrl)=>isSegmentPrefix(pathname, baseUrl));
105
- return match || '/';
106
- };
107
- let cachedRouteTree = null;
108
- let cachedRouter = null;
109
- let cachedRouterBasepath = null;
259
+ if (0 === getRouteObjects().length) return App;
110
260
  const RouterWrapper = ()=>{
111
- const runtimeContext = (0, __rspack_external_react.useContext)(InternalRuntimeContext);
112
- const baseUrl = selectBasePath(location.pathname).replace(/^\/*/, '/');
113
- const _basename = '/' === baseUrl ? urlJoin(baseUrl, runtimeContext._internalRouterBaseName || basename || '') : baseUrl;
114
- const routeTree = (0, __rspack_external_react.useMemo)(()=>{
115
- if (cachedRouteTree) return cachedRouteTree;
116
- const routeObjects = getRouteObjects();
117
- if (!routeObjects.length) return null;
118
- cachedRouteTree = createRouteTreeFromRouteObjects(routeObjects, {
119
- rscPayloadRouter: getGlobalEnableRsc()
120
- });
121
- return cachedRouteTree;
122
- }, []);
261
+ const runtimeContext = useContext(InternalRuntimeContext);
262
+ const _basename = getClientBasename(runtimeContext);
263
+ const routeTree = useMemo(()=>getRouteTree(), []);
123
264
  if (!routeTree) return App ? /*#__PURE__*/ jsx(App, {}) : null;
124
- const router = (0, __rspack_external_react.useMemo)(()=>{
125
- const lifecycleContext = {
126
- framework: 'tanstack',
127
- phase: 'client-create',
128
- routes: getRouteObjects(),
129
- runtimeContext,
130
- basename: _basename
131
- };
132
- hooks.onBeforeCreateRouter.call(lifecycleContext);
133
- if (cachedRouter && cachedRouterBasepath === _basename) {
134
- wrapRouterSubscribeWithBlockState(cachedRouter, runtimeContext.unstable_getBlockNavState);
135
- hooks.onAfterCreateRouter.call({
136
- ...lifecycleContext,
137
- router: cachedRouter,
138
- runtimeContext
139
- });
140
- return cachedRouter;
141
- }
142
- const history = supportHtml5History ? createBrowserHistory() : createHashHistory();
143
- const rewrite = createModernBasepathRewrite(_basename);
144
- const serializationAdapters = getGlobalEnableRsc() ? getTanstackRscSerializationAdapters() : void 0;
145
- cachedRouter = createRouter({
146
- routeTree,
147
- basepath: '/',
148
- rewrite,
149
- history,
150
- context: {},
151
- ...serializationAdapters ? {
152
- serializationAdapters
153
- } : {}
154
- });
155
- cachedRouterBasepath = _basename;
156
- wrapRouterSubscribeWithBlockState(cachedRouter, runtimeContext.unstable_getBlockNavState);
157
- hooks.onAfterCreateRouter.call({
158
- ...lifecycleContext,
159
- router: cachedRouter,
160
- runtimeContext
161
- });
162
- return cachedRouter;
163
- }, [
265
+ const router = useMemo(()=>getRouter(runtimeContext, _basename), [
164
266
  _basename,
165
267
  routeTree,
166
- supportHtml5History,
167
268
  runtimeContext
168
269
  ]);
270
+ if (!router) return App ? /*#__PURE__*/ jsx(App, {}) : null;
169
271
  const runtimeState = applyRouterRuntimeState(runtimeContext, {
170
272
  framework: 'tanstack',
171
273
  basename: _basename,
@@ -179,30 +281,29 @@ const tanstackRouterPlugin = (userConfig = {})=>{
179
281
  basename: _basename,
180
282
  router
181
283
  };
182
- const hasSSRBootstrap = "u" > typeof window && Boolean(window.$_TSR);
183
- if (hasSSRBootstrap) hooks.onBeforeHydrateRouter.call({
284
+ const hasSSRBootstrap = "u" > typeof window && (Boolean(window.$_TSR) || hasTanstackSsrHydrationRecord(router));
285
+ const needsRouterClient = hasSSRBootstrap;
286
+ if (needsRouterClient) hooks.onBeforeHydrateRouter.call({
184
287
  ...lifecycleContext,
185
288
  phase: 'hydrate',
186
289
  router,
187
290
  runtimeContext: runtimeState
188
291
  });
189
- const RouterContent = hasSSRBootstrap ? /*#__PURE__*/ jsx(__rspack_external_react.Suspense, {
190
- fallback: null,
191
- children: /*#__PURE__*/ jsx(RouterClient, {
192
- router: router
193
- })
292
+ const RouterContent = needsRouterClient ? /*#__PURE__*/ jsx(ModernRouterClient, {
293
+ router: router
194
294
  }) : /*#__PURE__*/ jsx(RouterProvider, {
195
295
  router: router
196
296
  });
197
- if (hasSSRBootstrap) hooks.onAfterHydrateRouter.call({
297
+ const HydratableRouterContent = wrapTanstackSsrHydrationBoundary(RouterContent, hasSSRBootstrap);
298
+ if (needsRouterClient) hooks.onAfterHydrateRouter.call({
198
299
  ...lifecycleContext,
199
300
  phase: 'hydrate',
200
301
  router,
201
302
  runtimeContext: runtimeState
202
303
  });
203
304
  return App ? /*#__PURE__*/ jsx(App, {
204
- children: RouterContent
205
- }) : RouterContent;
305
+ children: HydratableRouterContent
306
+ }) : HydratableRouterContent;
206
307
  };
207
308
  return RouterWrapper;
208
309
  });
@@ -6,24 +6,42 @@ import { createRequestContext, storage } from "@modern-js/runtime-utils/node";
6
6
  import { time } from "@modern-js/runtime-utils/time";
7
7
  import { LOADER_REPORTER_NAME } from "@modern-js/utils/universal/constants";
8
8
  import { RouterProvider, createMemoryHistory, createRouter } from "@tanstack/react-router";
9
- import { attachRouterServerSsrUtils } from "@tanstack/react-router/ssr/server";
10
- import { Suspense, useContext } from "react";
9
+ import { attachRouterServerSsrUtils } from "@tanstack/router-core/ssr/server";
10
+ import { useContext } from "react";
11
11
  import { createModernBasepathRewrite } from "./basepathRewrite.mjs";
12
12
  import { modifyRoutes, onAfterCreateRouter, onAfterHydrateRouter, onBeforeCreateRouter, onBeforeCreateRoutes, onBeforeHydrateRouter } from "./hooks.mjs";
13
+ import { wrapTanstackSsrHydrationBoundary } from "./hydrationBoundary.mjs";
13
14
  import { applyRouterServerPrepareResult, createRouterServerSnapshot } from "./lifecycle.mjs";
14
15
  import { createRouteTreeFromRouteObjects, getModernRouteIdsFromMatches } from "./routeTree.mjs";
15
16
  import { createTanstackRscServerPayload, handleTanstackRscRedirect } from "./rsc/payloadRouter.mjs";
17
+ import { getModernTanstackRouterFastDefaults } from "./types.mjs";
16
18
  import { createRouteObjectsFromConfig, urlJoin } from "./utils.mjs";
17
19
  const setTanstackRscServerPayload = (payload)=>{
18
20
  const storageContext = storage.useContext?.();
19
21
  if (storageContext) storageContext.serverPayload = payload;
20
22
  };
23
+ function isPromiseLike(value) {
24
+ return Boolean(value && 'function' == typeof value.then);
25
+ }
21
26
  function isPreloadableRouteComponent(component) {
22
27
  if (!component || 'function' != typeof component) return false;
23
28
  const preloadable = component;
24
29
  return 'function' == typeof preloadable.load || 'function' == typeof preloadable.preload;
25
30
  }
31
+ function isReactLazyRouteComponent(component) {
32
+ return null != component && 'object' == typeof component && 'function' == typeof component._init && '_payload' in component;
33
+ }
34
+ async function preloadReactLazyRouteComponent(component) {
35
+ try {
36
+ component._init?.(component._payload);
37
+ } catch (thrown) {
38
+ if (!isPromiseLike(thrown)) throw thrown;
39
+ await thrown;
40
+ component._init?.(component._payload);
41
+ }
42
+ }
26
43
  async function preloadRouteComponent(component) {
44
+ if (isReactLazyRouteComponent(component)) return void await preloadReactLazyRouteComponent(component);
27
45
  if (!isPreloadableRouteComponent(component)) return;
28
46
  if ('function' == typeof component.load) return void await component.load({});
29
47
  await component.preload?.({});
@@ -162,6 +180,7 @@ const tanstackRouterPlugin = (userConfig = {})=>{
162
180
  };
163
181
  hooks.onBeforeCreateRouter.call(routerLifecycleContext);
164
182
  const tanstackRouter = createRouter({
183
+ ...getModernTanstackRouterFastDefaults(mergedConfig),
165
184
  routeTree,
166
185
  history,
167
186
  basepath: '/',
@@ -207,10 +226,12 @@ const tanstackRouterPlugin = (userConfig = {})=>{
207
226
  await preloadMatchedRouteComponents(serverRouter);
208
227
  context.ssrContext?.response.status(tanstackRouter.state.statusCode);
209
228
  await serverRouter.serverSsr?.dehydrate?.();
210
- await waitForRouterSerialization(serverRouter);
211
- if (isRSCNavigation) setTanstackRscServerPayload(createTanstackRscServerPayload(serverRouter, {
212
- omitClientLoaderData: true
213
- }));
229
+ if (isRSCNavigation) {
230
+ await waitForRouterSerialization(serverRouter);
231
+ setTanstackRscServerPayload(createTanstackRscServerPayload(serverRouter, {
232
+ omitClientLoaderData: true
233
+ }));
234
+ }
214
235
  const ssrScriptTags = serverRouter.serverSsr?.takeBufferedScripts?.();
215
236
  const hydrationScripts = routerManagedTagsToHtml(ssrScriptTags);
216
237
  const matchedRouteIds = getModernRouteIdsFromMatches(serverRouter);
@@ -248,12 +269,9 @@ const tanstackRouterPlugin = (userConfig = {})=>{
248
269
  if (!router) return App ? /*#__PURE__*/ jsx(App, {
249
270
  ...props
250
271
  }) : null;
251
- const routerWrapper = /*#__PURE__*/ jsx(Suspense, {
252
- fallback: null,
253
- children: /*#__PURE__*/ jsx(RouterProvider, {
254
- router: router
255
- })
256
- });
272
+ const routerWrapper = wrapTanstackSsrHydrationBoundary(/*#__PURE__*/ jsx(RouterProvider, {
273
+ router: router
274
+ }), true);
257
275
  return App ? /*#__PURE__*/ jsx(App, {
258
276
  children: routerWrapper
259
277
  }) : routerWrapper;
@@ -0,0 +1,2 @@
1
+ import "node:module";
2
+ export { default, tanstackRouterPlugin } from "./plugin.node.mjs";
@@ -5,7 +5,7 @@ function resolvePreloadFromPrefetch(prefetch, preload) {
5
5
  if (void 0 !== preload) return preload;
6
6
  if ('none' === prefetch) return false;
7
7
  if ('intent' === prefetch || 'render' === prefetch || 'viewport' === prefetch) return prefetch;
8
- return preload;
8
+ return 'viewport';
9
9
  }
10
10
  const LinkComponentImpl = (props)=>{
11
11
  const { prefetch, preload, ...rest } = props;