@bleedingdev/modern-js-plugin-tanstack 3.2.0-ultramodern.12 → 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 +89 -31
- package/dist/cjs/cli/routeSplitting.js +55 -0
- package/dist/cjs/cli/tanstackTypes.js +172 -170
- 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 +48 -0
- package/dist/cjs/runtime/index.js +79 -35
- 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 +195 -114
- package/dist/cjs/runtime/plugin.node.js +45 -45
- package/dist/cjs/runtime/plugin.worker.js +53 -0
- 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 +74 -207
- 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 +31 -1
- package/dist/cjs/runtime/utils.js +9 -10
- package/dist/cjs/runtime.js +9 -5
- package/dist/esm/cli/index.mjs +75 -27
- package/dist/esm/cli/routeSplitting.mjs +14 -0
- package/dist/esm/cli/tanstackTypes.mjs +158 -160
- package/dist/esm/runtime/hooks.mjs +1 -8
- package/dist/esm/runtime/hydrationBoundary.mjs +10 -0
- package/dist/esm/runtime/index.mjs +5 -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 +191 -114
- package/dist/esm/runtime/plugin.node.mjs +40 -44
- package/dist/esm/runtime/plugin.worker.mjs +1 -0
- 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 +59 -193
- 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/types.mjs +7 -0
- package/dist/esm/runtime/utils.mjs +0 -5
- package/dist/esm-node/cli/index.mjs +75 -27
- package/dist/esm-node/cli/routeSplitting.mjs +15 -0
- package/dist/esm-node/cli/tanstackTypes.mjs +158 -160
- package/dist/esm-node/runtime/hooks.mjs +1 -8
- package/dist/esm-node/runtime/hydrationBoundary.mjs +11 -0
- package/dist/esm-node/runtime/index.mjs +5 -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 +191 -114
- package/dist/esm-node/runtime/plugin.node.mjs +40 -44
- package/dist/esm-node/runtime/plugin.worker.mjs +2 -0
- 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 +59 -193
- 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/types.mjs +7 -0
- package/dist/esm-node/runtime/utils.mjs +0 -5
- package/dist/types/cli/index.d.ts +14 -1
- package/dist/types/cli/routeSplitting.d.ts +20 -0
- package/dist/types/cli/tanstackTypes.d.ts +21 -1
- package/dist/types/runtime/hooks.d.ts +8 -33
- package/dist/types/runtime/hydrationBoundary.d.ts +2 -0
- package/dist/types/runtime/index.d.ts +8 -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 +2 -15
- package/dist/types/runtime/plugin.node.d.ts +2 -15
- package/dist/types/runtime/plugin.worker.d.ts +1 -0
- 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 +14 -53
- package/package.json +42 -40
- package/rstest.config.mts +6 -0
- package/src/cli/index.ts +162 -23
- package/src/cli/routeSplitting.ts +43 -0
- package/src/cli/tanstackTypes.ts +331 -187
- package/src/runtime/hooks.ts +10 -27
- package/src/runtime/hydrationBoundary.tsx +12 -0
- package/src/runtime/index.tsx +17 -7
- 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 +72 -85
- package/src/runtime/plugin.tsx +361 -206
- package/src/runtime/plugin.worker.tsx +4 -0
- 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 +163 -354
- 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 +32 -66
- package/src/runtime/utils.tsx +3 -6
- package/tests/router/cli.test.ts +586 -5
- package/tests/router/fastDefaults.test.ts +25 -0
- package/tests/router/hooks.test.ts +26 -0
- package/tests/router/hydrationBoundary.test.tsx +23 -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 +381 -81
- package/tests/router/rsc.test.tsx +70 -0
- package/tests/router/tanstackTypes.test.ts +573 -1
- 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
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,9 +11,16 @@ import {
|
|
|
10
11
|
createRootRoute,
|
|
11
12
|
createRoute,
|
|
12
13
|
notFound,
|
|
13
|
-
|
|
14
|
+
rootRouteId,
|
|
14
15
|
} from '@tanstack/react-router';
|
|
15
|
-
import {
|
|
16
|
+
import { createElement, type ElementType } from 'react';
|
|
17
|
+
import {
|
|
18
|
+
isRedirectResponse,
|
|
19
|
+
isResponse,
|
|
20
|
+
isTanstackRedirect,
|
|
21
|
+
throwTanstackRedirect,
|
|
22
|
+
} from './loaderBridge';
|
|
23
|
+
import { withModernRouteMatchContext } from './outlet';
|
|
16
24
|
import {
|
|
17
25
|
isTanstackRscPayloadNavigationEnabled,
|
|
18
26
|
loadTanstackRscRouteData,
|
|
@@ -75,40 +83,18 @@ type ModernRouteObject = RouteObject & {
|
|
|
75
83
|
isClientComponent?: boolean;
|
|
76
84
|
lazyImport?: () => unknown;
|
|
77
85
|
loader?: ModernLoader;
|
|
86
|
+
loaderDeps?: unknown;
|
|
78
87
|
pendingComponent?: unknown;
|
|
79
88
|
shouldRevalidate?: ModernShouldRevalidate;
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
type ModernGeneratedRoute = (NestedRoute | PageRoute) & {
|
|
83
|
-
_component?: string;
|
|
84
|
-
action?: unknown;
|
|
85
|
-
children?: ModernGeneratedRoute[];
|
|
86
|
-
component?: unknown;
|
|
87
|
-
config?: { handle?: Record<string, unknown> } | unknown;
|
|
88
|
-
clientData?: unknown;
|
|
89
|
-
data?: string;
|
|
90
|
-
error?: unknown;
|
|
91
|
-
errorComponent?: unknown;
|
|
92
|
-
filename?: string;
|
|
93
|
-
handle?: Record<string, unknown>;
|
|
94
|
-
hasAction?: boolean;
|
|
95
|
-
hasClientLoader?: boolean;
|
|
96
|
-
hasLoader?: boolean;
|
|
97
|
-
inValidSSRRoute?: boolean;
|
|
98
|
-
id?: string;
|
|
99
|
-
index?: boolean;
|
|
100
|
-
isClientComponent?: boolean;
|
|
101
|
-
isRoot?: boolean;
|
|
102
|
-
lazyImport?: () => unknown;
|
|
103
|
-
loader?: ModernLoader;
|
|
104
|
-
loading?: unknown;
|
|
105
|
-
pendingComponent?: unknown;
|
|
106
|
-
path?: string;
|
|
107
|
-
shouldRevalidate?: ModernShouldRevalidate;
|
|
89
|
+
validateSearch?: unknown;
|
|
108
90
|
};
|
|
109
91
|
|
|
110
92
|
type MutableTanstackRoute = AnyRoute & {
|
|
111
93
|
addChildren: (children: AnyRoute[]) => void;
|
|
94
|
+
id?: string;
|
|
95
|
+
options: {
|
|
96
|
+
component?: unknown;
|
|
97
|
+
};
|
|
112
98
|
};
|
|
113
99
|
|
|
114
100
|
type TanstackRouteOptions = Record<string, unknown>;
|
|
@@ -118,6 +104,15 @@ type ModernDeferredDataLike = {
|
|
|
118
104
|
__modern_deferred?: unknown;
|
|
119
105
|
data?: unknown;
|
|
120
106
|
};
|
|
107
|
+
type ModernRouteModule = {
|
|
108
|
+
Component?: unknown;
|
|
109
|
+
default?: unknown;
|
|
110
|
+
};
|
|
111
|
+
type PreloadableComponent = {
|
|
112
|
+
(props: Record<string, unknown>): ReturnType<typeof createElement>;
|
|
113
|
+
load?: () => Promise<unknown>;
|
|
114
|
+
preload?: () => Promise<unknown>;
|
|
115
|
+
};
|
|
121
116
|
type RouteTreeOptions = {
|
|
122
117
|
rscPayloadRouter?: boolean;
|
|
123
118
|
};
|
|
@@ -134,6 +129,20 @@ function createTanstackRootRoute(
|
|
|
134
129
|
return createRootRoute(options as never) as unknown as MutableTanstackRoute;
|
|
135
130
|
}
|
|
136
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
|
+
|
|
137
146
|
function toTanstackPath(pathname: string): string {
|
|
138
147
|
// TanStack Router uses `$param` and `$` (splat) style params.
|
|
139
148
|
// Modern's conventional routing currently generates React Router style params (e.g. `:id`, `*`).
|
|
@@ -163,28 +172,6 @@ function toTanstackPath(pathname: string): string {
|
|
|
163
172
|
.join('/');
|
|
164
173
|
}
|
|
165
174
|
|
|
166
|
-
function isResponse(value: unknown): value is Response {
|
|
167
|
-
const record = value as { headers?: unknown; status?: unknown } | null;
|
|
168
|
-
return (
|
|
169
|
-
record != null &&
|
|
170
|
-
typeof record === 'object' &&
|
|
171
|
-
typeof record.status === 'number' &&
|
|
172
|
-
typeof record.headers === 'object'
|
|
173
|
-
);
|
|
174
|
-
}
|
|
175
|
-
|
|
176
|
-
function isTanstackRedirect(value: unknown): boolean {
|
|
177
|
-
return (
|
|
178
|
-
isResponse(value) &&
|
|
179
|
-
typeof (value as { options?: unknown }).options === 'object'
|
|
180
|
-
);
|
|
181
|
-
}
|
|
182
|
-
|
|
183
|
-
const redirectStatusCodes = new Set([301, 302, 303, 307, 308]);
|
|
184
|
-
function isRedirectResponse(res: Response) {
|
|
185
|
-
return redirectStatusCodes.has(res.status);
|
|
186
|
-
}
|
|
187
|
-
|
|
188
175
|
function isModernDeferredData(
|
|
189
176
|
value: unknown,
|
|
190
177
|
): value is ModernDeferredDataLike & { data: Record<string, unknown> } {
|
|
@@ -219,44 +206,74 @@ function normalizeModernLoaderResponse(result: unknown): unknown {
|
|
|
219
206
|
return normalizeModernLoaderResult(result);
|
|
220
207
|
}
|
|
221
208
|
|
|
222
|
-
function
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
|
|
209
|
+
function pickRouteModuleComponent(
|
|
210
|
+
routeModule: unknown,
|
|
211
|
+
seen: Set<unknown> = new Set(),
|
|
212
|
+
): ElementType<Record<string, unknown>> | undefined {
|
|
213
|
+
if (
|
|
214
|
+
typeof routeModule === 'function' ||
|
|
215
|
+
(routeModule &&
|
|
216
|
+
typeof routeModule === 'object' &&
|
|
217
|
+
'$$typeof' in routeModule)
|
|
218
|
+
) {
|
|
219
|
+
return routeModule as ElementType<Record<string, unknown>>;
|
|
228
220
|
}
|
|
229
|
-
}
|
|
230
221
|
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
throw redirect({ href: target });
|
|
222
|
+
if (!routeModule || typeof routeModule !== 'object') {
|
|
223
|
+
return undefined;
|
|
224
|
+
}
|
|
225
|
+
if (seen.has(routeModule)) {
|
|
226
|
+
return undefined;
|
|
237
227
|
}
|
|
228
|
+
seen.add(routeModule);
|
|
238
229
|
|
|
239
|
-
|
|
230
|
+
const module = routeModule as ModernRouteModule;
|
|
231
|
+
for (const candidate of [module.default, module.Component]) {
|
|
232
|
+
const component = pickRouteModuleComponent(candidate, seen);
|
|
233
|
+
if (component) {
|
|
234
|
+
return component;
|
|
235
|
+
}
|
|
236
|
+
}
|
|
237
|
+
|
|
238
|
+
return undefined;
|
|
240
239
|
}
|
|
241
240
|
|
|
242
|
-
function
|
|
243
|
-
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
|
|
247
|
-
|
|
248
|
-
}) {
|
|
249
|
-
// React Router uses `*` for splat params, TanStack Router uses `_splat`.
|
|
250
|
-
if (modernRoute.type === 'nested' && modernRoute.path?.includes('*')) {
|
|
251
|
-
const { _splat, ...rest } = params as RouteParams & {
|
|
252
|
-
_splat?: string;
|
|
253
|
-
};
|
|
254
|
-
if (typeof _splat !== 'undefined') {
|
|
255
|
-
return { ...rest, '*': _splat };
|
|
256
|
-
}
|
|
257
|
-
return rest;
|
|
241
|
+
function createServerLazyImportComponent(
|
|
242
|
+
lazyImport: () => unknown,
|
|
243
|
+
fallbackComponent?: unknown,
|
|
244
|
+
): PreloadableComponent | unknown {
|
|
245
|
+
if (typeof document !== 'undefined') {
|
|
246
|
+
return fallbackComponent;
|
|
258
247
|
}
|
|
259
|
-
|
|
248
|
+
|
|
249
|
+
let resolvedComponent: ElementType<Record<string, unknown>> | undefined;
|
|
250
|
+
let pendingLoad: Promise<unknown> | undefined;
|
|
251
|
+
|
|
252
|
+
const load = async () => {
|
|
253
|
+
if (resolvedComponent) {
|
|
254
|
+
return resolvedComponent;
|
|
255
|
+
}
|
|
256
|
+
|
|
257
|
+
const routeModule = await lazyImport();
|
|
258
|
+
const component = pickRouteModuleComponent(routeModule);
|
|
259
|
+
if (component) {
|
|
260
|
+
resolvedComponent = component;
|
|
261
|
+
}
|
|
262
|
+
return resolvedComponent;
|
|
263
|
+
};
|
|
264
|
+
|
|
265
|
+
const Component: PreloadableComponent = props => {
|
|
266
|
+
if (resolvedComponent) {
|
|
267
|
+
return createElement(resolvedComponent, props);
|
|
268
|
+
}
|
|
269
|
+
|
|
270
|
+
pendingLoad ||= load();
|
|
271
|
+
throw pendingLoad;
|
|
272
|
+
};
|
|
273
|
+
Component.load = load;
|
|
274
|
+
Component.preload = load;
|
|
275
|
+
|
|
276
|
+
return Component;
|
|
260
277
|
}
|
|
261
278
|
|
|
262
279
|
function createModernRequest(input: string, signal: AbortSignal) {
|
|
@@ -316,91 +333,6 @@ function createModernShouldReload(
|
|
|
316
333
|
};
|
|
317
334
|
}
|
|
318
335
|
|
|
319
|
-
function wrapModernLoader(
|
|
320
|
-
modernRoute: NestedRoute | PageRoute,
|
|
321
|
-
modernLoader: ModernLoader | undefined,
|
|
322
|
-
revalidationState?: RouteRevalidationState,
|
|
323
|
-
options: RouteTreeOptions = {},
|
|
324
|
-
) {
|
|
325
|
-
const route = modernRoute as ModernGeneratedRoute;
|
|
326
|
-
return async (ctx: TanstackLoaderContext) => {
|
|
327
|
-
try {
|
|
328
|
-
if (revalidationState) {
|
|
329
|
-
rememberRouteLocation(revalidationState, ctx);
|
|
330
|
-
}
|
|
331
|
-
|
|
332
|
-
if (typeof route.lazyImport === 'function') {
|
|
333
|
-
try {
|
|
334
|
-
await route.lazyImport();
|
|
335
|
-
} catch {}
|
|
336
|
-
}
|
|
337
|
-
|
|
338
|
-
const signal: AbortSignal =
|
|
339
|
-
ctx?.abortController?.signal ||
|
|
340
|
-
ctx?.signal ||
|
|
341
|
-
new AbortController().signal;
|
|
342
|
-
const baseRequest: Request | undefined =
|
|
343
|
-
ctx?.context?.request instanceof Request
|
|
344
|
-
? ctx.context.request
|
|
345
|
-
: undefined;
|
|
346
|
-
|
|
347
|
-
const href =
|
|
348
|
-
typeof ctx?.location === 'string'
|
|
349
|
-
? ctx.location
|
|
350
|
-
: ctx?.location?.publicHref ||
|
|
351
|
-
ctx?.location?.href ||
|
|
352
|
-
ctx?.location?.url?.href ||
|
|
353
|
-
'';
|
|
354
|
-
|
|
355
|
-
const request = baseRequest
|
|
356
|
-
? new Request(baseRequest, { signal })
|
|
357
|
-
: createModernRequest(href, signal);
|
|
358
|
-
const params = mapParamsForModernLoader({
|
|
359
|
-
modernRoute,
|
|
360
|
-
params: ctx.params || {},
|
|
361
|
-
});
|
|
362
|
-
|
|
363
|
-
const loadModernData = async () => {
|
|
364
|
-
const result = modernLoader
|
|
365
|
-
? await modernLoader({
|
|
366
|
-
request,
|
|
367
|
-
params,
|
|
368
|
-
context: ctx?.context?.requestContext,
|
|
369
|
-
})
|
|
370
|
-
: null;
|
|
371
|
-
|
|
372
|
-
return normalizeModernLoaderResponse(result);
|
|
373
|
-
};
|
|
374
|
-
|
|
375
|
-
if (options.rscPayloadRouter && isTanstackRscPayloadNavigationEnabled()) {
|
|
376
|
-
return loadTanstackRscRouteData({
|
|
377
|
-
hasClientLoader:
|
|
378
|
-
route.hasClientLoader || typeof route.clientData !== 'undefined',
|
|
379
|
-
loadClientData: loadModernData,
|
|
380
|
-
request,
|
|
381
|
-
routeId: ctx.route?.id,
|
|
382
|
-
});
|
|
383
|
-
}
|
|
384
|
-
|
|
385
|
-
return loadModernData();
|
|
386
|
-
} catch (err) {
|
|
387
|
-
if (isResponse(err)) {
|
|
388
|
-
if (isTanstackRedirect(err)) {
|
|
389
|
-
throw err;
|
|
390
|
-
}
|
|
391
|
-
if (isRedirectResponse(err)) {
|
|
392
|
-
const location = err.headers.get('Location') || '/';
|
|
393
|
-
throwTanstackRedirect(location);
|
|
394
|
-
}
|
|
395
|
-
if (err.status === 404) {
|
|
396
|
-
throw notFound();
|
|
397
|
-
}
|
|
398
|
-
}
|
|
399
|
-
throw err;
|
|
400
|
-
}
|
|
401
|
-
};
|
|
402
|
-
}
|
|
403
|
-
|
|
404
336
|
function isRouteObjectPathlessLayout(route: RouteObject) {
|
|
405
337
|
return !route.path && !route.index;
|
|
406
338
|
}
|
|
@@ -468,9 +400,10 @@ function wrapRouteObjectLoader(
|
|
|
468
400
|
ctx?.location?.url?.href ||
|
|
469
401
|
'';
|
|
470
402
|
|
|
471
|
-
const request =
|
|
472
|
-
|
|
473
|
-
|
|
403
|
+
const request =
|
|
404
|
+
baseRequest !== undefined
|
|
405
|
+
? new Request(baseRequest, { signal })
|
|
406
|
+
: createModernRequest(href, signal);
|
|
474
407
|
|
|
475
408
|
const params = mapParamsForRouteObjectLoader({
|
|
476
409
|
route,
|
|
@@ -519,6 +452,18 @@ function wrapRouteObjectLoader(
|
|
|
519
452
|
|
|
520
453
|
function toRouteComponent(routeObject: RouteObject): unknown {
|
|
521
454
|
const route = routeObject as ModernRouteObject;
|
|
455
|
+
const lazyImport =
|
|
456
|
+
typeof route.lazyImport === 'function' ? route.lazyImport : undefined;
|
|
457
|
+
const fallbackComponent = route.Component
|
|
458
|
+
? route.Component
|
|
459
|
+
: route.element
|
|
460
|
+
? () => route.element
|
|
461
|
+
: undefined;
|
|
462
|
+
|
|
463
|
+
if (lazyImport && fallbackComponent) {
|
|
464
|
+
return createServerLazyImportComponent(lazyImport, fallbackComponent);
|
|
465
|
+
}
|
|
466
|
+
|
|
522
467
|
if (route.Component) {
|
|
523
468
|
return route.Component;
|
|
524
469
|
}
|
|
@@ -627,12 +572,14 @@ function createRouteFromRouteObject(opts: {
|
|
|
627
572
|
const stableFallbackId =
|
|
628
573
|
routeObject.id || modernRouteObject.file || routeObject.path || 'pathless';
|
|
629
574
|
|
|
575
|
+
const component = toRouteComponent(routeObject);
|
|
630
576
|
const base: TanstackRouteOptions = {
|
|
631
577
|
getParentRoute: () => parent,
|
|
632
|
-
component
|
|
578
|
+
component,
|
|
633
579
|
pendingComponent: toPendingComponent(routeObject),
|
|
634
580
|
errorComponent: toErrorComponent(routeObject),
|
|
635
|
-
|
|
581
|
+
validateSearch: modernRouteObject.validateSearch,
|
|
582
|
+
loaderDeps: modernRouteObject.loaderDeps,
|
|
636
583
|
staticData: createRouteStaticData({
|
|
637
584
|
modernRouteId: routeObject.id,
|
|
638
585
|
modernRouteAction: modernRouteObject.action,
|
|
@@ -667,6 +614,7 @@ function createRouteFromRouteObject(opts: {
|
|
|
667
614
|
}
|
|
668
615
|
|
|
669
616
|
const route = createTanstackRoute(base);
|
|
617
|
+
wrapRouteComponentWithModernContext(route, component, routeObject.id);
|
|
670
618
|
|
|
671
619
|
const children = routeObject.children;
|
|
672
620
|
if (children && children.length > 0) {
|
|
@@ -683,175 +631,6 @@ function createRouteFromRouteObject(opts: {
|
|
|
683
631
|
return route;
|
|
684
632
|
}
|
|
685
633
|
|
|
686
|
-
function createRouteFromModernRoute(opts: {
|
|
687
|
-
options?: RouteTreeOptions;
|
|
688
|
-
parent: AnyRoute;
|
|
689
|
-
modernRoute: NestedRoute | PageRoute;
|
|
690
|
-
}): AnyRoute {
|
|
691
|
-
const { options = {}, parent, modernRoute } = opts;
|
|
692
|
-
const route = modernRoute as ModernGeneratedRoute;
|
|
693
|
-
const revalidationState: RouteRevalidationState = {};
|
|
694
|
-
|
|
695
|
-
const modernId = route.id;
|
|
696
|
-
const stableFallbackId =
|
|
697
|
-
modernId ||
|
|
698
|
-
route._component ||
|
|
699
|
-
route.filename ||
|
|
700
|
-
route.data ||
|
|
701
|
-
(typeof route.loader === 'function' ? route.id : undefined);
|
|
702
|
-
|
|
703
|
-
const pendingComponent = route.loading || route.pendingComponent;
|
|
704
|
-
const errorComponent = route.error || route.errorComponent;
|
|
705
|
-
const component = route.component;
|
|
706
|
-
const modernLoader = route.loader;
|
|
707
|
-
const modernAction = route.action;
|
|
708
|
-
const modernShouldRevalidate = route.shouldRevalidate;
|
|
709
|
-
const shouldReload = createModernShouldReload(
|
|
710
|
-
modernShouldRevalidate,
|
|
711
|
-
revalidationState,
|
|
712
|
-
);
|
|
713
|
-
|
|
714
|
-
// Pathless layout: no path segment, but must remain in the tree.
|
|
715
|
-
const isPathlessLayout =
|
|
716
|
-
route.type === 'nested' &&
|
|
717
|
-
typeof route.index !== 'boolean' &&
|
|
718
|
-
typeof route.path === 'undefined';
|
|
719
|
-
|
|
720
|
-
const isIndexRoute = route.type === 'nested' && Boolean(route.index);
|
|
721
|
-
|
|
722
|
-
const base: TanstackRouteOptions = {
|
|
723
|
-
getParentRoute: () => parent,
|
|
724
|
-
component: component || undefined,
|
|
725
|
-
pendingComponent: pendingComponent || undefined,
|
|
726
|
-
errorComponent: errorComponent || undefined,
|
|
727
|
-
wrapInSuspense: true,
|
|
728
|
-
staticData: createRouteStaticData({
|
|
729
|
-
modernRouteId: modernId,
|
|
730
|
-
modernRouteAction: modernAction,
|
|
731
|
-
modernRouteHandle: mergeModernRouteHandle(route),
|
|
732
|
-
modernRouteHasAction: route.hasAction || Boolean(modernAction),
|
|
733
|
-
modernRouteHasClientLoader:
|
|
734
|
-
route.hasClientLoader || typeof route.clientData !== 'undefined',
|
|
735
|
-
modernRouteHasLoader:
|
|
736
|
-
route.hasLoader || typeof modernLoader === 'function',
|
|
737
|
-
modernRouteIsClientComponent: route.isClientComponent,
|
|
738
|
-
modernRouteLoader: modernLoader,
|
|
739
|
-
modernRouteShouldRevalidate: modernShouldRevalidate,
|
|
740
|
-
}),
|
|
741
|
-
loader: wrapModernLoader(
|
|
742
|
-
modernRoute,
|
|
743
|
-
modernLoader,
|
|
744
|
-
revalidationState,
|
|
745
|
-
options,
|
|
746
|
-
),
|
|
747
|
-
};
|
|
748
|
-
if (route.inValidSSRRoute) {
|
|
749
|
-
base.ssr = false;
|
|
750
|
-
}
|
|
751
|
-
if (shouldReload) {
|
|
752
|
-
base.shouldReload = shouldReload;
|
|
753
|
-
}
|
|
754
|
-
|
|
755
|
-
if (isPathlessLayout) {
|
|
756
|
-
// Use a stable custom id for pathless layouts to avoid hydration mismatch.
|
|
757
|
-
base.id = stableFallbackId || 'pathless';
|
|
758
|
-
} else {
|
|
759
|
-
const rawPath = route.path;
|
|
760
|
-
base.path = isIndexRoute ? '/' : toTanstackPath(rawPath || '');
|
|
761
|
-
}
|
|
762
|
-
|
|
763
|
-
const tanstackRoute = createTanstackRoute(base);
|
|
764
|
-
|
|
765
|
-
const children = route.children as Array<NestedRoute | PageRoute> | undefined;
|
|
766
|
-
if (children && children.length > 0) {
|
|
767
|
-
const childRoutes = children.map(child =>
|
|
768
|
-
createRouteFromModernRoute({
|
|
769
|
-
options,
|
|
770
|
-
parent: tanstackRoute,
|
|
771
|
-
modernRoute: child,
|
|
772
|
-
}),
|
|
773
|
-
);
|
|
774
|
-
tanstackRoute.addChildren(childRoutes);
|
|
775
|
-
}
|
|
776
|
-
|
|
777
|
-
return tanstackRoute;
|
|
778
|
-
}
|
|
779
|
-
|
|
780
|
-
export function createRouteTreeFromModernRoutes(
|
|
781
|
-
routes: Array<NestedRoute | PageRoute>,
|
|
782
|
-
options: RouteTreeOptions = {},
|
|
783
|
-
): ModernTanstackRootRoute {
|
|
784
|
-
const rootModern = routes.find(
|
|
785
|
-
r =>
|
|
786
|
-
r &&
|
|
787
|
-
(r as ModernGeneratedRoute).type === 'nested' &&
|
|
788
|
-
(r as ModernGeneratedRoute).isRoot,
|
|
789
|
-
) as ModernGeneratedRoute | undefined;
|
|
790
|
-
|
|
791
|
-
const rootComponent = rootModern?.component;
|
|
792
|
-
const pendingComponent = rootModern?.loading;
|
|
793
|
-
const errorComponent = rootModern?.error;
|
|
794
|
-
const rootLoader = rootModern?.loader;
|
|
795
|
-
const rootAction = rootModern?.action;
|
|
796
|
-
const rootModernId = rootModern?.id;
|
|
797
|
-
const rootShouldRevalidate = rootModern?.shouldRevalidate;
|
|
798
|
-
const rootRevalidationState: RouteRevalidationState = {};
|
|
799
|
-
const rootShouldReload = createModernShouldReload(
|
|
800
|
-
rootShouldRevalidate,
|
|
801
|
-
rootRevalidationState,
|
|
802
|
-
);
|
|
803
|
-
|
|
804
|
-
const rootRouteOptions: TanstackRootRouteOptions = {
|
|
805
|
-
component: rootComponent || undefined,
|
|
806
|
-
pendingComponent: pendingComponent || undefined,
|
|
807
|
-
errorComponent: errorComponent || undefined,
|
|
808
|
-
wrapInSuspense: true,
|
|
809
|
-
notFoundComponent: DefaultNotFound,
|
|
810
|
-
staticData: createRouteStaticData({
|
|
811
|
-
modernRouteId: rootModernId,
|
|
812
|
-
modernRouteAction: rootAction,
|
|
813
|
-
modernRouteHandle: rootModern
|
|
814
|
-
? mergeModernRouteHandle(rootModern)
|
|
815
|
-
: undefined,
|
|
816
|
-
modernRouteHasAction: rootModern?.hasAction || Boolean(rootAction),
|
|
817
|
-
modernRouteHasClientLoader:
|
|
818
|
-
rootModern?.hasClientLoader ||
|
|
819
|
-
typeof rootModern?.clientData !== 'undefined',
|
|
820
|
-
modernRouteHasLoader:
|
|
821
|
-
rootModern?.hasLoader || typeof rootLoader === 'function',
|
|
822
|
-
modernRouteIsClientComponent: rootModern?.isClientComponent,
|
|
823
|
-
modernRouteLoader: rootLoader,
|
|
824
|
-
modernRouteShouldRevalidate: rootShouldRevalidate,
|
|
825
|
-
}),
|
|
826
|
-
loader: rootModern
|
|
827
|
-
? wrapModernLoader(rootModern, rootLoader, rootRevalidationState, options)
|
|
828
|
-
: undefined,
|
|
829
|
-
};
|
|
830
|
-
if (rootShouldReload) {
|
|
831
|
-
rootRouteOptions.shouldReload = rootShouldReload;
|
|
832
|
-
}
|
|
833
|
-
if (rootModern?.inValidSSRRoute) {
|
|
834
|
-
rootRouteOptions.ssr = false;
|
|
835
|
-
}
|
|
836
|
-
|
|
837
|
-
const rootRoute = createTanstackRootRoute(rootRouteOptions);
|
|
838
|
-
|
|
839
|
-
const topLevel = rootModern
|
|
840
|
-
? (rootModern.children as Array<NestedRoute | PageRoute>) || []
|
|
841
|
-
: routes;
|
|
842
|
-
|
|
843
|
-
const childRoutes = topLevel.map(child =>
|
|
844
|
-
createRouteFromModernRoute({
|
|
845
|
-
options,
|
|
846
|
-
parent: rootRoute,
|
|
847
|
-
modernRoute: child,
|
|
848
|
-
}),
|
|
849
|
-
);
|
|
850
|
-
|
|
851
|
-
rootRoute.addChildren(childRoutes);
|
|
852
|
-
return rootRoute as unknown as ModernTanstackRootRoute;
|
|
853
|
-
}
|
|
854
|
-
|
|
855
634
|
function getRootLikeRouteObject(routes: RouteObject[]) {
|
|
856
635
|
return routes.find(route => route.path === '/' && !route.index);
|
|
857
636
|
}
|
|
@@ -870,13 +649,17 @@ export function createRouteTreeFromRouteObjects(
|
|
|
870
649
|
rootRevalidationState,
|
|
871
650
|
);
|
|
872
651
|
|
|
652
|
+
const rootComponent = rootLikeRoute
|
|
653
|
+
? toRouteComponent(rootLikeRoute)
|
|
654
|
+
: undefined;
|
|
873
655
|
const rootRouteOptions: TanstackRootRouteOptions = {
|
|
874
|
-
component:
|
|
656
|
+
component: rootComponent,
|
|
875
657
|
pendingComponent: rootLikeRoute
|
|
876
658
|
? toPendingComponent(rootLikeRoute)
|
|
877
659
|
: undefined,
|
|
878
660
|
errorComponent: rootLikeRoute ? toErrorComponent(rootLikeRoute) : undefined,
|
|
879
|
-
|
|
661
|
+
validateSearch: rootLikeRoute?.validateSearch,
|
|
662
|
+
loaderDeps: rootLikeRoute?.loaderDeps,
|
|
880
663
|
notFoundComponent: DefaultNotFound,
|
|
881
664
|
staticData: createRouteStaticData({
|
|
882
665
|
modernRouteId: rootLikeRoute?.id,
|
|
@@ -907,6 +690,12 @@ export function createRouteTreeFromRouteObjects(
|
|
|
907
690
|
}
|
|
908
691
|
|
|
909
692
|
const rootRoute = createTanstackRootRoute(rootRouteOptions);
|
|
693
|
+
if (rootComponent) {
|
|
694
|
+
rootRoute.options.component = withModernRouteMatchContext(
|
|
695
|
+
rootComponent,
|
|
696
|
+
rootRouteId,
|
|
697
|
+
) as typeof rootRoute.options.component;
|
|
698
|
+
}
|
|
910
699
|
|
|
911
700
|
const topLevel = rootLikeRoute
|
|
912
701
|
? [
|
|
@@ -925,18 +714,38 @@ export function createRouteTreeFromRouteObjects(
|
|
|
925
714
|
|
|
926
715
|
export function getModernRouteIdsFromMatches(router: AnyRouter): string[] {
|
|
927
716
|
const matches = router.state.matches || [];
|
|
717
|
+
const routesById = (
|
|
718
|
+
router as AnyRouter & {
|
|
719
|
+
routesById?: Record<
|
|
720
|
+
string,
|
|
721
|
+
{
|
|
722
|
+
options?: {
|
|
723
|
+
staticData?: { modernRouteId?: unknown };
|
|
724
|
+
};
|
|
725
|
+
}
|
|
726
|
+
>;
|
|
727
|
+
}
|
|
728
|
+
).routesById;
|
|
928
729
|
const ids = matches
|
|
929
730
|
.map(match => {
|
|
930
|
-
const
|
|
931
|
-
|
|
932
|
-
|
|
933
|
-
|
|
934
|
-
staticData?: { modernRouteId?: unknown };
|
|
935
|
-
};
|
|
731
|
+
const normalizedMatch = match as {
|
|
732
|
+
route?: {
|
|
733
|
+
options?: {
|
|
734
|
+
staticData?: { modernRouteId?: unknown };
|
|
936
735
|
};
|
|
937
|
-
}
|
|
938
|
-
|
|
939
|
-
|
|
736
|
+
};
|
|
737
|
+
routeId?: unknown;
|
|
738
|
+
};
|
|
739
|
+
const routeId =
|
|
740
|
+
typeof normalizedMatch.routeId === 'string'
|
|
741
|
+
? normalizedMatch.routeId
|
|
742
|
+
: undefined;
|
|
743
|
+
return (
|
|
744
|
+
normalizedMatch.route?.options?.staticData?.modernRouteId ??
|
|
745
|
+
(routeId
|
|
746
|
+
? routesById?.[routeId]?.options?.staticData?.modernRouteId
|
|
747
|
+
: undefined)
|
|
748
|
+
);
|
|
940
749
|
})
|
|
941
750
|
.filter((id): id is string => typeof id === 'string');
|
|
942
751
|
return Array.from(new Set(ids));
|
|
@@ -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';
|