@bleedingdev/modern-js-plugin-tanstack 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 (60) hide show
  1. package/dist/cjs/cli/index.js +12 -0
  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 +4 -1
  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 +4 -1
  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 +15 -15
  44. package/src/cli/index.ts +17 -0
  45. package/src/cli/routeSplitting.ts +81 -0
  46. package/src/cli/tanstackTypes.ts +216 -67
  47. package/src/runtime/hydrationBoundary.tsx +12 -0
  48. package/src/runtime/index.tsx +107 -2
  49. package/src/runtime/outlet.tsx +42 -0
  50. package/src/runtime/plugin.node.tsx +57 -8
  51. package/src/runtime/plugin.tsx +353 -149
  52. package/src/runtime/plugin.worker.tsx +4 -0
  53. package/src/runtime/routeTree.ts +194 -23
  54. package/src/runtime/ssr-shim.d.ts +1 -3
  55. package/src/runtime/types.ts +13 -0
  56. package/tests/router/cli.test.ts +239 -0
  57. package/tests/router/fastDefaults.test.ts +25 -0
  58. package/tests/router/hydrationBoundary.test.tsx +23 -0
  59. package/tests/router/routeTree.test.ts +416 -1
  60. package/tests/router/tanstackTypes.test.ts +184 -0
@@ -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,85 @@ 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
+ async function preloadHydratedRouteComponents(router) {
67
+ const preloadableRouter = router;
68
+ const routesById = preloadableRouter.routesById || {};
69
+ const matches = preloadableRouter.stores.matches.get();
70
+ await Promise.all(matches.map((match)=>{
71
+ if (!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 resolvedComponent = pickRouteModuleComponent(modernRouteId && getCachedRouteModule(modernRouteId) || routeModule);
79
+ if (resolvedComponent && modernRouteId) route.options.component = withModernRouteMatchContext(resolvedComponent, modernRouteId);
80
+ });
81
+ }));
82
+ }
83
+ function getTanstackSsrHydrationRecord(router) {
84
+ let hydrationRecord = routerHydrationRecords.get(router);
85
+ if (!hydrationRecord) {
86
+ hydrationRecord = {
87
+ promise: Promise.resolve(),
88
+ status: 'pending'
89
+ };
90
+ routerHydrationRecords.set(router, hydrationRecord);
91
+ try {
92
+ hydrationRecord.promise = hydrate(router).then(async (value)=>{
93
+ await preloadHydratedRouteComponents(router);
94
+ return value;
95
+ }).then((value)=>{
96
+ hydrationRecord.status = 'fulfilled';
97
+ return value;
98
+ }, (error)=>{
99
+ hydrationRecord.status = 'rejected';
100
+ hydrationRecord.error = error;
101
+ throw error;
102
+ });
103
+ } catch (error) {
104
+ hydrationRecord.status = 'rejected';
105
+ hydrationRecord.error = error;
106
+ hydrationRecord.promise = Promise.reject(error);
107
+ hydrationRecord.promise.catch(()=>{});
108
+ }
109
+ }
110
+ return hydrationRecord;
111
+ }
112
+ function getTanstackSsrHydrationPromise(router) {
113
+ return getTanstackSsrHydrationRecord(router).promise;
114
+ }
115
+ function hasTanstackSsrHydrationRecord(router) {
116
+ return routerHydrationRecords.has(router);
117
+ }
118
+ function ModernRouterClient({ router }) {
119
+ const hydrationRecord = getTanstackSsrHydrationRecord(router);
120
+ if ('rejected' === hydrationRecord.status) throw hydrationRecord.error;
121
+ return /*#__PURE__*/ jsx(RouterProvider, {
122
+ router: router
123
+ });
124
+ }
42
125
  function stripSyntheticNotFoundRoute(routes) {
43
126
  return routes.filter((route)=>!('*' === route.path && !route.id && !route.loader)).map((route)=>{
44
127
  if (!route.children?.length) return route;
@@ -60,9 +143,97 @@ const tanstackRouterPlugin = (userConfig = {})=>{
60
143
  onBeforeHydrateRouter: onBeforeHydrateRouter
61
144
  },
62
145
  setup: (api)=>{
63
- api.onBeforeRender((context)=>{
146
+ const hooks = api.getHooks();
147
+ let cachedRouteObjects;
148
+ let cachedRouteTree = null;
149
+ let cachedRouter = null;
150
+ let cachedRouterBasepath = null;
151
+ const getMergedConfig = ()=>{
64
152
  const pluginConfig = api.getRuntimeConfig();
65
- const mergedConfig = merge(pluginConfig.router || {}, userConfig);
153
+ return merge(pluginConfig.router || {}, userConfig);
154
+ };
155
+ const getRouteObjects = ()=>{
156
+ if (void 0 !== cachedRouteObjects) return cachedRouteObjects;
157
+ const mergedConfig = getMergedConfig();
158
+ const { routesConfig, createRoutes } = mergedConfig;
159
+ const finalRouteConfig = {
160
+ routes: getGlobalRoutes(),
161
+ globalApp: getGlobalLayoutApp(),
162
+ ...routesConfig
163
+ };
164
+ const routeObjects = createRoutes ? createRoutes() : createRouteObjectsFromConfig({
165
+ routesConfig: finalRouteConfig
166
+ }) || [];
167
+ const normalizedRouteObjects = createRoutes ? routeObjects : stripSyntheticNotFoundRoute(routeObjects);
168
+ cachedRouteObjects = hooks.modifyRoutes.call(normalizedRouteObjects);
169
+ return cachedRouteObjects;
170
+ };
171
+ const getRouteTree = ()=>{
172
+ if (cachedRouteTree) return cachedRouteTree;
173
+ const routeObjects = getRouteObjects();
174
+ if (!routeObjects.length) return null;
175
+ cachedRouteTree = createRouteTreeFromRouteObjects(routeObjects, {
176
+ rscPayloadRouter: getGlobalEnableRsc()
177
+ });
178
+ return cachedRouteTree;
179
+ };
180
+ const selectBasePath = (pathname)=>{
181
+ const { serverBase = [] } = getMergedConfig();
182
+ const match = serverBase.find((baseUrl)=>isSegmentPrefix(pathname, baseUrl));
183
+ return match || '/';
184
+ };
185
+ const getClientBasename = (runtimeContext)=>{
186
+ const { basename = '' } = getMergedConfig();
187
+ const baseUrl = selectBasePath(location.pathname).replace(/^\/*/, '/');
188
+ return '/' === baseUrl ? urlJoin(baseUrl, runtimeContext._internalRouterBaseName || basename || '') : baseUrl;
189
+ };
190
+ const getRouter = (runtimeContext, _basename)=>{
191
+ const routeTree = getRouteTree();
192
+ if (!routeTree) return null;
193
+ const lifecycleContext = {
194
+ framework: 'tanstack',
195
+ phase: 'client-create',
196
+ routes: getRouteObjects(),
197
+ runtimeContext,
198
+ basename: _basename
199
+ };
200
+ hooks.onBeforeCreateRouter.call(lifecycleContext);
201
+ if (cachedRouter && cachedRouterBasepath === _basename) {
202
+ wrapRouterSubscribeWithBlockState(cachedRouter, runtimeContext.unstable_getBlockNavState);
203
+ hooks.onAfterCreateRouter.call({
204
+ ...lifecycleContext,
205
+ router: cachedRouter,
206
+ runtimeContext
207
+ });
208
+ return cachedRouter;
209
+ }
210
+ const mergedConfig = getMergedConfig();
211
+ const { supportHtml5History = true } = mergedConfig;
212
+ const history = supportHtml5History ? createBrowserHistory() : createHashHistory();
213
+ const rewrite = createModernBasepathRewrite(_basename);
214
+ const serializationAdapters = getGlobalEnableRsc() ? getTanstackRscSerializationAdapters() : void 0;
215
+ cachedRouter = createRouter({
216
+ ...getModernTanstackRouterFastDefaults(mergedConfig),
217
+ routeTree,
218
+ basepath: '/',
219
+ rewrite,
220
+ history,
221
+ context: {},
222
+ ...serializationAdapters ? {
223
+ serializationAdapters
224
+ } : {}
225
+ });
226
+ cachedRouterBasepath = _basename;
227
+ wrapRouterSubscribeWithBlockState(cachedRouter, runtimeContext.unstable_getBlockNavState);
228
+ hooks.onAfterCreateRouter.call({
229
+ ...lifecycleContext,
230
+ router: cachedRouter,
231
+ runtimeContext
232
+ });
233
+ return cachedRouter;
234
+ };
235
+ api.onBeforeRender(async (context)=>{
236
+ const mergedConfig = getMergedConfig();
66
237
  if ("u" > typeof window && window._SSR_DATA && mergedConfig.unstable_reloadOnURLMismatch) {
67
238
  const { ssrContext } = context;
68
239
  const currentPathname = normalizePathname(window.location.pathname);
@@ -74,98 +245,32 @@ const tanstackRouterPlugin = (userConfig = {})=>{
74
245
  }
75
246
  }
76
247
  context.router = {
248
+ Link: Link,
77
249
  useMatches: useMatches,
78
250
  useLocation: useLocation,
79
251
  useNavigate: useNavigate,
80
252
  useRouter: useRouter
81
253
  };
254
+ const hasSSRBootstrap = "u" > typeof window && Boolean(window.$_TSR);
255
+ if (hasSSRBootstrap && getRouteObjects().length) {
256
+ const runtimeContext = context;
257
+ const router = getRouter(runtimeContext, getClientBasename(runtimeContext));
258
+ if (router) await getTanstackSsrHydrationPromise(router);
259
+ }
82
260
  });
83
261
  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;
262
+ if (!getRouteObjects().length) return App;
110
263
  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
- }, []);
264
+ const runtimeContext = useContext(InternalRuntimeContext);
265
+ const _basename = getClientBasename(runtimeContext);
266
+ const routeTree = useMemo(()=>getRouteTree(), []);
123
267
  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
- }, [
268
+ const router = useMemo(()=>getRouter(runtimeContext, _basename), [
164
269
  _basename,
165
270
  routeTree,
166
- supportHtml5History,
167
271
  runtimeContext
168
272
  ]);
273
+ if (!router) return App ? /*#__PURE__*/ jsx(App, {}) : null;
169
274
  const runtimeState = applyRouterRuntimeState(runtimeContext, {
170
275
  framework: 'tanstack',
171
276
  basename: _basename,
@@ -179,30 +284,29 @@ const tanstackRouterPlugin = (userConfig = {})=>{
179
284
  basename: _basename,
180
285
  router
181
286
  };
182
- const hasSSRBootstrap = "u" > typeof window && Boolean(window.$_TSR);
183
- if (hasSSRBootstrap) hooks.onBeforeHydrateRouter.call({
287
+ const hasSSRBootstrap = "u" > typeof window && (Boolean(window.$_TSR) || hasTanstackSsrHydrationRecord(router));
288
+ const needsRouterClient = hasSSRBootstrap;
289
+ if (needsRouterClient) hooks.onBeforeHydrateRouter.call({
184
290
  ...lifecycleContext,
185
291
  phase: 'hydrate',
186
292
  router,
187
293
  runtimeContext: runtimeState
188
294
  });
189
- const RouterContent = hasSSRBootstrap ? /*#__PURE__*/ jsx(__rspack_external_react.Suspense, {
190
- fallback: null,
191
- children: /*#__PURE__*/ jsx(RouterClient, {
192
- router: router
193
- })
295
+ const RouterContent = needsRouterClient ? /*#__PURE__*/ jsx(ModernRouterClient, {
296
+ router: router
194
297
  }) : /*#__PURE__*/ jsx(RouterProvider, {
195
298
  router: router
196
299
  });
197
- if (hasSSRBootstrap) hooks.onAfterHydrateRouter.call({
300
+ const HydratableRouterContent = wrapTanstackSsrHydrationBoundary(RouterContent, hasSSRBootstrap);
301
+ if (needsRouterClient) hooks.onAfterHydrateRouter.call({
198
302
  ...lifecycleContext,
199
303
  phase: 'hydrate',
200
304
  router,
201
305
  runtimeContext: runtimeState
202
306
  });
203
307
  return App ? /*#__PURE__*/ jsx(App, {
204
- children: RouterContent
205
- }) : RouterContent;
308
+ children: HydratableRouterContent
309
+ }) : HydratableRouterContent;
206
310
  };
207
311
  return RouterWrapper;
208
312
  });
@@ -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 Boolean(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";
@@ -1,6 +1,8 @@
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
  import { isTanstackRscPayloadNavigationEnabled, loadTanstackRscRouteData } from "./rsc/payloadRouter.mjs";
5
7
  function createTanstackRoute(options) {
6
8
  return createRoute(options);
@@ -8,6 +10,10 @@ function createTanstackRoute(options) {
8
10
  function createTanstackRootRoute(options) {
9
11
  return createRootRoute(options);
10
12
  }
13
+ function wrapRouteComponentWithModernContext(route, component, routeId) {
14
+ const routeMatchId = routeId || route.id;
15
+ if (component && routeMatchId) route.options.component = withModernRouteMatchContext(component, routeMatchId);
16
+ }
11
17
  function toTanstackPath(pathname) {
12
18
  return pathname.split('/').map((segment)=>{
13
19
  if (!segment) return segment;
@@ -55,6 +61,40 @@ function normalizeModernLoaderResponse(result) {
55
61
  }
56
62
  return normalizeModernLoaderResult(result);
57
63
  }
64
+ function pickRouteModuleComponent(routeModule, seen = new Set()) {
65
+ if ('function' == typeof routeModule || routeModule && 'object' == typeof routeModule && '$$typeof' in routeModule) return routeModule;
66
+ if (!routeModule || 'object' != typeof routeModule) return;
67
+ if (seen.has(routeModule)) return;
68
+ seen.add(routeModule);
69
+ const module = routeModule;
70
+ for (const candidate of [
71
+ module.default,
72
+ module.Component
73
+ ]){
74
+ const component = pickRouteModuleComponent(candidate, seen);
75
+ if (component) return component;
76
+ }
77
+ }
78
+ function createServerLazyImportComponent(lazyImport, fallbackComponent) {
79
+ if ("u" > typeof document) return fallbackComponent;
80
+ let resolvedComponent;
81
+ let pendingLoad;
82
+ const load = async ()=>{
83
+ if (resolvedComponent) return resolvedComponent;
84
+ const routeModule = await lazyImport();
85
+ const component = pickRouteModuleComponent(routeModule);
86
+ if (component) resolvedComponent = component;
87
+ return resolvedComponent;
88
+ };
89
+ const Component = (props)=>{
90
+ if (resolvedComponent) return createElement(resolvedComponent, props);
91
+ pendingLoad ||= load();
92
+ throw pendingLoad;
93
+ };
94
+ Component.load = load;
95
+ Component.preload = load;
96
+ return Component;
97
+ }
58
98
  function isAbsoluteUrl(value) {
59
99
  try {
60
100
  new URL(value);
@@ -127,7 +167,7 @@ function wrapModernLoader(modernRoute, modernLoader, revalidationState, options
127
167
  const signal = ctx?.abortController?.signal || ctx?.signal || new AbortController().signal;
128
168
  const baseRequest = ctx?.context?.request instanceof Request ? ctx.context.request : void 0;
129
169
  const href = 'string' == typeof ctx?.location ? ctx.location : ctx?.location?.publicHref || ctx?.location?.href || ctx?.location?.url?.href || '';
130
- const request = baseRequest ? new Request(baseRequest, {
170
+ const request = void 0 !== baseRequest ? new Request(baseRequest, {
131
171
  signal
132
172
  }) : createModernRequest(href, signal);
133
173
  const params = mapParamsForModernLoader({
@@ -192,7 +232,7 @@ function wrapRouteObjectLoader(route, revalidationState, options = {}) {
192
232
  const signal = ctx?.abortController?.signal || ctx?.signal || new AbortController().signal;
193
233
  const baseRequest = ctx?.context?.request instanceof Request ? ctx.context.request : void 0;
194
234
  const href = 'string' == typeof ctx?.location ? ctx.location : ctx?.location?.publicHref || ctx?.location?.href || ctx?.location?.url?.href || '';
195
- const request = baseRequest ? new Request(baseRequest, {
235
+ const request = void 0 !== baseRequest ? new Request(baseRequest, {
196
236
  signal
197
237
  }) : createModernRequest(href, signal);
198
238
  const params = mapParamsForRouteObjectLoader({
@@ -229,10 +269,18 @@ function wrapRouteObjectLoader(route, revalidationState, options = {}) {
229
269
  }
230
270
  function toRouteComponent(routeObject) {
231
271
  const route = routeObject;
272
+ const lazyImport = 'function' == typeof route.lazyImport ? route.lazyImport : void 0;
273
+ const fallbackComponent = route.Component ? route.Component : route.element ? ()=>route.element : void 0;
274
+ if (lazyImport && fallbackComponent) return createServerLazyImportComponent(lazyImport, fallbackComponent);
232
275
  if (route.Component) return route.Component;
233
276
  const element = route.element;
234
277
  if (element) return ()=>element;
235
278
  }
279
+ function toModernRouteComponent(route) {
280
+ const component = route.component || void 0;
281
+ if ('function' == typeof route.lazyImport && component) return createServerLazyImportComponent(route.lazyImport, component);
282
+ return component;
283
+ }
236
284
  function toErrorComponent(routeObject) {
237
285
  const route = routeObject;
238
286
  if (route.ErrorBoundary) return route.ErrorBoundary;
@@ -270,12 +318,14 @@ function createRouteFromRouteObject(opts) {
270
318
  const shouldRevalidate = modernRouteObject.shouldRevalidate;
271
319
  const shouldReload = createModernShouldReload(shouldRevalidate, revalidationState);
272
320
  const stableFallbackId = routeObject.id || modernRouteObject.file || routeObject.path || 'pathless';
321
+ const component = toRouteComponent(routeObject);
273
322
  const base = {
274
323
  getParentRoute: ()=>parent,
275
- component: toRouteComponent(routeObject),
324
+ component,
276
325
  pendingComponent: toPendingComponent(routeObject),
277
326
  errorComponent: toErrorComponent(routeObject),
278
- wrapInSuspense: true,
327
+ validateSearch: modernRouteObject.validateSearch,
328
+ loaderDeps: modernRouteObject.loaderDeps,
279
329
  staticData: createRouteStaticData({
280
330
  modernRouteId: routeObject.id,
281
331
  modernRouteAction: modernRouteObject.action,
@@ -294,6 +344,7 @@ function createRouteFromRouteObject(opts) {
294
344
  if (isRouteObjectPathlessLayout(routeObject)) base.id = stableFallbackId;
295
345
  else base.path = routeObject.index ? '/' : toTanstackPath(routeObject.path || '');
296
346
  const route = createTanstackRoute(base);
347
+ wrapRouteComponentWithModernContext(route, component, routeObject.id);
297
348
  const children = routeObject.children;
298
349
  if (children && children.length > 0) {
299
350
  const childRoutes = children.map((child)=>createRouteFromRouteObject({
@@ -313,7 +364,7 @@ function createRouteFromModernRoute(opts) {
313
364
  const stableFallbackId = modernId || route._component || route.filename || route.data || ('function' == typeof route.loader ? route.id : void 0);
314
365
  const pendingComponent = route.loading || route.pendingComponent;
315
366
  const errorComponent = route.error || route.errorComponent;
316
- const component = route.component;
367
+ const component = toModernRouteComponent(route);
317
368
  const modernLoader = route.loader;
318
369
  const modernAction = route.action;
319
370
  const modernShouldRevalidate = route.shouldRevalidate;
@@ -325,7 +376,8 @@ function createRouteFromModernRoute(opts) {
325
376
  component: component || void 0,
326
377
  pendingComponent: pendingComponent || void 0,
327
378
  errorComponent: errorComponent || void 0,
328
- wrapInSuspense: true,
379
+ validateSearch: route.validateSearch,
380
+ loaderDeps: route.loaderDeps,
329
381
  staticData: createRouteStaticData({
330
382
  modernRouteId: modernId,
331
383
  modernRouteAction: modernAction,
@@ -347,6 +399,7 @@ function createRouteFromModernRoute(opts) {
347
399
  base.path = isIndexRoute ? '/' : toTanstackPath(rawPath || '');
348
400
  }
349
401
  const tanstackRoute = createTanstackRoute(base);
402
+ wrapRouteComponentWithModernContext(tanstackRoute, component, modernId);
350
403
  const children = route.children;
351
404
  if (children && children.length > 0) {
352
405
  const childRoutes = children.map((child)=>createRouteFromModernRoute({
@@ -360,7 +413,7 @@ function createRouteFromModernRoute(opts) {
360
413
  }
361
414
  function createRouteTreeFromModernRoutes(routes, options = {}) {
362
415
  const rootModern = routes.find((r)=>r && 'nested' === r.type && r.isRoot);
363
- const rootComponent = rootModern?.component;
416
+ const rootComponent = rootModern ? toModernRouteComponent(rootModern) : void 0;
364
417
  const pendingComponent = rootModern?.loading;
365
418
  const errorComponent = rootModern?.error;
366
419
  const rootLoader = rootModern?.loader;
@@ -373,7 +426,8 @@ function createRouteTreeFromModernRoutes(routes, options = {}) {
373
426
  component: rootComponent || void 0,
374
427
  pendingComponent: pendingComponent || void 0,
375
428
  errorComponent: errorComponent || void 0,
376
- wrapInSuspense: true,
429
+ validateSearch: rootModern?.validateSearch,
430
+ loaderDeps: rootModern?.loaderDeps,
377
431
  notFoundComponent: DefaultNotFound,
378
432
  staticData: createRouteStaticData({
379
433
  modernRouteId: rootModernId,
@@ -391,6 +445,7 @@ function createRouteTreeFromModernRoutes(routes, options = {}) {
391
445
  if (rootShouldReload) rootRouteOptions.shouldReload = rootShouldReload;
392
446
  if (rootModern?.inValidSSRRoute) rootRouteOptions.ssr = false;
393
447
  const rootRoute = createTanstackRootRoute(rootRouteOptions);
448
+ if (rootComponent) rootRoute.options.component = withModernRouteMatchContext(rootComponent, rootRouteId);
394
449
  const topLevel = rootModern ? rootModern.children || [] : routes;
395
450
  const childRoutes = topLevel.map((child)=>createRouteFromModernRoute({
396
451
  options,
@@ -408,11 +463,13 @@ function createRouteTreeFromRouteObjects(routes, options = {}) {
408
463
  const rootRevalidationState = {};
409
464
  const rootShouldRevalidate = rootLikeRoute?.shouldRevalidate;
410
465
  const rootShouldReload = createModernShouldReload(rootShouldRevalidate, rootRevalidationState);
466
+ const rootComponent = rootLikeRoute ? toRouteComponent(rootLikeRoute) : void 0;
411
467
  const rootRouteOptions = {
412
- component: rootLikeRoute ? toRouteComponent(rootLikeRoute) : void 0,
468
+ component: rootComponent,
413
469
  pendingComponent: rootLikeRoute ? toPendingComponent(rootLikeRoute) : void 0,
414
470
  errorComponent: rootLikeRoute ? toErrorComponent(rootLikeRoute) : void 0,
415
- wrapInSuspense: true,
471
+ validateSearch: rootLikeRoute?.validateSearch,
472
+ loaderDeps: rootLikeRoute?.loaderDeps,
416
473
  notFoundComponent: DefaultNotFound,
417
474
  staticData: createRouteStaticData({
418
475
  modernRouteId: rootLikeRoute?.id,
@@ -430,6 +487,7 @@ function createRouteTreeFromRouteObjects(routes, options = {}) {
430
487
  if (rootShouldReload) rootRouteOptions.shouldReload = rootShouldReload;
431
488
  if (rootLikeRoute?.inValidSSRRoute) rootRouteOptions.ssr = false;
432
489
  const rootRoute = createTanstackRootRoute(rootRouteOptions);
490
+ if (rootComponent) rootRoute.options.component = withModernRouteMatchContext(rootComponent, rootRouteId);
433
491
  const topLevel = rootLikeRoute ? [
434
492
  ...rootLikeRoute.children || [],
435
493
  ...routes.filter((route)=>route !== rootLikeRoute)
@@ -444,9 +502,11 @@ function createRouteTreeFromRouteObjects(routes, options = {}) {
444
502
  }
445
503
  function getModernRouteIdsFromMatches(router) {
446
504
  const matches = router.state.matches || [];
505
+ const routesById = router.routesById;
447
506
  const ids = matches.map((match)=>{
448
- const route = match.route;
449
- return route?.options?.staticData?.modernRouteId;
507
+ const normalizedMatch = match;
508
+ const routeId = 'string' == typeof normalizedMatch.routeId ? normalizedMatch.routeId : void 0;
509
+ return normalizedMatch.route?.options?.staticData?.modernRouteId ?? (routeId ? routesById?.[routeId]?.options?.staticData?.modernRouteId : void 0);
450
510
  }).filter((id)=>'string' == typeof id);
451
511
  return Array.from(new Set(ids));
452
512
  }