@bleedingdev/modern-js-plugin-tanstack 3.2.0-ultramodern.1 → 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 (73) hide show
  1. package/dist/cjs/cli/index.js +15 -6
  2. package/dist/cjs/cli/routeSplitting.js +83 -0
  3. package/dist/cjs/cli/tanstackTypes.js +146 -58
  4. package/dist/cjs/runtime/hydrationBoundary.js +44 -0
  5. package/dist/cjs/runtime/index.js +321 -69
  6. package/dist/cjs/runtime/outlet.js +54 -0
  7. package/dist/cjs/runtime/plugin.js +194 -90
  8. package/dist/cjs/runtime/plugin.node.js +29 -11
  9. package/dist/cjs/runtime/plugin.worker.js +49 -0
  10. package/dist/cjs/runtime/routeTree.js +72 -12
  11. package/dist/cjs/runtime/types.js +27 -1
  12. package/dist/esm/cli/index.mjs +7 -7
  13. package/dist/esm/cli/routeSplitting.mjs +43 -0
  14. package/dist/esm/cli/tanstackTypes.mjs +146 -58
  15. package/dist/esm/runtime/hydrationBoundary.mjs +10 -0
  16. package/dist/esm/runtime/index.mjs +3 -2
  17. package/dist/esm/runtime/outlet.mjs +17 -0
  18. package/dist/esm/runtime/plugin.mjs +197 -93
  19. package/dist/esm/runtime/plugin.node.mjs +30 -12
  20. package/dist/esm/runtime/plugin.worker.mjs +1 -0
  21. package/dist/esm/runtime/routeTree.mjs +73 -13
  22. package/dist/esm/runtime/types.mjs +7 -0
  23. package/dist/esm-node/cli/index.mjs +7 -7
  24. package/dist/esm-node/cli/routeSplitting.mjs +44 -0
  25. package/dist/esm-node/cli/tanstackTypes.mjs +146 -58
  26. package/dist/esm-node/runtime/hydrationBoundary.mjs +11 -0
  27. package/dist/esm-node/runtime/index.mjs +3 -2
  28. package/dist/esm-node/runtime/outlet.mjs +18 -0
  29. package/dist/esm-node/runtime/plugin.mjs +197 -93
  30. package/dist/esm-node/runtime/plugin.node.mjs +30 -12
  31. package/dist/esm-node/runtime/plugin.worker.mjs +2 -0
  32. package/dist/esm-node/runtime/routeTree.mjs +73 -13
  33. package/dist/esm-node/runtime/types.mjs +7 -0
  34. package/dist/types/cli/index.d.ts +4 -0
  35. package/dist/types/cli/routeSplitting.d.ts +29 -0
  36. package/dist/types/runtime/hydrationBoundary.d.ts +2 -0
  37. package/dist/types/runtime/index.d.ts +5 -2
  38. package/dist/types/runtime/outlet.d.ts +2 -0
  39. package/dist/types/runtime/plugin.d.ts +1 -1
  40. package/dist/types/runtime/plugin.node.d.ts +1 -1
  41. package/dist/types/runtime/plugin.worker.d.ts +1 -0
  42. package/dist/types/runtime/types.d.ts +7 -0
  43. package/package.json +14 -14
  44. package/src/cli/index.ts +32 -18
  45. package/src/cli/routeSplitting.ts +81 -0
  46. package/src/cli/tanstackTypes.ts +217 -67
  47. package/src/runtime/basepathRewrite.ts +1 -0
  48. package/src/runtime/dataMutation.tsx +1 -0
  49. package/src/runtime/hydrationBoundary.tsx +12 -0
  50. package/src/runtime/index.tsx +107 -2
  51. package/src/runtime/lifecycle.ts +1 -0
  52. package/src/runtime/outlet.tsx +42 -0
  53. package/src/runtime/plugin.node.tsx +58 -8
  54. package/src/runtime/plugin.tsx +354 -149
  55. package/src/runtime/plugin.worker.tsx +4 -0
  56. package/src/runtime/routeTree.ts +195 -23
  57. package/src/runtime/rsc/ClientSlot.tsx +1 -0
  58. package/src/runtime/rsc/CompositeComponent.tsx +1 -0
  59. package/src/runtime/rsc/ReplayableStream.ts +1 -0
  60. package/src/runtime/rsc/RscNodeRenderer.tsx +1 -0
  61. package/src/runtime/rsc/client.tsx +2 -3
  62. package/src/runtime/rsc/createRscProxy.tsx +1 -0
  63. package/src/runtime/rsc/payloadRouter.ts +1 -0
  64. package/src/runtime/rsc/server.tsx +1 -0
  65. package/src/runtime/rsc/slotUsageSanitizer.ts +1 -0
  66. package/src/runtime/ssr-shim.d.ts +1 -3
  67. package/src/runtime/types.ts +13 -0
  68. package/src/runtime/utils.tsx +1 -0
  69. package/tests/router/cli.test.ts +239 -0
  70. package/tests/router/fastDefaults.test.ts +25 -0
  71. package/tests/router/hydrationBoundary.test.tsx +23 -0
  72. package/tests/router/routeTree.test.ts +416 -1
  73. package/tests/router/tanstackTypes.test.ts +184 -0
@@ -1,6 +1,7 @@
1
- export * from "@tanstack/react-router";
2
- export { useMatch } from "@tanstack/react-router";
1
+ export { Asset, Await, Block, CatchBoundary, CatchNotFound, ClientOnly, DEFAULT_PROTOCOL_ALLOWLIST, DefaultGlobalNotFound, ErrorComponent, FileRoute, FileRouteLoader, HeadContent, LazyRoute, Match, MatchRoute, Matches, Navigate, NotFoundRoute, RootRoute, Route, RouteApi, Router, RouterContextProvider, RouterProvider, ScriptOnce, Scripts, ScrollRestoration, SearchParamError, cleanPath, composeRewrites, createBrowserHistory, createControlledPromise, createFileRoute, createHashHistory, createHistory, createLazyFileRoute, createLazyRoute, createLink, createMemoryHistory, createRootRoute, createRootRouteWithContext, createRoute, createRouteMask, createRouter, createRouterConfig, createSerializationAdapter, deepEqual, defaultParseSearch, defaultStringifySearch, defer, functionalUpdate, getRouteApi, interpolatePath, isMatch, isNotFound, isPlainArray, isPlainObject, isRedirect, joinPaths, lazyFn, lazyRouteComponent, linkOptions, notFound, parseSearchWith, reactUse, redirect, replaceEqualDeep, resolvePath, retainSearchParams, rootRouteId, rootRouteWithContext, stringifySearchWith, stripSearchParams, trimPath, trimPathLeft, trimPathRight, useAwaited, useBlocker, useCanGoBack, useChildMatches, useElementScrollRestoration, useHydrated, useLayoutEffect, useLinkProps, useLoaderData, useLoaderDeps, useLocation, useMatch, useMatchRoute, useMatches, useNavigate, useParams, useParentMatches, useRouteContext, useRouter, useRouterState, useSearch, useTags } from "@tanstack/react-router";
3
2
  export { Form, RouteActionResponseError, useFetcher } from "./dataMutation.mjs";
3
+ export { Outlet } from "./outlet.mjs";
4
4
  export { tanstackRouterPlugin as default, tanstackRouterPlugin } from "./plugin.mjs";
5
5
  export { Link, NavLink } from "./prefetchLink.mjs";
6
6
  export { CompositeComponent } from "./rsc/client.mjs";
7
+ export { getModernTanstackRouterFastDefaults, modernTanstackRouterFastDefaults } from "./types.mjs";
@@ -0,0 +1,17 @@
1
+ import { jsx } from "react/jsx-runtime";
2
+ import { Outlet } from "@tanstack/react-router";
3
+ import { createElement, memo } from "react";
4
+ const outlet_Outlet = /*#__PURE__*/ memo(function() {
5
+ return /*#__PURE__*/ jsx(Outlet, {});
6
+ });
7
+ function withModernRouteMatchContext(component, _routeId) {
8
+ if (!component) return component;
9
+ const Component = component;
10
+ const WrappedRouteComponent = (props)=>/*#__PURE__*/ createElement(Component, props);
11
+ const preloadable = component;
12
+ if ('function' == typeof preloadable.load) WrappedRouteComponent.load = preloadable.load.bind(preloadable);
13
+ if ('function' == typeof preloadable.preload) WrappedRouteComponent.preload = preloadable.preload.bind(preloadable);
14
+ else if ('function' == typeof preloadable.load) WrappedRouteComponent.preload = WrappedRouteComponent.load;
15
+ return WrappedRouteComponent;
16
+ }
17
+ export { outlet_Outlet as Outlet, withModernRouteMatchContext };
@@ -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,85 @@ 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
+ 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
+ }
41
124
  function stripSyntheticNotFoundRoute(routes) {
42
125
  return routes.filter((route)=>!('*' === route.path && !route.id && !route.loader)).map((route)=>{
43
126
  if (!route.children?.length) return route;
@@ -59,9 +142,97 @@ const tanstackRouterPlugin = (userConfig = {})=>{
59
142
  onBeforeHydrateRouter: onBeforeHydrateRouter
60
143
  },
61
144
  setup: (api)=>{
62
- api.onBeforeRender((context)=>{
145
+ const hooks = api.getHooks();
146
+ let cachedRouteObjects;
147
+ let cachedRouteTree = null;
148
+ let cachedRouter = null;
149
+ let cachedRouterBasepath = null;
150
+ const getMergedConfig = ()=>{
63
151
  const pluginConfig = api.getRuntimeConfig();
64
- const mergedConfig = merge(pluginConfig.router || {}, userConfig);
152
+ return merge(pluginConfig.router || {}, userConfig);
153
+ };
154
+ const getRouteObjects = ()=>{
155
+ if (void 0 !== cachedRouteObjects) return cachedRouteObjects;
156
+ const mergedConfig = getMergedConfig();
157
+ const { routesConfig, createRoutes } = mergedConfig;
158
+ const finalRouteConfig = {
159
+ routes: getGlobalRoutes(),
160
+ globalApp: getGlobalLayoutApp(),
161
+ ...routesConfig
162
+ };
163
+ const routeObjects = createRoutes ? createRoutes() : createRouteObjectsFromConfig({
164
+ routesConfig: finalRouteConfig
165
+ }) || [];
166
+ const normalizedRouteObjects = createRoutes ? routeObjects : stripSyntheticNotFoundRoute(routeObjects);
167
+ cachedRouteObjects = hooks.modifyRoutes.call(normalizedRouteObjects);
168
+ return cachedRouteObjects;
169
+ };
170
+ const getRouteTree = ()=>{
171
+ if (cachedRouteTree) return cachedRouteTree;
172
+ const routeObjects = getRouteObjects();
173
+ if (!routeObjects.length) return null;
174
+ cachedRouteTree = createRouteTreeFromRouteObjects(routeObjects, {
175
+ rscPayloadRouter: getGlobalEnableRsc()
176
+ });
177
+ return cachedRouteTree;
178
+ };
179
+ const selectBasePath = (pathname)=>{
180
+ const { serverBase = [] } = getMergedConfig();
181
+ const match = serverBase.find((baseUrl)=>isSegmentPrefix(pathname, baseUrl));
182
+ return match || '/';
183
+ };
184
+ const getClientBasename = (runtimeContext)=>{
185
+ const { basename = '' } = getMergedConfig();
186
+ const baseUrl = selectBasePath(location.pathname).replace(/^\/*/, '/');
187
+ return '/' === baseUrl ? urlJoin(baseUrl, runtimeContext._internalRouterBaseName || basename || '') : baseUrl;
188
+ };
189
+ const getRouter = (runtimeContext, _basename)=>{
190
+ const routeTree = getRouteTree();
191
+ if (!routeTree) return null;
192
+ const lifecycleContext = {
193
+ framework: 'tanstack',
194
+ phase: 'client-create',
195
+ routes: getRouteObjects(),
196
+ runtimeContext,
197
+ basename: _basename
198
+ };
199
+ hooks.onBeforeCreateRouter.call(lifecycleContext);
200
+ if (cachedRouter && cachedRouterBasepath === _basename) {
201
+ wrapRouterSubscribeWithBlockState(cachedRouter, runtimeContext.unstable_getBlockNavState);
202
+ hooks.onAfterCreateRouter.call({
203
+ ...lifecycleContext,
204
+ router: cachedRouter,
205
+ runtimeContext
206
+ });
207
+ return cachedRouter;
208
+ }
209
+ const mergedConfig = getMergedConfig();
210
+ const { supportHtml5History = true } = mergedConfig;
211
+ const history = supportHtml5History ? createBrowserHistory() : createHashHistory();
212
+ const rewrite = createModernBasepathRewrite(_basename);
213
+ const serializationAdapters = getGlobalEnableRsc() ? getTanstackRscSerializationAdapters() : void 0;
214
+ cachedRouter = createRouter({
215
+ ...getModernTanstackRouterFastDefaults(mergedConfig),
216
+ routeTree,
217
+ basepath: '/',
218
+ rewrite,
219
+ history,
220
+ context: {},
221
+ ...serializationAdapters ? {
222
+ serializationAdapters
223
+ } : {}
224
+ });
225
+ cachedRouterBasepath = _basename;
226
+ wrapRouterSubscribeWithBlockState(cachedRouter, runtimeContext.unstable_getBlockNavState);
227
+ hooks.onAfterCreateRouter.call({
228
+ ...lifecycleContext,
229
+ router: cachedRouter,
230
+ runtimeContext
231
+ });
232
+ return cachedRouter;
233
+ };
234
+ api.onBeforeRender(async (context)=>{
235
+ const mergedConfig = getMergedConfig();
65
236
  if ("u" > typeof window && window._SSR_DATA && mergedConfig.unstable_reloadOnURLMismatch) {
66
237
  const { ssrContext } = context;
67
238
  const currentPathname = normalizePathname(window.location.pathname);
@@ -73,98 +244,32 @@ const tanstackRouterPlugin = (userConfig = {})=>{
73
244
  }
74
245
  }
75
246
  context.router = {
247
+ Link: Link,
76
248
  useMatches: useMatches,
77
249
  useLocation: useLocation,
78
250
  useNavigate: useNavigate,
79
251
  useRouter: useRouter
80
252
  };
253
+ const hasSSRBootstrap = "u" > typeof window && Boolean(window.$_TSR);
254
+ if (hasSSRBootstrap && getRouteObjects().length) {
255
+ const runtimeContext = context;
256
+ const router = getRouter(runtimeContext, getClientBasename(runtimeContext));
257
+ if (router) await getTanstackSsrHydrationPromise(router);
258
+ }
81
259
  });
82
260
  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;
261
+ if (!getRouteObjects().length) return App;
109
262
  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
- }, []);
263
+ const runtimeContext = useContext(InternalRuntimeContext);
264
+ const _basename = getClientBasename(runtimeContext);
265
+ const routeTree = useMemo(()=>getRouteTree(), []);
122
266
  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
- }, [
267
+ const router = useMemo(()=>getRouter(runtimeContext, _basename), [
163
268
  _basename,
164
269
  routeTree,
165
- supportHtml5History,
166
270
  runtimeContext
167
271
  ]);
272
+ if (!router) return App ? /*#__PURE__*/ jsx(App, {}) : null;
168
273
  const runtimeState = applyRouterRuntimeState(runtimeContext, {
169
274
  framework: 'tanstack',
170
275
  basename: _basename,
@@ -178,30 +283,29 @@ const tanstackRouterPlugin = (userConfig = {})=>{
178
283
  basename: _basename,
179
284
  router
180
285
  };
181
- const hasSSRBootstrap = "u" > typeof window && Boolean(window.$_TSR);
182
- if (hasSSRBootstrap) hooks.onBeforeHydrateRouter.call({
286
+ const hasSSRBootstrap = "u" > typeof window && (Boolean(window.$_TSR) || hasTanstackSsrHydrationRecord(router));
287
+ const needsRouterClient = hasSSRBootstrap;
288
+ if (needsRouterClient) hooks.onBeforeHydrateRouter.call({
183
289
  ...lifecycleContext,
184
290
  phase: 'hydrate',
185
291
  router,
186
292
  runtimeContext: runtimeState
187
293
  });
188
- const RouterContent = hasSSRBootstrap ? /*#__PURE__*/ jsx(__rspack_external_react.Suspense, {
189
- fallback: null,
190
- children: /*#__PURE__*/ jsx(RouterClient, {
191
- router: router
192
- })
294
+ const RouterContent = needsRouterClient ? /*#__PURE__*/ jsx(ModernRouterClient, {
295
+ router: router
193
296
  }) : /*#__PURE__*/ jsx(RouterProvider, {
194
297
  router: router
195
298
  });
196
- if (hasSSRBootstrap) hooks.onAfterHydrateRouter.call({
299
+ const HydratableRouterContent = wrapTanstackSsrHydrationBoundary(RouterContent, hasSSRBootstrap);
300
+ if (needsRouterClient) hooks.onAfterHydrateRouter.call({
197
301
  ...lifecycleContext,
198
302
  phase: 'hydrate',
199
303
  router,
200
304
  runtimeContext: runtimeState
201
305
  });
202
306
  return App ? /*#__PURE__*/ jsx(App, {
203
- children: RouterContent
204
- }) : RouterContent;
307
+ children: HydratableRouterContent
308
+ }) : HydratableRouterContent;
205
309
  };
206
310
  return RouterWrapper;
207
311
  });
@@ -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 Boolean(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";