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