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

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 (94) hide show
  1. package/dist/cjs/cli/index.js +47 -27
  2. package/dist/cjs/cli/routeSplitting.js +0 -32
  3. package/dist/cjs/cli/tanstackTypes.js +34 -199
  4. package/dist/cjs/runtime/hooks.js +11 -14
  5. package/dist/cjs/runtime/index.js +107 -319
  6. package/dist/cjs/runtime/lifecycle.js +12 -86
  7. package/dist/cjs/runtime/loaderBridge.js +173 -0
  8. package/dist/cjs/runtime/plugin.js +6 -30
  9. package/dist/cjs/runtime/plugin.node.js +7 -29
  10. package/dist/cjs/runtime/pluginCore.js +55 -0
  11. package/dist/cjs/runtime/register.js +56 -0
  12. package/dist/cjs/runtime/routeTree.js +10 -207
  13. package/dist/cjs/runtime/{DefaultNotFound.js → router.js} +5 -15
  14. package/dist/cjs/runtime/rsc/payloadRouter.js +35 -1
  15. package/dist/cjs/runtime/state.js +45 -0
  16. package/dist/cjs/runtime/utils.js +0 -5
  17. package/dist/esm/cli/index.mjs +52 -26
  18. package/dist/esm/cli/routeSplitting.mjs +1 -30
  19. package/dist/esm/cli/tanstackTypes.mjs +32 -194
  20. package/dist/esm/runtime/hooks.mjs +1 -8
  21. package/dist/esm/runtime/index.mjs +4 -2
  22. package/dist/esm/runtime/lifecycle.mjs +1 -82
  23. package/dist/esm/runtime/loaderBridge.mjs +114 -0
  24. package/dist/esm/runtime/plugin.mjs +8 -32
  25. package/dist/esm/runtime/plugin.node.mjs +10 -32
  26. package/dist/esm/runtime/pluginCore.mjs +14 -0
  27. package/dist/esm/runtime/register.mjs +18 -0
  28. package/dist/esm/runtime/routeTree.mjs +4 -198
  29. package/dist/esm/runtime/router.mjs +2 -0
  30. package/dist/esm/runtime/rsc/payloadRouter.mjs +35 -1
  31. package/dist/esm/runtime/state.mjs +7 -0
  32. package/dist/esm/runtime/utils.mjs +0 -5
  33. package/dist/esm-node/cli/index.mjs +52 -26
  34. package/dist/esm-node/cli/routeSplitting.mjs +1 -30
  35. package/dist/esm-node/cli/tanstackTypes.mjs +32 -194
  36. package/dist/esm-node/runtime/hooks.mjs +1 -8
  37. package/dist/esm-node/runtime/index.mjs +4 -2
  38. package/dist/esm-node/runtime/lifecycle.mjs +1 -82
  39. package/dist/esm-node/runtime/loaderBridge.mjs +115 -0
  40. package/dist/esm-node/runtime/plugin.mjs +8 -32
  41. package/dist/esm-node/runtime/plugin.node.mjs +10 -32
  42. package/dist/esm-node/runtime/pluginCore.mjs +15 -0
  43. package/dist/esm-node/runtime/register.mjs +19 -0
  44. package/dist/esm-node/runtime/routeTree.mjs +4 -198
  45. package/dist/esm-node/runtime/router.mjs +3 -0
  46. package/dist/esm-node/runtime/rsc/payloadRouter.mjs +35 -1
  47. package/dist/esm-node/runtime/state.mjs +8 -0
  48. package/dist/esm-node/runtime/utils.mjs +0 -5
  49. package/dist/types/cli/index.d.ts +9 -2
  50. package/dist/types/cli/routeSplitting.d.ts +6 -15
  51. package/dist/types/cli/tanstackTypes.d.ts +13 -2
  52. package/dist/types/runtime/hooks.d.ts +8 -18
  53. package/dist/types/runtime/index.d.ts +6 -4
  54. package/dist/types/runtime/lifecycle.d.ts +7 -22
  55. package/dist/types/runtime/loaderBridge.d.ts +48 -0
  56. package/dist/types/runtime/plugin.d.ts +1 -14
  57. package/dist/types/runtime/plugin.node.d.ts +1 -14
  58. package/dist/types/runtime/pluginCore.d.ts +21 -0
  59. package/dist/types/runtime/register.d.ts +9 -0
  60. package/dist/types/runtime/routeTree.d.ts +0 -2
  61. package/dist/types/runtime/router.d.ts +14 -0
  62. package/dist/types/runtime/state.d.ts +16 -0
  63. package/dist/types/runtime/types.d.ts +7 -53
  64. package/package.json +30 -28
  65. package/rstest.config.mts +6 -0
  66. package/src/cli/index.ts +111 -29
  67. package/src/cli/routeSplitting.ts +6 -44
  68. package/src/cli/tanstackTypes.ts +78 -214
  69. package/src/runtime/hooks.ts +10 -27
  70. package/src/runtime/index.tsx +12 -107
  71. package/src/runtime/lifecycle.ts +16 -151
  72. package/src/runtime/loaderBridge.ts +257 -0
  73. package/src/runtime/plugin.node.tsx +14 -77
  74. package/src/runtime/plugin.tsx +12 -72
  75. package/src/runtime/pluginCore.ts +48 -0
  76. package/src/runtime/register.ts +58 -0
  77. package/src/runtime/routeTree.ts +8 -370
  78. package/src/runtime/router.ts +15 -0
  79. package/src/runtime/rsc/payloadRouter.ts +45 -2
  80. package/src/runtime/state.ts +29 -0
  81. package/src/runtime/types.ts +20 -67
  82. package/src/runtime/utils.tsx +3 -6
  83. package/tests/router/cli.test.ts +297 -31
  84. package/tests/router/hooks.test.ts +26 -0
  85. package/tests/router/loaderBridge.test.ts +211 -0
  86. package/tests/router/packageSurface.test.ts +24 -0
  87. package/tests/router/register.test.ts +46 -0
  88. package/tests/router/routeTree.test.ts +65 -180
  89. package/tests/router/rsc.test.tsx +70 -0
  90. package/tests/router/tanstackTypes.test.ts +164 -6
  91. package/dist/esm/runtime/DefaultNotFound.mjs +0 -13
  92. package/dist/esm-node/runtime/DefaultNotFound.mjs +0 -14
  93. package/dist/types/runtime/DefaultNotFound.d.ts +0 -2
  94. package/src/runtime/DefaultNotFound.tsx +0 -15
@@ -1,16 +1,11 @@
1
1
  // @effect-diagnostics globalConsole:off strictBooleanExpressions:off
2
2
  /// <reference path="./ssr-shim.d.ts" />
3
3
 
4
- import type { Plugin, RuntimePluginExtends } from '@modern-js/plugin';
5
- import type { RuntimePluginAPI } from '@modern-js/plugin/runtime';
6
4
  import {
7
5
  getGlobalEnableRsc,
8
- getGlobalLayoutApp,
9
- getGlobalRoutes,
10
6
  InternalRuntimeContext,
11
7
  type TInternalRuntimeContext,
12
8
  } from '@modern-js/runtime/context';
13
- import { merge } from '@modern-js/runtime-utils/merge';
14
9
  import type { RouteObject } from '@modern-js/runtime-utils/router';
15
10
  import { normalizePathname } from '@modern-js/runtime-utils/url';
16
11
  import {
@@ -27,21 +22,19 @@ import {
27
22
  import { hydrate as hydrateTanstackRouter } from '@tanstack/react-router/ssr/client';
28
23
  import { useContext, useMemo } from 'react';
29
24
  import { createModernBasepathRewrite } from './basepathRewrite';
30
- import {
31
- modifyRoutes as modifyRoutesHook,
32
- onAfterCreateRouter as onAfterCreateRouterHook,
33
- onAfterHydrateRouter as onAfterHydrateRouterHook,
34
- onBeforeCreateRouter as onBeforeCreateRouterHook,
35
- onBeforeCreateRoutes as onBeforeCreateRoutesHook,
36
- onBeforeHydrateRouter as onBeforeHydrateRouterHook,
37
- type RouterExtendsHooks,
38
- } from './hooks';
25
+ import { routerProviderRegistryHooks } from './hooks';
39
26
  import { wrapTanstackSsrHydrationBoundary } from './hydrationBoundary';
40
27
  import {
41
28
  applyRouterRuntimeState,
42
29
  type RouterLifecycleContext,
43
30
  } from './lifecycle';
44
31
  import { withModernRouteMatchContext } from './outlet';
32
+ import {
33
+ getFinalRouteConfig,
34
+ getMergedRouterConfig,
35
+ type TanstackRouterPluginAPI,
36
+ type TanstackRouterRuntimePlugin,
37
+ } from './pluginCore';
45
38
  import { Link } from './prefetchLink';
46
39
  import { createRouteTreeFromRouteObjects } from './routeTree';
47
40
  import { getTanstackRscSerializationAdapters } from './rsc/client';
@@ -94,25 +87,6 @@ type RouterWithPreloadableRoutes = AnyRouter & {
94
87
  >;
95
88
  };
96
89
 
97
- type TanstackRouterRuntimeConfig = {
98
- plugins?: TanstackRouterRuntimePlugin[];
99
- router?: Partial<RouterConfig>;
100
- [key: string]: unknown;
101
- };
102
-
103
- type TanstackRouterRuntimeExtends = Required<
104
- RuntimePluginExtends<TanstackRouterRuntimeConfig, TInternalRuntimeContext>
105
- > & {
106
- extendHooks: RouterExtendsHooks;
107
- };
108
-
109
- type TanstackRouterPluginAPI = RuntimePluginAPI<TanstackRouterRuntimeExtends>;
110
-
111
- type TanstackRouterRuntimePlugin = Plugin<
112
- TanstackRouterPluginAPI,
113
- TInternalRuntimeContext
114
- >;
115
-
116
90
  function normalizeBase(b: string) {
117
91
  if (b.length > 1 && b.endsWith('/')) {
118
92
  return b.slice(0, -1);
@@ -302,33 +276,12 @@ function ModernRouterClient({ router }: { router: AnyRouter }) {
302
276
  return <RouterProvider router={router} />;
303
277
  }
304
278
 
305
- function stripSyntheticNotFoundRoute(routes: RouteObject[]): RouteObject[] {
306
- return routes
307
- .filter(route => !(route.path === '*' && !route.id && !route.loader))
308
- .map(route => {
309
- if (!route.children?.length) {
310
- return route;
311
- }
312
- return {
313
- ...route,
314
- children: stripSyntheticNotFoundRoute(route.children),
315
- };
316
- });
317
- }
318
-
319
279
  export const tanstackRouterPlugin = (
320
280
  userConfig: Partial<RouterConfig> = {},
321
281
  ): TanstackRouterRuntimePlugin => {
322
282
  const plugin: TanstackRouterRuntimePlugin = {
323
283
  name: '@modern-js/plugin-router-tanstack',
324
- registryHooks: {
325
- modifyRoutes: modifyRoutesHook,
326
- onAfterCreateRouter: onAfterCreateRouterHook,
327
- onAfterHydrateRouter: onAfterHydrateRouterHook,
328
- onBeforeCreateRouter: onBeforeCreateRouterHook,
329
- onBeforeCreateRoutes: onBeforeCreateRoutesHook,
330
- onBeforeHydrateRouter: onBeforeHydrateRouterHook,
331
- },
284
+ registryHooks: routerProviderRegistryHooks,
332
285
  setup: (api: TanstackRouterPluginAPI) => {
333
286
  const hooks = api.getHooks();
334
287
  let cachedRouteObjects: RouteObject[] | undefined;
@@ -338,12 +291,7 @@ export const tanstackRouterPlugin = (
338
291
  let cachedRouter: AnyRouter | null = null;
339
292
  let cachedRouterBasepath: string | null = null;
340
293
 
341
- const getMergedConfig = () => {
342
- const pluginConfig = api.getRuntimeConfig() as {
343
- router?: Partial<RouterConfig>;
344
- };
345
- return merge(pluginConfig.router || {}, userConfig) as RouterConfig;
346
- };
294
+ const getMergedConfig = () => getMergedRouterConfig(api, userConfig);
347
295
 
348
296
  const getRouteObjects = () => {
349
297
  if (typeof cachedRouteObjects !== 'undefined') {
@@ -351,12 +299,8 @@ export const tanstackRouterPlugin = (
351
299
  }
352
300
 
353
301
  const mergedConfig = getMergedConfig();
354
- const { routesConfig, createRoutes } = mergedConfig;
355
- const finalRouteConfig = {
356
- routes: getGlobalRoutes(),
357
- globalApp: getGlobalLayoutApp(),
358
- ...routesConfig,
359
- };
302
+ const { createRoutes } = mergedConfig;
303
+ const finalRouteConfig = getFinalRouteConfig(mergedConfig);
360
304
 
361
305
  const routeObjects = createRoutes
362
306
  ? createRoutes()
@@ -364,12 +308,8 @@ export const tanstackRouterPlugin = (
364
308
  routesConfig: finalRouteConfig,
365
309
  }) || [];
366
310
 
367
- const normalizedRouteObjects = createRoutes
368
- ? routeObjects
369
- : stripSyntheticNotFoundRoute(routeObjects);
370
-
371
311
  cachedRouteObjects = hooks.modifyRoutes.call(
372
- normalizedRouteObjects,
312
+ routeObjects,
373
313
  ) as RouteObject[];
374
314
  return cachedRouteObjects;
375
315
  };
@@ -0,0 +1,48 @@
1
+ import type { Plugin, RuntimePluginExtends } from '@modern-js/plugin';
2
+ import type { RuntimePluginAPI } from '@modern-js/plugin/runtime';
3
+ import {
4
+ getGlobalLayoutApp,
5
+ getGlobalRoutes,
6
+ type TInternalRuntimeContext,
7
+ } from '@modern-js/runtime/context';
8
+ import { merge } from '@modern-js/runtime-utils/merge';
9
+ import type { RouterExtendsHooks } from './hooks';
10
+ import type { RouterConfig } from './types';
11
+
12
+ export type TanstackRouterRuntimeConfig = {
13
+ plugins?: TanstackRouterRuntimePlugin[];
14
+ router?: Partial<RouterConfig>;
15
+ [key: string]: unknown;
16
+ };
17
+
18
+ type TanstackRouterRuntimeExtends = Required<
19
+ RuntimePluginExtends<TanstackRouterRuntimeConfig, TInternalRuntimeContext>
20
+ > & {
21
+ extendHooks: RouterExtendsHooks;
22
+ };
23
+
24
+ export type TanstackRouterPluginAPI =
25
+ RuntimePluginAPI<TanstackRouterRuntimeExtends>;
26
+
27
+ export type TanstackRouterRuntimePlugin = Plugin<
28
+ TanstackRouterPluginAPI,
29
+ TInternalRuntimeContext
30
+ >;
31
+
32
+ export function getMergedRouterConfig(
33
+ api: TanstackRouterPluginAPI,
34
+ userConfig: Partial<RouterConfig>,
35
+ ): RouterConfig {
36
+ const pluginConfig = api.getRuntimeConfig() as {
37
+ router?: Partial<RouterConfig>;
38
+ };
39
+ return merge(pluginConfig.router || {}, userConfig) as RouterConfig;
40
+ }
41
+
42
+ export function getFinalRouteConfig(mergedConfig: RouterConfig) {
43
+ return {
44
+ routes: getGlobalRoutes(),
45
+ globalApp: getGlobalLayoutApp(),
46
+ ...mergedConfig.routesConfig,
47
+ };
48
+ }
@@ -0,0 +1,58 @@
1
+ /**
2
+ * Registers the TanStack router provider with the @modern-js/runtime router
3
+ * provider registry. Importing '@modern-js/plugin-tanstack/runtime' is enough
4
+ * to make `runtime.router.framework: 'tanstack'` resolvable by the built-in
5
+ * router runtime plugin.
6
+ *
7
+ * This module is intentionally side-effectful (see `sideEffects` in
8
+ * package.json).
9
+ */
10
+ import {
11
+ type RouterProviderFactory,
12
+ type RouterProviderPlugin,
13
+ registerRouterProvider,
14
+ } from '@modern-js/runtime/context';
15
+ import { Form, RouteActionResponseError, useFetcher } from './dataMutation';
16
+ import { Outlet } from './outlet';
17
+ import { tanstackRouterPlugin } from './plugin';
18
+ import { Link, NavLink } from './prefetchLink';
19
+
20
+ // The TanStack runtime plugin types its API against its own hook registry,
21
+ // while the provider contract is typed against the built-in router hook
22
+ // registry of @modern-js/runtime. The two are runtime-compatible (the
23
+ // built-in router plugin registers the hooks and forwards its API to the
24
+ // resolved provider), but nominally distinct — hence the explicit adapter
25
+ // cast at this single boundary.
26
+ const tanstackRouterProviderFactory: RouterProviderFactory = userConfig =>
27
+ tanstackRouterPlugin(userConfig) as unknown as RouterProviderPlugin;
28
+
29
+ registerRouterProvider('tanstack', tanstackRouterProviderFactory);
30
+
31
+ /**
32
+ * Compatibility bindings for the deprecated `@modern-js/runtime/tanstack-router`
33
+ * alias. `@modern-js/runtime` cannot depend on this package (the dependency
34
+ * direction is plugin-tanstack -> runtime), so the alias resolves the
35
+ * Modern.js specific bindings through this `Symbol.for` slot at use time.
36
+ *
37
+ * `??=` keeps the first copy: when Module Federation evaluates a second
38
+ * bundled copy of this module, both copies are functionally identical and the
39
+ * established registration wins (mirroring the router-provider registry).
40
+ */
41
+ const COMPAT_BINDINGS_SLOT: unique symbol = Symbol.for(
42
+ '@modern-js/plugin-tanstack:runtime-compat-bindings',
43
+ );
44
+
45
+ export const tanstackRouterCompatBindings = {
46
+ Form,
47
+ Link,
48
+ NavLink,
49
+ Outlet,
50
+ RouteActionResponseError,
51
+ useFetcher,
52
+ };
53
+
54
+ (
55
+ globalThis as {
56
+ [COMPAT_BINDINGS_SLOT]?: typeof tanstackRouterCompatBindings;
57
+ }
58
+ )[COMPAT_BINDINGS_SLOT] ??= tanstackRouterCompatBindings;
@@ -1,6 +1,7 @@
1
1
  // @effect-diagnostics asyncFunction:off strictBooleanExpressions:off
2
+
3
+ import { DefaultNotFound } from '@modern-js/runtime/context';
2
4
  import type { RouteObject } from '@modern-js/runtime-utils/router';
3
- import type { NestedRoute, PageRoute } from '@modern-js/types';
4
5
  import type {
5
6
  AnyRoute,
6
7
  AnyRouter,
@@ -10,11 +11,15 @@ import {
10
11
  createRootRoute,
11
12
  createRoute,
12
13
  notFound,
13
- redirect,
14
14
  rootRouteId,
15
15
  } from '@tanstack/react-router';
16
16
  import { createElement, type ElementType } from 'react';
17
- import { DefaultNotFound } from './DefaultNotFound';
17
+ import {
18
+ isRedirectResponse,
19
+ isResponse,
20
+ isTanstackRedirect,
21
+ throwTanstackRedirect,
22
+ } from './loaderBridge';
18
23
  import { withModernRouteMatchContext } from './outlet';
19
24
  import {
20
25
  isTanstackRscPayloadNavigationEnabled,
@@ -84,36 +89,6 @@ type ModernRouteObject = RouteObject & {
84
89
  validateSearch?: unknown;
85
90
  };
86
91
 
87
- type ModernGeneratedRoute = (NestedRoute | PageRoute) & {
88
- _component?: string;
89
- action?: unknown;
90
- children?: ModernGeneratedRoute[];
91
- component?: unknown;
92
- config?: { handle?: Record<string, unknown> } | unknown;
93
- clientData?: unknown;
94
- data?: string;
95
- error?: unknown;
96
- errorComponent?: unknown;
97
- filename?: string;
98
- handle?: Record<string, unknown>;
99
- hasAction?: boolean;
100
- hasClientLoader?: boolean;
101
- hasLoader?: boolean;
102
- inValidSSRRoute?: boolean;
103
- id?: string;
104
- index?: boolean;
105
- isClientComponent?: boolean;
106
- isRoot?: boolean;
107
- lazyImport?: () => unknown;
108
- loader?: ModernLoader;
109
- loaderDeps?: unknown;
110
- loading?: unknown;
111
- pendingComponent?: unknown;
112
- path?: string;
113
- shouldRevalidate?: ModernShouldRevalidate;
114
- validateSearch?: unknown;
115
- };
116
-
117
92
  type MutableTanstackRoute = AnyRoute & {
118
93
  addChildren: (children: AnyRoute[]) => void;
119
94
  id?: string;
@@ -197,28 +172,6 @@ function toTanstackPath(pathname: string): string {
197
172
  .join('/');
198
173
  }
199
174
 
200
- function isResponse(value: unknown): value is Response {
201
- const record = value as { headers?: unknown; status?: unknown } | null;
202
- return (
203
- record != null &&
204
- typeof record === 'object' &&
205
- typeof record.status === 'number' &&
206
- typeof record.headers === 'object'
207
- );
208
- }
209
-
210
- function isTanstackRedirect(value: unknown): boolean {
211
- return (
212
- isResponse(value) &&
213
- typeof (value as { options?: unknown }).options === 'object'
214
- );
215
- }
216
-
217
- const redirectStatusCodes = new Set([301, 302, 303, 307, 308]);
218
- function isRedirectResponse(res: Response) {
219
- return redirectStatusCodes.has(res.status);
220
- }
221
-
222
175
  function isModernDeferredData(
223
176
  value: unknown,
224
177
  ): value is ModernDeferredDataLike & { data: Record<string, unknown> } {
@@ -323,46 +276,6 @@ function createServerLazyImportComponent(
323
276
  return Component;
324
277
  }
325
278
 
326
- function isAbsoluteUrl(value: string) {
327
- try {
328
- void new URL(value);
329
- return true;
330
- } catch {
331
- return false;
332
- }
333
- }
334
-
335
- function throwTanstackRedirect(location: string) {
336
- const target = location || '/';
337
- // Prefer `to` for internal/relative redirects so basepath can be applied.
338
- // Use `href` for absolute redirects (external).
339
- if (isAbsoluteUrl(target)) {
340
- throw redirect({ href: target });
341
- }
342
-
343
- throw redirect({ to: target });
344
- }
345
-
346
- function mapParamsForModernLoader({
347
- modernRoute,
348
- params,
349
- }: {
350
- modernRoute: NestedRoute | PageRoute;
351
- params: RouteParams;
352
- }) {
353
- // React Router uses `*` for splat params, TanStack Router uses `_splat`.
354
- if (modernRoute.type === 'nested' && modernRoute.path?.includes('*')) {
355
- const { _splat, ...rest } = params as RouteParams & {
356
- _splat?: string;
357
- };
358
- if (typeof _splat !== 'undefined') {
359
- return { ...rest, '*': _splat };
360
- }
361
- return rest;
362
- }
363
- return params;
364
- }
365
-
366
279
  function createModernRequest(input: string, signal: AbortSignal) {
367
280
  return new Request(input, { signal });
368
281
  }
@@ -420,92 +333,6 @@ function createModernShouldReload(
420
333
  };
421
334
  }
422
335
 
423
- function wrapModernLoader(
424
- modernRoute: NestedRoute | PageRoute,
425
- modernLoader: ModernLoader | undefined,
426
- revalidationState?: RouteRevalidationState,
427
- options: RouteTreeOptions = {},
428
- ) {
429
- const route = modernRoute as ModernGeneratedRoute;
430
- return async (ctx: TanstackLoaderContext) => {
431
- try {
432
- if (revalidationState) {
433
- rememberRouteLocation(revalidationState, ctx);
434
- }
435
-
436
- if (typeof route.lazyImport === 'function') {
437
- try {
438
- await route.lazyImport();
439
- } catch {}
440
- }
441
-
442
- const signal: AbortSignal =
443
- ctx?.abortController?.signal ||
444
- ctx?.signal ||
445
- new AbortController().signal;
446
- const baseRequest: Request | undefined =
447
- ctx?.context?.request instanceof Request
448
- ? ctx.context.request
449
- : undefined;
450
-
451
- const href =
452
- typeof ctx?.location === 'string'
453
- ? ctx.location
454
- : ctx?.location?.publicHref ||
455
- ctx?.location?.href ||
456
- ctx?.location?.url?.href ||
457
- '';
458
-
459
- const request =
460
- baseRequest !== undefined
461
- ? new Request(baseRequest, { signal })
462
- : createModernRequest(href, signal);
463
- const params = mapParamsForModernLoader({
464
- modernRoute,
465
- params: ctx.params || {},
466
- });
467
-
468
- const loadModernData = async () => {
469
- const result = modernLoader
470
- ? await modernLoader({
471
- request,
472
- params,
473
- context: ctx?.context?.requestContext,
474
- })
475
- : null;
476
-
477
- return normalizeModernLoaderResponse(result);
478
- };
479
-
480
- if (options.rscPayloadRouter && isTanstackRscPayloadNavigationEnabled()) {
481
- return loadTanstackRscRouteData({
482
- hasClientLoader:
483
- route.hasClientLoader || typeof route.clientData !== 'undefined',
484
- loadClientData: loadModernData,
485
- request,
486
- routeId: ctx.route?.id,
487
- });
488
- }
489
-
490
- return loadModernData();
491
- } catch (err) {
492
- if (isResponse(err)) {
493
- if (isTanstackRedirect(err)) {
494
- throw err;
495
- }
496
- if (isRedirectResponse(err)) {
497
- const location = err.headers.get('Location') || '/';
498
- throwTanstackRedirect(location);
499
- }
500
- if (err.status === 404) {
501
- throw notFound();
502
- }
503
- }
504
- throw err;
505
- }
506
- };
507
- }
508
-
509
336
  function isRouteObjectPathlessLayout(route: RouteObject) {
510
337
  return !route.path && !route.index;
511
338
  }
@@ -647,15 +474,6 @@ function toRouteComponent(routeObject: RouteObject): unknown {
647
474
  return undefined;
648
475
  }
649
476
 
650
- function toModernRouteComponent(route: ModernGeneratedRoute): unknown {
651
- const component = route.component || undefined;
652
- if (typeof route.lazyImport === 'function' && component) {
653
- return createServerLazyImportComponent(route.lazyImport, component);
654
- }
655
-
656
- return component;
657
- }
658
-
659
477
  function toErrorComponent(routeObject: RouteObject): unknown {
660
478
  const route = routeObject as ModernRouteObject;
661
479
  if (route.ErrorBoundary) {
@@ -813,186 +631,6 @@ function createRouteFromRouteObject(opts: {
813
631
  return route;
814
632
  }
815
633
 
816
- function createRouteFromModernRoute(opts: {
817
- options?: RouteTreeOptions;
818
- parent: AnyRoute;
819
- modernRoute: NestedRoute | PageRoute;
820
- }): AnyRoute {
821
- const { options = {}, parent, modernRoute } = opts;
822
- const route = modernRoute as ModernGeneratedRoute;
823
- const revalidationState: RouteRevalidationState = {};
824
-
825
- const modernId = route.id;
826
- const stableFallbackId =
827
- modernId ||
828
- route._component ||
829
- route.filename ||
830
- route.data ||
831
- (typeof route.loader === 'function' ? route.id : undefined);
832
-
833
- const pendingComponent = route.loading || route.pendingComponent;
834
- const errorComponent = route.error || route.errorComponent;
835
- const component = toModernRouteComponent(route);
836
- const modernLoader = route.loader;
837
- const modernAction = route.action;
838
- const modernShouldRevalidate = route.shouldRevalidate;
839
- const shouldReload = createModernShouldReload(
840
- modernShouldRevalidate,
841
- revalidationState,
842
- );
843
-
844
- // Pathless layout: no path segment, but must remain in the tree.
845
- const isPathlessLayout =
846
- route.type === 'nested' &&
847
- typeof route.index !== 'boolean' &&
848
- typeof route.path === 'undefined';
849
-
850
- const isIndexRoute = route.type === 'nested' && Boolean(route.index);
851
-
852
- const base: TanstackRouteOptions = {
853
- getParentRoute: () => parent,
854
- component: component || undefined,
855
- pendingComponent: pendingComponent || undefined,
856
- errorComponent: errorComponent || undefined,
857
- validateSearch: route.validateSearch,
858
- loaderDeps: route.loaderDeps,
859
- staticData: createRouteStaticData({
860
- modernRouteId: modernId,
861
- modernRouteAction: modernAction,
862
- modernRouteHandle: mergeModernRouteHandle(route),
863
- modernRouteHasAction: route.hasAction || Boolean(modernAction),
864
- modernRouteHasClientLoader:
865
- route.hasClientLoader || typeof route.clientData !== 'undefined',
866
- modernRouteHasLoader:
867
- route.hasLoader || typeof modernLoader === 'function',
868
- modernRouteIsClientComponent: route.isClientComponent,
869
- modernRouteLoader: modernLoader,
870
- modernRouteShouldRevalidate: modernShouldRevalidate,
871
- }),
872
- loader: wrapModernLoader(
873
- modernRoute,
874
- modernLoader,
875
- revalidationState,
876
- options,
877
- ),
878
- };
879
- if (route.inValidSSRRoute) {
880
- base.ssr = false;
881
- }
882
- if (shouldReload) {
883
- base.shouldReload = shouldReload;
884
- }
885
-
886
- if (isPathlessLayout) {
887
- // Use a stable custom id for pathless layouts to avoid hydration mismatch.
888
- base.id = stableFallbackId || 'pathless';
889
- } else {
890
- const rawPath = route.path;
891
- base.path = isIndexRoute ? '/' : toTanstackPath(rawPath || '');
892
- }
893
-
894
- const tanstackRoute = createTanstackRoute(base);
895
- wrapRouteComponentWithModernContext(tanstackRoute, component, modernId);
896
-
897
- const children = route.children as Array<NestedRoute | PageRoute> | undefined;
898
- if (children && children.length > 0) {
899
- const childRoutes = children.map(child =>
900
- createRouteFromModernRoute({
901
- options,
902
- parent: tanstackRoute,
903
- modernRoute: child,
904
- }),
905
- );
906
- tanstackRoute.addChildren(childRoutes);
907
- }
908
-
909
- return tanstackRoute;
910
- }
911
-
912
- export function createRouteTreeFromModernRoutes(
913
- routes: Array<NestedRoute | PageRoute>,
914
- options: RouteTreeOptions = {},
915
- ): ModernTanstackRootRoute {
916
- const rootModern = routes.find(
917
- r =>
918
- r &&
919
- (r as ModernGeneratedRoute).type === 'nested' &&
920
- (r as ModernGeneratedRoute).isRoot,
921
- ) as ModernGeneratedRoute | undefined;
922
-
923
- const rootComponent = rootModern
924
- ? toModernRouteComponent(rootModern)
925
- : undefined;
926
- const pendingComponent = rootModern?.loading;
927
- const errorComponent = rootModern?.error;
928
- const rootLoader = rootModern?.loader;
929
- const rootAction = rootModern?.action;
930
- const rootModernId = rootModern?.id;
931
- const rootShouldRevalidate = rootModern?.shouldRevalidate;
932
- const rootRevalidationState: RouteRevalidationState = {};
933
- const rootShouldReload = createModernShouldReload(
934
- rootShouldRevalidate,
935
- rootRevalidationState,
936
- );
937
-
938
- const rootRouteOptions: TanstackRootRouteOptions = {
939
- component: rootComponent || undefined,
940
- pendingComponent: pendingComponent || undefined,
941
- errorComponent: errorComponent || undefined,
942
- validateSearch: rootModern?.validateSearch,
943
- loaderDeps: rootModern?.loaderDeps,
944
- notFoundComponent: DefaultNotFound,
945
- staticData: createRouteStaticData({
946
- modernRouteId: rootModernId,
947
- modernRouteAction: rootAction,
948
- modernRouteHandle: rootModern
949
- ? mergeModernRouteHandle(rootModern)
950
- : undefined,
951
- modernRouteHasAction: rootModern?.hasAction || Boolean(rootAction),
952
- modernRouteHasClientLoader:
953
- rootModern?.hasClientLoader ||
954
- typeof rootModern?.clientData !== 'undefined',
955
- modernRouteHasLoader:
956
- rootModern?.hasLoader || typeof rootLoader === 'function',
957
- modernRouteIsClientComponent: rootModern?.isClientComponent,
958
- modernRouteLoader: rootLoader,
959
- modernRouteShouldRevalidate: rootShouldRevalidate,
960
- }),
961
- loader: rootModern
962
- ? wrapModernLoader(rootModern, rootLoader, rootRevalidationState, options)
963
- : undefined,
964
- };
965
- if (rootShouldReload) {
966
- rootRouteOptions.shouldReload = rootShouldReload;
967
- }
968
- if (rootModern?.inValidSSRRoute) {
969
- rootRouteOptions.ssr = false;
970
- }
971
-
972
- const rootRoute = createTanstackRootRoute(rootRouteOptions);
973
- if (rootComponent) {
974
- rootRoute.options.component = withModernRouteMatchContext(
975
- rootComponent,
976
- rootRouteId,
977
- ) as typeof rootRoute.options.component;
978
- }
979
-
980
- const topLevel = rootModern
981
- ? (rootModern.children as Array<NestedRoute | PageRoute>) || []
982
- : routes;
983
-
984
- const childRoutes = topLevel.map(child =>
985
- createRouteFromModernRoute({
986
- options,
987
- parent: rootRoute,
988
- modernRoute: child,
989
- }),
990
- );
991
-
992
- rootRoute.addChildren(childRoutes);
993
- return rootRoute as unknown as ModernTanstackRootRoute;
994
- }
995
-
996
634
  function getRootLikeRouteObject(routes: RouteObject[]) {
997
635
  return routes.find(route => route.path === '/' && !route.index);
998
636
  }
@@ -0,0 +1,15 @@
1
+ /**
2
+ * Entry-injected router module for entrypoints that are NOT TanStack
3
+ * file-route entrypoints (e.g. apps configuring
4
+ * `router: { framework: 'tanstack', createRoutes }` in modern.runtime.ts).
5
+ *
6
+ * The CLI plugin injects `{ name: 'router', path: '<pkg>/runtime/router' }`
7
+ * for those entries, so the generated entry code value-imports `routerPlugin`
8
+ * from here. That single import both installs the framework-resolving router
9
+ * plugin of @modern-js/runtime AND registers the TanStack router provider
10
+ * (the './register' side effect) — the registration can therefore never be
11
+ * tree-shaken away from the entry that needs it.
12
+ */
13
+ import './register';
14
+
15
+ export { routerPlugin } from '@modern-js/runtime/router/internal';