@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.
- package/dist/cjs/cli/index.js +47 -27
- package/dist/cjs/cli/routeSplitting.js +0 -32
- package/dist/cjs/cli/tanstackTypes.js +34 -199
- package/dist/cjs/runtime/hooks.js +11 -14
- package/dist/cjs/runtime/index.js +107 -319
- package/dist/cjs/runtime/lifecycle.js +12 -86
- package/dist/cjs/runtime/loaderBridge.js +173 -0
- package/dist/cjs/runtime/plugin.js +6 -30
- package/dist/cjs/runtime/plugin.node.js +7 -29
- package/dist/cjs/runtime/pluginCore.js +55 -0
- package/dist/cjs/runtime/register.js +56 -0
- package/dist/cjs/runtime/routeTree.js +10 -207
- package/dist/cjs/runtime/{DefaultNotFound.js → router.js} +5 -15
- package/dist/cjs/runtime/rsc/payloadRouter.js +35 -1
- package/dist/cjs/runtime/state.js +45 -0
- package/dist/cjs/runtime/utils.js +0 -5
- package/dist/esm/cli/index.mjs +52 -26
- package/dist/esm/cli/routeSplitting.mjs +1 -30
- package/dist/esm/cli/tanstackTypes.mjs +32 -194
- package/dist/esm/runtime/hooks.mjs +1 -8
- package/dist/esm/runtime/index.mjs +4 -2
- package/dist/esm/runtime/lifecycle.mjs +1 -82
- package/dist/esm/runtime/loaderBridge.mjs +114 -0
- package/dist/esm/runtime/plugin.mjs +8 -32
- package/dist/esm/runtime/plugin.node.mjs +10 -32
- package/dist/esm/runtime/pluginCore.mjs +14 -0
- package/dist/esm/runtime/register.mjs +18 -0
- package/dist/esm/runtime/routeTree.mjs +4 -198
- package/dist/esm/runtime/router.mjs +2 -0
- package/dist/esm/runtime/rsc/payloadRouter.mjs +35 -1
- package/dist/esm/runtime/state.mjs +7 -0
- package/dist/esm/runtime/utils.mjs +0 -5
- package/dist/esm-node/cli/index.mjs +52 -26
- package/dist/esm-node/cli/routeSplitting.mjs +1 -30
- package/dist/esm-node/cli/tanstackTypes.mjs +32 -194
- package/dist/esm-node/runtime/hooks.mjs +1 -8
- package/dist/esm-node/runtime/index.mjs +4 -2
- package/dist/esm-node/runtime/lifecycle.mjs +1 -82
- package/dist/esm-node/runtime/loaderBridge.mjs +115 -0
- package/dist/esm-node/runtime/plugin.mjs +8 -32
- package/dist/esm-node/runtime/plugin.node.mjs +10 -32
- package/dist/esm-node/runtime/pluginCore.mjs +15 -0
- package/dist/esm-node/runtime/register.mjs +19 -0
- package/dist/esm-node/runtime/routeTree.mjs +4 -198
- package/dist/esm-node/runtime/router.mjs +3 -0
- package/dist/esm-node/runtime/rsc/payloadRouter.mjs +35 -1
- package/dist/esm-node/runtime/state.mjs +8 -0
- package/dist/esm-node/runtime/utils.mjs +0 -5
- package/dist/types/cli/index.d.ts +9 -2
- package/dist/types/cli/routeSplitting.d.ts +6 -15
- package/dist/types/cli/tanstackTypes.d.ts +13 -2
- package/dist/types/runtime/hooks.d.ts +8 -18
- package/dist/types/runtime/index.d.ts +6 -4
- package/dist/types/runtime/lifecycle.d.ts +7 -22
- package/dist/types/runtime/loaderBridge.d.ts +48 -0
- package/dist/types/runtime/plugin.d.ts +1 -14
- package/dist/types/runtime/plugin.node.d.ts +1 -14
- package/dist/types/runtime/pluginCore.d.ts +21 -0
- package/dist/types/runtime/register.d.ts +9 -0
- package/dist/types/runtime/routeTree.d.ts +0 -2
- package/dist/types/runtime/router.d.ts +14 -0
- package/dist/types/runtime/state.d.ts +16 -0
- package/dist/types/runtime/types.d.ts +7 -53
- package/package.json +30 -28
- package/rstest.config.mts +6 -0
- package/src/cli/index.ts +111 -29
- package/src/cli/routeSplitting.ts +6 -44
- package/src/cli/tanstackTypes.ts +78 -214
- package/src/runtime/hooks.ts +10 -27
- package/src/runtime/index.tsx +12 -107
- package/src/runtime/lifecycle.ts +16 -151
- package/src/runtime/loaderBridge.ts +257 -0
- package/src/runtime/plugin.node.tsx +14 -77
- package/src/runtime/plugin.tsx +12 -72
- package/src/runtime/pluginCore.ts +48 -0
- package/src/runtime/register.ts +58 -0
- package/src/runtime/routeTree.ts +8 -370
- package/src/runtime/router.ts +15 -0
- package/src/runtime/rsc/payloadRouter.ts +45 -2
- package/src/runtime/state.ts +29 -0
- package/src/runtime/types.ts +20 -67
- package/src/runtime/utils.tsx +3 -6
- package/tests/router/cli.test.ts +297 -31
- package/tests/router/hooks.test.ts +26 -0
- package/tests/router/loaderBridge.test.ts +211 -0
- package/tests/router/packageSurface.test.ts +24 -0
- package/tests/router/register.test.ts +46 -0
- package/tests/router/routeTree.test.ts +65 -180
- package/tests/router/rsc.test.tsx +70 -0
- package/tests/router/tanstackTypes.test.ts +164 -6
- package/dist/esm/runtime/DefaultNotFound.mjs +0 -13
- package/dist/esm-node/runtime/DefaultNotFound.mjs +0 -14
- package/dist/types/runtime/DefaultNotFound.d.ts +0 -2
- package/src/runtime/DefaultNotFound.tsx +0 -15
package/src/runtime/plugin.tsx
CHANGED
|
@@ -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 {
|
|
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
|
-
|
|
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;
|
package/src/runtime/routeTree.ts
CHANGED
|
@@ -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 {
|
|
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';
|