@bleedingdev/modern-js-plugin-tanstack 3.2.0-ultramodern.98 → 3.4.0-ultramodern.0
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 +80 -34
- package/dist/cjs/cli/routeSplitting.js +13 -41
- package/dist/cjs/cli/tanstackTypes.js +114 -200
- package/dist/cjs/cli.js +12 -8
- package/dist/cjs/runtime/basepathRewrite.js +12 -8
- package/dist/cjs/runtime/dataMutation.js +9 -5
- package/dist/cjs/runtime/hooks.js +20 -19
- package/dist/cjs/runtime/hydrationBoundary.js +12 -7
- package/dist/cjs/runtime/index.js +66 -54
- package/dist/cjs/runtime/lifecycle.js +21 -91
- package/dist/cjs/runtime/loaderBridge.js +173 -0
- package/dist/cjs/runtime/outlet.js +58 -0
- package/dist/cjs/runtime/plugin.js +190 -110
- package/dist/cjs/runtime/plugin.node.js +25 -40
- package/dist/cjs/runtime/plugin.worker.js +9 -5
- package/dist/cjs/runtime/pluginCore.js +55 -0
- package/dist/cjs/runtime/prefetchLink.js +10 -6
- package/dist/cjs/runtime/register.js +56 -0
- package/dist/cjs/runtime/routeTree.js +30 -212
- package/dist/cjs/runtime/router.js +41 -0
- package/dist/cjs/runtime/rsc/ClientSlot.js +9 -5
- package/dist/cjs/runtime/rsc/CompositeComponent.js +9 -5
- package/dist/cjs/runtime/rsc/ReplayableStream.js +14 -9
- package/dist/cjs/runtime/rsc/RscNodeRenderer.js +9 -5
- package/dist/cjs/runtime/rsc/SlotContext.js +9 -5
- package/dist/cjs/runtime/rsc/client.js +9 -5
- package/dist/cjs/runtime/rsc/createRscProxy.js +9 -5
- package/dist/cjs/runtime/rsc/index.js +9 -5
- package/dist/cjs/runtime/rsc/payloadRouter.js +44 -6
- package/dist/cjs/runtime/rsc/server.js +9 -5
- package/dist/cjs/runtime/rsc/slotUsageSanitizer.js +9 -5
- package/dist/cjs/runtime/rsc/symbols.js +20 -15
- package/dist/cjs/runtime/state.js +45 -0
- package/dist/cjs/runtime/types.js +13 -9
- package/dist/cjs/runtime/utils.js +9 -11
- package/dist/cjs/runtime.js +9 -5
- package/dist/esm/cli/index.mjs +73 -28
- package/dist/esm/cli/routeSplitting.mjs +1 -30
- package/dist/esm/cli/tanstackTypes.mjs +100 -190
- package/dist/esm/runtime/hooks.mjs +1 -8
- package/dist/esm/runtime/hydrationBoundary.mjs +3 -2
- 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/outlet.mjs +17 -0
- package/dist/esm/runtime/plugin.mjs +183 -107
- package/dist/esm/runtime/plugin.node.mjs +19 -38
- package/dist/esm/runtime/pluginCore.mjs +14 -0
- package/dist/esm/runtime/prefetchLink.mjs +1 -1
- package/dist/esm/runtime/register.mjs +18 -0
- package/dist/esm/runtime/routeTree.mjs +15 -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 -6
- package/dist/esm-node/cli/index.mjs +73 -28
- package/dist/esm-node/cli/routeSplitting.mjs +1 -30
- package/dist/esm-node/cli/tanstackTypes.mjs +100 -190
- package/dist/esm-node/runtime/hooks.mjs +1 -8
- package/dist/esm-node/runtime/hydrationBoundary.mjs +3 -2
- 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/outlet.mjs +18 -0
- package/dist/esm-node/runtime/plugin.mjs +183 -107
- package/dist/esm-node/runtime/plugin.node.mjs +19 -38
- package/dist/esm-node/runtime/pluginCore.mjs +15 -0
- package/dist/esm-node/runtime/prefetchLink.mjs +1 -1
- package/dist/esm-node/runtime/register.mjs +19 -0
- package/dist/esm-node/runtime/routeTree.mjs +15 -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 -6
- package/dist/types/cli/index.d.ts +11 -2
- package/dist/types/cli/routeSplitting.d.ts +6 -15
- package/dist/types/cli/tanstackTypes.d.ts +21 -1
- package/dist/types/runtime/hooks.d.ts +8 -33
- package/dist/types/runtime/index.d.ts +6 -3
- package/dist/types/runtime/lifecycle.d.ts +7 -22
- package/dist/types/runtime/loaderBridge.d.ts +48 -0
- package/dist/types/runtime/outlet.d.ts +2 -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 +40 -38
- package/rstest.config.mts +6 -0
- package/src/cli/index.ts +146 -24
- package/src/cli/routeSplitting.ts +6 -44
- package/src/cli/tanstackTypes.ts +203 -208
- package/src/runtime/hooks.ts +10 -27
- package/src/runtime/hydrationBoundary.tsx +5 -5
- package/src/runtime/index.tsx +12 -14
- package/src/runtime/lifecycle.ts +16 -151
- package/src/runtime/loaderBridge.ts +257 -0
- package/src/runtime/outlet.tsx +48 -0
- package/src/runtime/plugin.node.tsx +28 -83
- package/src/runtime/plugin.tsx +350 -202
- package/src/runtime/pluginCore.ts +48 -0
- package/src/runtime/prefetchLink.tsx +1 -1
- package/src/runtime/register.ts +58 -0
- package/src/runtime/routeTree.ts +41 -365
- package/src/runtime/router.ts +15 -0
- package/src/runtime/rsc/payloadRouter.ts +45 -2
- package/src/runtime/ssr-shim.d.ts +1 -3
- package/src/runtime/state.ts +29 -0
- package/src/runtime/types.ts +20 -67
- package/src/runtime/utils.tsx +3 -7
- package/tests/router/cli.test.ts +373 -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/prefetchLink.test.tsx +43 -7
- package/tests/router/register.test.ts +46 -0
- package/tests/router/routeTree.test.ts +176 -139
- package/tests/router/rsc.test.tsx +70 -0
- package/tests/router/tanstackTypes.test.ts +395 -7
- package/dist/cjs/runtime/DefaultNotFound.js +0 -47
- 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
|
@@ -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,10 +11,16 @@ import {
|
|
|
10
11
|
createRootRoute,
|
|
11
12
|
createRoute,
|
|
12
13
|
notFound,
|
|
13
|
-
|
|
14
|
+
rootRouteId,
|
|
14
15
|
} from '@tanstack/react-router';
|
|
15
16
|
import { createElement, type ElementType } from 'react';
|
|
16
|
-
import {
|
|
17
|
+
import {
|
|
18
|
+
isRedirectResponse,
|
|
19
|
+
isResponse,
|
|
20
|
+
isTanstackRedirect,
|
|
21
|
+
throwTanstackRedirect,
|
|
22
|
+
} from './loaderBridge';
|
|
23
|
+
import { withModernRouteMatchContext } from './outlet';
|
|
17
24
|
import {
|
|
18
25
|
isTanstackRscPayloadNavigationEnabled,
|
|
19
26
|
loadTanstackRscRouteData,
|
|
@@ -82,38 +89,12 @@ type ModernRouteObject = RouteObject & {
|
|
|
82
89
|
validateSearch?: unknown;
|
|
83
90
|
};
|
|
84
91
|
|
|
85
|
-
type ModernGeneratedRoute = (NestedRoute | PageRoute) & {
|
|
86
|
-
_component?: string;
|
|
87
|
-
action?: unknown;
|
|
88
|
-
children?: ModernGeneratedRoute[];
|
|
89
|
-
component?: unknown;
|
|
90
|
-
config?: { handle?: Record<string, unknown> } | unknown;
|
|
91
|
-
clientData?: unknown;
|
|
92
|
-
data?: string;
|
|
93
|
-
error?: unknown;
|
|
94
|
-
errorComponent?: unknown;
|
|
95
|
-
filename?: string;
|
|
96
|
-
handle?: Record<string, unknown>;
|
|
97
|
-
hasAction?: boolean;
|
|
98
|
-
hasClientLoader?: boolean;
|
|
99
|
-
hasLoader?: boolean;
|
|
100
|
-
inValidSSRRoute?: boolean;
|
|
101
|
-
id?: string;
|
|
102
|
-
index?: boolean;
|
|
103
|
-
isClientComponent?: boolean;
|
|
104
|
-
isRoot?: boolean;
|
|
105
|
-
lazyImport?: () => unknown;
|
|
106
|
-
loader?: ModernLoader;
|
|
107
|
-
loaderDeps?: unknown;
|
|
108
|
-
loading?: unknown;
|
|
109
|
-
pendingComponent?: unknown;
|
|
110
|
-
path?: string;
|
|
111
|
-
shouldRevalidate?: ModernShouldRevalidate;
|
|
112
|
-
validateSearch?: unknown;
|
|
113
|
-
};
|
|
114
|
-
|
|
115
92
|
type MutableTanstackRoute = AnyRoute & {
|
|
116
93
|
addChildren: (children: AnyRoute[]) => void;
|
|
94
|
+
id?: string;
|
|
95
|
+
options: {
|
|
96
|
+
component?: unknown;
|
|
97
|
+
};
|
|
117
98
|
};
|
|
118
99
|
|
|
119
100
|
type TanstackRouteOptions = Record<string, unknown>;
|
|
@@ -148,6 +129,20 @@ function createTanstackRootRoute(
|
|
|
148
129
|
return createRootRoute(options as never) as unknown as MutableTanstackRoute;
|
|
149
130
|
}
|
|
150
131
|
|
|
132
|
+
function wrapRouteComponentWithModernContext(
|
|
133
|
+
route: MutableTanstackRoute,
|
|
134
|
+
component: unknown,
|
|
135
|
+
routeId?: string,
|
|
136
|
+
) {
|
|
137
|
+
const routeMatchId = routeId || route.id;
|
|
138
|
+
if (component && routeMatchId) {
|
|
139
|
+
route.options.component = withModernRouteMatchContext(
|
|
140
|
+
component,
|
|
141
|
+
routeMatchId,
|
|
142
|
+
) as typeof route.options.component;
|
|
143
|
+
}
|
|
144
|
+
}
|
|
145
|
+
|
|
151
146
|
function toTanstackPath(pathname: string): string {
|
|
152
147
|
// TanStack Router uses `$param` and `$` (splat) style params.
|
|
153
148
|
// Modern's conventional routing currently generates React Router style params (e.g. `:id`, `*`).
|
|
@@ -177,28 +172,6 @@ function toTanstackPath(pathname: string): string {
|
|
|
177
172
|
.join('/');
|
|
178
173
|
}
|
|
179
174
|
|
|
180
|
-
function isResponse(value: unknown): value is Response {
|
|
181
|
-
const record = value as { headers?: unknown; status?: unknown } | null;
|
|
182
|
-
return (
|
|
183
|
-
record != null &&
|
|
184
|
-
typeof record === 'object' &&
|
|
185
|
-
typeof record.status === 'number' &&
|
|
186
|
-
typeof record.headers === 'object'
|
|
187
|
-
);
|
|
188
|
-
}
|
|
189
|
-
|
|
190
|
-
function isTanstackRedirect(value: unknown): boolean {
|
|
191
|
-
return (
|
|
192
|
-
isResponse(value) &&
|
|
193
|
-
typeof (value as { options?: unknown }).options === 'object'
|
|
194
|
-
);
|
|
195
|
-
}
|
|
196
|
-
|
|
197
|
-
const redirectStatusCodes = new Set([301, 302, 303, 307, 308]);
|
|
198
|
-
function isRedirectResponse(res: Response) {
|
|
199
|
-
return redirectStatusCodes.has(res.status);
|
|
200
|
-
}
|
|
201
|
-
|
|
202
175
|
function isModernDeferredData(
|
|
203
176
|
value: unknown,
|
|
204
177
|
): value is ModernDeferredDataLike & { data: Record<string, unknown> } {
|
|
@@ -303,46 +276,6 @@ function createServerLazyImportComponent(
|
|
|
303
276
|
return Component;
|
|
304
277
|
}
|
|
305
278
|
|
|
306
|
-
function isAbsoluteUrl(value: string) {
|
|
307
|
-
try {
|
|
308
|
-
void new URL(value);
|
|
309
|
-
return true;
|
|
310
|
-
} catch {
|
|
311
|
-
return false;
|
|
312
|
-
}
|
|
313
|
-
}
|
|
314
|
-
|
|
315
|
-
function throwTanstackRedirect(location: string) {
|
|
316
|
-
const target = location || '/';
|
|
317
|
-
// Prefer `to` for internal/relative redirects so basepath can be applied.
|
|
318
|
-
// Use `href` for absolute redirects (external).
|
|
319
|
-
if (isAbsoluteUrl(target)) {
|
|
320
|
-
throw redirect({ href: target });
|
|
321
|
-
}
|
|
322
|
-
|
|
323
|
-
throw redirect({ to: target });
|
|
324
|
-
}
|
|
325
|
-
|
|
326
|
-
function mapParamsForModernLoader({
|
|
327
|
-
modernRoute,
|
|
328
|
-
params,
|
|
329
|
-
}: {
|
|
330
|
-
modernRoute: NestedRoute | PageRoute;
|
|
331
|
-
params: RouteParams;
|
|
332
|
-
}) {
|
|
333
|
-
// React Router uses `*` for splat params, TanStack Router uses `_splat`.
|
|
334
|
-
if (modernRoute.type === 'nested' && modernRoute.path?.includes('*')) {
|
|
335
|
-
const { _splat, ...rest } = params as RouteParams & {
|
|
336
|
-
_splat?: string;
|
|
337
|
-
};
|
|
338
|
-
if (typeof _splat !== 'undefined') {
|
|
339
|
-
return { ...rest, '*': _splat };
|
|
340
|
-
}
|
|
341
|
-
return rest;
|
|
342
|
-
}
|
|
343
|
-
return params;
|
|
344
|
-
}
|
|
345
|
-
|
|
346
279
|
function createModernRequest(input: string, signal: AbortSignal) {
|
|
347
280
|
return new Request(input, { signal });
|
|
348
281
|
}
|
|
@@ -400,92 +333,6 @@ function createModernShouldReload(
|
|
|
400
333
|
};
|
|
401
334
|
}
|
|
402
335
|
|
|
403
|
-
function wrapModernLoader(
|
|
404
|
-
modernRoute: NestedRoute | PageRoute,
|
|
405
|
-
modernLoader: ModernLoader | undefined,
|
|
406
|
-
revalidationState?: RouteRevalidationState,
|
|
407
|
-
options: RouteTreeOptions = {},
|
|
408
|
-
) {
|
|
409
|
-
const route = modernRoute as ModernGeneratedRoute;
|
|
410
|
-
return async (ctx: TanstackLoaderContext) => {
|
|
411
|
-
try {
|
|
412
|
-
if (revalidationState) {
|
|
413
|
-
rememberRouteLocation(revalidationState, ctx);
|
|
414
|
-
}
|
|
415
|
-
|
|
416
|
-
if (typeof route.lazyImport === 'function') {
|
|
417
|
-
try {
|
|
418
|
-
await route.lazyImport();
|
|
419
|
-
} catch {}
|
|
420
|
-
}
|
|
421
|
-
|
|
422
|
-
const signal: AbortSignal =
|
|
423
|
-
ctx?.abortController?.signal ||
|
|
424
|
-
ctx?.signal ||
|
|
425
|
-
new AbortController().signal;
|
|
426
|
-
const baseRequest: Request | undefined =
|
|
427
|
-
ctx?.context?.request instanceof Request
|
|
428
|
-
? ctx.context.request
|
|
429
|
-
: undefined;
|
|
430
|
-
|
|
431
|
-
const href =
|
|
432
|
-
typeof ctx?.location === 'string'
|
|
433
|
-
? ctx.location
|
|
434
|
-
: ctx?.location?.publicHref ||
|
|
435
|
-
ctx?.location?.href ||
|
|
436
|
-
ctx?.location?.url?.href ||
|
|
437
|
-
'';
|
|
438
|
-
|
|
439
|
-
const request =
|
|
440
|
-
baseRequest !== undefined
|
|
441
|
-
? new Request(baseRequest, { signal })
|
|
442
|
-
: createModernRequest(href, signal);
|
|
443
|
-
const params = mapParamsForModernLoader({
|
|
444
|
-
modernRoute,
|
|
445
|
-
params: ctx.params || {},
|
|
446
|
-
});
|
|
447
|
-
|
|
448
|
-
const loadModernData = async () => {
|
|
449
|
-
const result = modernLoader
|
|
450
|
-
? await modernLoader({
|
|
451
|
-
request,
|
|
452
|
-
params,
|
|
453
|
-
context: ctx?.context?.requestContext,
|
|
454
|
-
})
|
|
455
|
-
: null;
|
|
456
|
-
|
|
457
|
-
return normalizeModernLoaderResponse(result);
|
|
458
|
-
};
|
|
459
|
-
|
|
460
|
-
if (options.rscPayloadRouter && isTanstackRscPayloadNavigationEnabled()) {
|
|
461
|
-
return loadTanstackRscRouteData({
|
|
462
|
-
hasClientLoader:
|
|
463
|
-
route.hasClientLoader || typeof route.clientData !== 'undefined',
|
|
464
|
-
loadClientData: loadModernData,
|
|
465
|
-
request,
|
|
466
|
-
routeId: ctx.route?.id,
|
|
467
|
-
});
|
|
468
|
-
}
|
|
469
|
-
|
|
470
|
-
return loadModernData();
|
|
471
|
-
} catch (err) {
|
|
472
|
-
if (isResponse(err)) {
|
|
473
|
-
if (isTanstackRedirect(err)) {
|
|
474
|
-
throw err;
|
|
475
|
-
}
|
|
476
|
-
if (isRedirectResponse(err)) {
|
|
477
|
-
const location = err.headers.get('Location') || '/';
|
|
478
|
-
throwTanstackRedirect(location);
|
|
479
|
-
}
|
|
480
|
-
if (err.status === 404) {
|
|
481
|
-
throw notFound();
|
|
482
|
-
}
|
|
483
|
-
}
|
|
484
|
-
throw err;
|
|
485
|
-
}
|
|
486
|
-
};
|
|
487
|
-
}
|
|
488
|
-
|
|
489
336
|
function isRouteObjectPathlessLayout(route: RouteObject) {
|
|
490
337
|
return !route.path && !route.index;
|
|
491
338
|
}
|
|
@@ -627,15 +474,6 @@ function toRouteComponent(routeObject: RouteObject): unknown {
|
|
|
627
474
|
return undefined;
|
|
628
475
|
}
|
|
629
476
|
|
|
630
|
-
function toModernRouteComponent(route: ModernGeneratedRoute): unknown {
|
|
631
|
-
const component = route.component || undefined;
|
|
632
|
-
if (typeof route.lazyImport === 'function' && component) {
|
|
633
|
-
return createServerLazyImportComponent(route.lazyImport, component);
|
|
634
|
-
}
|
|
635
|
-
|
|
636
|
-
return component;
|
|
637
|
-
}
|
|
638
|
-
|
|
639
477
|
function toErrorComponent(routeObject: RouteObject): unknown {
|
|
640
478
|
const route = routeObject as ModernRouteObject;
|
|
641
479
|
if (route.ErrorBoundary) {
|
|
@@ -734,9 +572,10 @@ function createRouteFromRouteObject(opts: {
|
|
|
734
572
|
const stableFallbackId =
|
|
735
573
|
routeObject.id || modernRouteObject.file || routeObject.path || 'pathless';
|
|
736
574
|
|
|
575
|
+
const component = toRouteComponent(routeObject);
|
|
737
576
|
const base: TanstackRouteOptions = {
|
|
738
577
|
getParentRoute: () => parent,
|
|
739
|
-
component
|
|
578
|
+
component,
|
|
740
579
|
pendingComponent: toPendingComponent(routeObject),
|
|
741
580
|
errorComponent: toErrorComponent(routeObject),
|
|
742
581
|
validateSearch: modernRouteObject.validateSearch,
|
|
@@ -775,6 +614,7 @@ function createRouteFromRouteObject(opts: {
|
|
|
775
614
|
}
|
|
776
615
|
|
|
777
616
|
const route = createTanstackRoute(base);
|
|
617
|
+
wrapRouteComponentWithModernContext(route, component, routeObject.id);
|
|
778
618
|
|
|
779
619
|
const children = routeObject.children;
|
|
780
620
|
if (children && children.length > 0) {
|
|
@@ -791,179 +631,6 @@ function createRouteFromRouteObject(opts: {
|
|
|
791
631
|
return route;
|
|
792
632
|
}
|
|
793
633
|
|
|
794
|
-
function createRouteFromModernRoute(opts: {
|
|
795
|
-
options?: RouteTreeOptions;
|
|
796
|
-
parent: AnyRoute;
|
|
797
|
-
modernRoute: NestedRoute | PageRoute;
|
|
798
|
-
}): AnyRoute {
|
|
799
|
-
const { options = {}, parent, modernRoute } = opts;
|
|
800
|
-
const route = modernRoute as ModernGeneratedRoute;
|
|
801
|
-
const revalidationState: RouteRevalidationState = {};
|
|
802
|
-
|
|
803
|
-
const modernId = route.id;
|
|
804
|
-
const stableFallbackId =
|
|
805
|
-
modernId ||
|
|
806
|
-
route._component ||
|
|
807
|
-
route.filename ||
|
|
808
|
-
route.data ||
|
|
809
|
-
(typeof route.loader === 'function' ? route.id : undefined);
|
|
810
|
-
|
|
811
|
-
const pendingComponent = route.loading || route.pendingComponent;
|
|
812
|
-
const errorComponent = route.error || route.errorComponent;
|
|
813
|
-
const component = toModernRouteComponent(route);
|
|
814
|
-
const modernLoader = route.loader;
|
|
815
|
-
const modernAction = route.action;
|
|
816
|
-
const modernShouldRevalidate = route.shouldRevalidate;
|
|
817
|
-
const shouldReload = createModernShouldReload(
|
|
818
|
-
modernShouldRevalidate,
|
|
819
|
-
revalidationState,
|
|
820
|
-
);
|
|
821
|
-
|
|
822
|
-
// Pathless layout: no path segment, but must remain in the tree.
|
|
823
|
-
const isPathlessLayout =
|
|
824
|
-
route.type === 'nested' &&
|
|
825
|
-
typeof route.index !== 'boolean' &&
|
|
826
|
-
typeof route.path === 'undefined';
|
|
827
|
-
|
|
828
|
-
const isIndexRoute = route.type === 'nested' && Boolean(route.index);
|
|
829
|
-
|
|
830
|
-
const base: TanstackRouteOptions = {
|
|
831
|
-
getParentRoute: () => parent,
|
|
832
|
-
component: component || undefined,
|
|
833
|
-
pendingComponent: pendingComponent || undefined,
|
|
834
|
-
errorComponent: errorComponent || undefined,
|
|
835
|
-
validateSearch: route.validateSearch,
|
|
836
|
-
loaderDeps: route.loaderDeps,
|
|
837
|
-
staticData: createRouteStaticData({
|
|
838
|
-
modernRouteId: modernId,
|
|
839
|
-
modernRouteAction: modernAction,
|
|
840
|
-
modernRouteHandle: mergeModernRouteHandle(route),
|
|
841
|
-
modernRouteHasAction: route.hasAction || Boolean(modernAction),
|
|
842
|
-
modernRouteHasClientLoader:
|
|
843
|
-
route.hasClientLoader || typeof route.clientData !== 'undefined',
|
|
844
|
-
modernRouteHasLoader:
|
|
845
|
-
route.hasLoader || typeof modernLoader === 'function',
|
|
846
|
-
modernRouteIsClientComponent: route.isClientComponent,
|
|
847
|
-
modernRouteLoader: modernLoader,
|
|
848
|
-
modernRouteShouldRevalidate: modernShouldRevalidate,
|
|
849
|
-
}),
|
|
850
|
-
loader: wrapModernLoader(
|
|
851
|
-
modernRoute,
|
|
852
|
-
modernLoader,
|
|
853
|
-
revalidationState,
|
|
854
|
-
options,
|
|
855
|
-
),
|
|
856
|
-
};
|
|
857
|
-
if (route.inValidSSRRoute) {
|
|
858
|
-
base.ssr = false;
|
|
859
|
-
}
|
|
860
|
-
if (shouldReload) {
|
|
861
|
-
base.shouldReload = shouldReload;
|
|
862
|
-
}
|
|
863
|
-
|
|
864
|
-
if (isPathlessLayout) {
|
|
865
|
-
// Use a stable custom id for pathless layouts to avoid hydration mismatch.
|
|
866
|
-
base.id = stableFallbackId || 'pathless';
|
|
867
|
-
} else {
|
|
868
|
-
const rawPath = route.path;
|
|
869
|
-
base.path = isIndexRoute ? '/' : toTanstackPath(rawPath || '');
|
|
870
|
-
}
|
|
871
|
-
|
|
872
|
-
const tanstackRoute = createTanstackRoute(base);
|
|
873
|
-
|
|
874
|
-
const children = route.children as Array<NestedRoute | PageRoute> | undefined;
|
|
875
|
-
if (children && children.length > 0) {
|
|
876
|
-
const childRoutes = children.map(child =>
|
|
877
|
-
createRouteFromModernRoute({
|
|
878
|
-
options,
|
|
879
|
-
parent: tanstackRoute,
|
|
880
|
-
modernRoute: child,
|
|
881
|
-
}),
|
|
882
|
-
);
|
|
883
|
-
tanstackRoute.addChildren(childRoutes);
|
|
884
|
-
}
|
|
885
|
-
|
|
886
|
-
return tanstackRoute;
|
|
887
|
-
}
|
|
888
|
-
|
|
889
|
-
export function createRouteTreeFromModernRoutes(
|
|
890
|
-
routes: Array<NestedRoute | PageRoute>,
|
|
891
|
-
options: RouteTreeOptions = {},
|
|
892
|
-
): ModernTanstackRootRoute {
|
|
893
|
-
const rootModern = routes.find(
|
|
894
|
-
r =>
|
|
895
|
-
r &&
|
|
896
|
-
(r as ModernGeneratedRoute).type === 'nested' &&
|
|
897
|
-
(r as ModernGeneratedRoute).isRoot,
|
|
898
|
-
) as ModernGeneratedRoute | undefined;
|
|
899
|
-
|
|
900
|
-
const rootComponent = rootModern
|
|
901
|
-
? toModernRouteComponent(rootModern)
|
|
902
|
-
: undefined;
|
|
903
|
-
const pendingComponent = rootModern?.loading;
|
|
904
|
-
const errorComponent = rootModern?.error;
|
|
905
|
-
const rootLoader = rootModern?.loader;
|
|
906
|
-
const rootAction = rootModern?.action;
|
|
907
|
-
const rootModernId = rootModern?.id;
|
|
908
|
-
const rootShouldRevalidate = rootModern?.shouldRevalidate;
|
|
909
|
-
const rootRevalidationState: RouteRevalidationState = {};
|
|
910
|
-
const rootShouldReload = createModernShouldReload(
|
|
911
|
-
rootShouldRevalidate,
|
|
912
|
-
rootRevalidationState,
|
|
913
|
-
);
|
|
914
|
-
|
|
915
|
-
const rootRouteOptions: TanstackRootRouteOptions = {
|
|
916
|
-
component: rootComponent || undefined,
|
|
917
|
-
pendingComponent: pendingComponent || undefined,
|
|
918
|
-
errorComponent: errorComponent || undefined,
|
|
919
|
-
validateSearch: rootModern?.validateSearch,
|
|
920
|
-
loaderDeps: rootModern?.loaderDeps,
|
|
921
|
-
notFoundComponent: DefaultNotFound,
|
|
922
|
-
staticData: createRouteStaticData({
|
|
923
|
-
modernRouteId: rootModernId,
|
|
924
|
-
modernRouteAction: rootAction,
|
|
925
|
-
modernRouteHandle: rootModern
|
|
926
|
-
? mergeModernRouteHandle(rootModern)
|
|
927
|
-
: undefined,
|
|
928
|
-
modernRouteHasAction: rootModern?.hasAction || Boolean(rootAction),
|
|
929
|
-
modernRouteHasClientLoader:
|
|
930
|
-
rootModern?.hasClientLoader ||
|
|
931
|
-
typeof rootModern?.clientData !== 'undefined',
|
|
932
|
-
modernRouteHasLoader:
|
|
933
|
-
rootModern?.hasLoader || typeof rootLoader === 'function',
|
|
934
|
-
modernRouteIsClientComponent: rootModern?.isClientComponent,
|
|
935
|
-
modernRouteLoader: rootLoader,
|
|
936
|
-
modernRouteShouldRevalidate: rootShouldRevalidate,
|
|
937
|
-
}),
|
|
938
|
-
loader: rootModern
|
|
939
|
-
? wrapModernLoader(rootModern, rootLoader, rootRevalidationState, options)
|
|
940
|
-
: undefined,
|
|
941
|
-
};
|
|
942
|
-
if (rootShouldReload) {
|
|
943
|
-
rootRouteOptions.shouldReload = rootShouldReload;
|
|
944
|
-
}
|
|
945
|
-
if (rootModern?.inValidSSRRoute) {
|
|
946
|
-
rootRouteOptions.ssr = false;
|
|
947
|
-
}
|
|
948
|
-
|
|
949
|
-
const rootRoute = createTanstackRootRoute(rootRouteOptions);
|
|
950
|
-
|
|
951
|
-
const topLevel = rootModern
|
|
952
|
-
? (rootModern.children as Array<NestedRoute | PageRoute>) || []
|
|
953
|
-
: routes;
|
|
954
|
-
|
|
955
|
-
const childRoutes = topLevel.map(child =>
|
|
956
|
-
createRouteFromModernRoute({
|
|
957
|
-
options,
|
|
958
|
-
parent: rootRoute,
|
|
959
|
-
modernRoute: child,
|
|
960
|
-
}),
|
|
961
|
-
);
|
|
962
|
-
|
|
963
|
-
rootRoute.addChildren(childRoutes);
|
|
964
|
-
return rootRoute as unknown as ModernTanstackRootRoute;
|
|
965
|
-
}
|
|
966
|
-
|
|
967
634
|
function getRootLikeRouteObject(routes: RouteObject[]) {
|
|
968
635
|
return routes.find(route => route.path === '/' && !route.index);
|
|
969
636
|
}
|
|
@@ -982,8 +649,11 @@ export function createRouteTreeFromRouteObjects(
|
|
|
982
649
|
rootRevalidationState,
|
|
983
650
|
);
|
|
984
651
|
|
|
652
|
+
const rootComponent = rootLikeRoute
|
|
653
|
+
? toRouteComponent(rootLikeRoute)
|
|
654
|
+
: undefined;
|
|
985
655
|
const rootRouteOptions: TanstackRootRouteOptions = {
|
|
986
|
-
component:
|
|
656
|
+
component: rootComponent,
|
|
987
657
|
pendingComponent: rootLikeRoute
|
|
988
658
|
? toPendingComponent(rootLikeRoute)
|
|
989
659
|
: undefined,
|
|
@@ -1020,6 +690,12 @@ export function createRouteTreeFromRouteObjects(
|
|
|
1020
690
|
}
|
|
1021
691
|
|
|
1022
692
|
const rootRoute = createTanstackRootRoute(rootRouteOptions);
|
|
693
|
+
if (rootComponent) {
|
|
694
|
+
rootRoute.options.component = withModernRouteMatchContext(
|
|
695
|
+
rootComponent,
|
|
696
|
+
rootRouteId,
|
|
697
|
+
) as typeof rootRoute.options.component;
|
|
698
|
+
}
|
|
1023
699
|
|
|
1024
700
|
const topLevel = rootLikeRoute
|
|
1025
701
|
? [
|
|
@@ -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';
|
|
@@ -1,5 +1,6 @@
|
|
|
1
|
-
// @effect-diagnostics asyncFunction:off globalFetch:off strictBooleanExpressions:off
|
|
1
|
+
// @effect-diagnostics asyncFunction:off globalFetch:off processEnv:off strictBooleanExpressions:off
|
|
2
2
|
import type { PayloadRoute, ServerPayload } from '@modern-js/runtime/context';
|
|
3
|
+
import { isRouteErrorResponse } from '@modern-js/runtime-utils/router';
|
|
3
4
|
import { notFound, redirect } from '@tanstack/react-router';
|
|
4
5
|
|
|
5
6
|
type PayloadDecoder = (stream: ReadableStream<Uint8Array>) => Promise<unknown>;
|
|
@@ -103,6 +104,48 @@ function toPayloadRoute(match: RouterMatchLike): PayloadRoute | undefined {
|
|
|
103
104
|
};
|
|
104
105
|
}
|
|
105
106
|
|
|
107
|
+
function shouldRedactServerError(status = 500) {
|
|
108
|
+
return (
|
|
109
|
+
status >= 500 &&
|
|
110
|
+
process.env.NODE_ENV !== 'development' &&
|
|
111
|
+
process.env.NODE_ENV !== 'test'
|
|
112
|
+
);
|
|
113
|
+
}
|
|
114
|
+
|
|
115
|
+
function serializePayloadError(error: unknown): unknown {
|
|
116
|
+
if (isRouteErrorResponse(error)) {
|
|
117
|
+
if (shouldRedactServerError(error.status)) {
|
|
118
|
+
return {
|
|
119
|
+
status: error.status,
|
|
120
|
+
statusText: 'Internal Server Error',
|
|
121
|
+
data: 'Unexpected Server Error',
|
|
122
|
+
__type: 'RouteErrorResponse',
|
|
123
|
+
};
|
|
124
|
+
}
|
|
125
|
+
|
|
126
|
+
return { ...error, __type: 'RouteErrorResponse' };
|
|
127
|
+
}
|
|
128
|
+
|
|
129
|
+
if (error instanceof Error) {
|
|
130
|
+
if (shouldRedactServerError()) {
|
|
131
|
+
return {
|
|
132
|
+
message: 'Unexpected Server Error',
|
|
133
|
+
stack: undefined,
|
|
134
|
+
__type: 'Error',
|
|
135
|
+
};
|
|
136
|
+
}
|
|
137
|
+
|
|
138
|
+
return {
|
|
139
|
+
message: error.message,
|
|
140
|
+
stack: error.stack,
|
|
141
|
+
__type: 'Error',
|
|
142
|
+
...(error.name !== 'Error' ? { __subType: error.name } : {}),
|
|
143
|
+
};
|
|
144
|
+
}
|
|
145
|
+
|
|
146
|
+
return error;
|
|
147
|
+
}
|
|
148
|
+
|
|
106
149
|
export function createTanstackRscServerPayload(
|
|
107
150
|
router: TanstackPayloadRouterLike,
|
|
108
151
|
options: {
|
|
@@ -133,7 +176,7 @@ export function createTanstackRscServerPayload(
|
|
|
133
176
|
}
|
|
134
177
|
|
|
135
178
|
if (typeof match.error !== 'undefined') {
|
|
136
|
-
errors[payloadRoute.id] = match.error;
|
|
179
|
+
errors[payloadRoute.id] = serializePayloadError(match.error);
|
|
137
180
|
}
|
|
138
181
|
}
|
|
139
182
|
|
|
@@ -1,7 +1,5 @@
|
|
|
1
1
|
declare module '@tanstack/react-router/ssr/client' {
|
|
2
|
-
export function
|
|
3
|
-
router: unknown;
|
|
4
|
-
}): import('react').JSX.Element;
|
|
2
|
+
export function hydrate(router: unknown): Promise<unknown>;
|
|
5
3
|
}
|
|
6
4
|
|
|
7
5
|
declare module '@tanstack/react-router/ssr/server' {
|