@bleedingdev/modern-js-plugin-tanstack 3.9.0-ultramodern.11 → 3.9.0-ultramodern.13
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/artifacts.js +2 -1
- package/dist/cjs/cli/tanstackTypes/canonicalRoutes.js +7 -7
- package/dist/cjs/cli/tanstackTypes/shared.js +0 -14
- package/dist/cjs/cli/tanstackTypes/source.js +28 -63
- package/dist/cjs/runtime/lifecycle.js +0 -3
- package/dist/cjs/runtime/loaderBridge.js +10 -4
- package/dist/cjs/runtime/navigation.js +102 -0
- package/dist/cjs/runtime/plugin.js +6 -1
- package/dist/cjs/runtime/plugin.node.js +81 -63
- package/dist/cjs/runtime/routeTree/construction.js +19 -61
- package/dist/cjs/runtime/routeTree/loaders.js +1 -1
- package/dist/cjs/runtime/routeTree/paths.js +0 -6
- package/dist/cjs/runtime/ssrManagedTags.js +2 -12
- package/dist/cjs/runtime/utils.js +1 -0
- package/dist/cjs/shared/routeDescriptor.js +60 -0
- package/dist/esm/cli/artifacts.mjs +2 -1
- package/dist/esm/cli/index.mjs +1 -7
- package/dist/esm/cli/tanstackTypes/canonicalRoutes.mjs +7 -7
- package/dist/esm/cli/tanstackTypes/shared.mjs +1 -9
- package/dist/esm/cli/tanstackTypes/source.mjs +29 -64
- package/dist/esm/runtime/lifecycle.mjs +1 -1
- package/dist/esm/runtime/loaderBridge.mjs +8 -5
- package/dist/esm/runtime/navigation.mjs +64 -0
- package/dist/esm/runtime/plugin.mjs +6 -1
- package/dist/esm/runtime/plugin.node.mjs +83 -65
- package/dist/esm/runtime/routeTree/construction.mjs +19 -61
- package/dist/esm/runtime/routeTree/loaders.mjs +2 -2
- package/dist/esm/runtime/routeTree/paths.mjs +1 -4
- package/dist/esm/runtime/ssrManagedTags.mjs +1 -8
- package/dist/esm/runtime/utils.mjs +1 -0
- package/dist/esm/shared/routeDescriptor.mjs +22 -0
- package/dist/esm-node/cli/artifacts.mjs +2 -1
- package/dist/esm-node/cli/index.mjs +1 -7
- package/dist/esm-node/cli/tanstackTypes/canonicalRoutes.mjs +7 -7
- package/dist/esm-node/cli/tanstackTypes/shared.mjs +1 -9
- package/dist/esm-node/cli/tanstackTypes/source.mjs +29 -64
- package/dist/esm-node/runtime/lifecycle.mjs +1 -1
- package/dist/esm-node/runtime/loaderBridge.mjs +8 -5
- package/dist/esm-node/runtime/navigation.mjs +65 -0
- package/dist/esm-node/runtime/plugin.mjs +6 -1
- package/dist/esm-node/runtime/plugin.node.mjs +83 -65
- package/dist/esm-node/runtime/routeTree/construction.mjs +19 -61
- package/dist/esm-node/runtime/routeTree/loaders.mjs +2 -2
- package/dist/esm-node/runtime/routeTree/paths.mjs +1 -4
- package/dist/esm-node/runtime/ssrManagedTags.mjs +1 -8
- package/dist/esm-node/runtime/utils.mjs +1 -0
- package/dist/esm-node/shared/routeDescriptor.mjs +23 -0
- package/dist/types/cli/tanstackTypes/shared.d.ts +0 -2
- package/dist/types/runtime/lifecycle.d.ts +1 -1
- package/dist/types/runtime/loaderBridge.d.ts +1 -0
- package/dist/types/runtime/navigation.d.ts +4 -0
- package/dist/types/runtime/routeTree/paths.d.ts +0 -2
- package/dist/types/runtime/ssrManagedTags.d.ts +0 -1
- package/dist/types/runtime/ssrTypes.d.ts +0 -7
- package/dist/types/shared/routeDescriptor.d.ts +26 -0
- package/package.json +21 -21
- package/src/cli/artifacts.ts +6 -1
- package/src/cli/tanstackTypes/canonicalRoutes.ts +17 -12
- package/src/cli/tanstackTypes/shared.ts +0 -14
- package/src/cli/tanstackTypes/source.ts +43 -119
- package/src/runtime/lifecycle.ts +0 -1
- package/src/runtime/loaderBridge.ts +9 -9
- package/src/runtime/navigation.ts +78 -0
- package/src/runtime/plugin.node.tsx +111 -91
- package/src/runtime/plugin.tsx +6 -0
- package/src/runtime/routeTree/construction.ts +32 -112
- package/src/runtime/routeTree/loaders.ts +2 -4
- package/src/runtime/routeTree/paths.ts +0 -6
- package/src/runtime/ssrManagedTags.ts +0 -17
- package/src/runtime/ssrTypes.ts +0 -7
- package/src/runtime/utils.tsx +1 -0
- package/src/shared/routeDescriptor.ts +46 -0
- package/tests/router/clientNavigation.ts +13 -0
- package/tests/router/generateRouteArtifacts.test.ts +36 -2
- package/tests/router/localisedIdentity.test.tsx +7 -2
- package/tests/router/prefetchLink.test.tsx +29 -0
- package/tests/router/routeHooks.test.ts +2 -1
- package/tests/router/serverPlugin.test.ts +150 -0
- package/tests/router/tanstackTypes.test.ts +121 -2
- package/dist/esm/rslib-runtime~1.mjs +0 -18
- package/dist/esm-node/rslib-runtime~0.mjs +0 -19
|
@@ -23,11 +23,13 @@ import { createModernBasepathRewrite } from './basepathRewrite';
|
|
|
23
23
|
import { routerProviderRegistryHooks } from './hooks';
|
|
24
24
|
import { wrapTanstackSsrHydrationBoundary } from './hydrationBoundary';
|
|
25
25
|
import {
|
|
26
|
+
applyRouterRuntimeState,
|
|
26
27
|
applyRouterServerPrepareResult,
|
|
27
|
-
createRouterServerSnapshot,
|
|
28
28
|
getRouterRuntimeState,
|
|
29
|
+
getRouterServerSnapshot,
|
|
29
30
|
type RouterLifecycleContext,
|
|
30
31
|
} from './lifecycle';
|
|
32
|
+
import { createTanstackNavigation } from './navigation';
|
|
31
33
|
import {
|
|
32
34
|
createTanstackRouteObjects,
|
|
33
35
|
getTanstackRouteConfig,
|
|
@@ -54,7 +56,6 @@ import {
|
|
|
54
56
|
collectRouterErrors,
|
|
55
57
|
createGetSsrHref,
|
|
56
58
|
routerManagedTagsToHtml,
|
|
57
|
-
waitForRouterSerialization,
|
|
58
59
|
} from './ssrManagedTags';
|
|
59
60
|
import { preloadMatchedRouteComponents } from './ssrPreload';
|
|
60
61
|
import type {
|
|
@@ -168,116 +169,135 @@ export const tanstackRouterPlugin = (
|
|
|
168
169
|
setTanstackRscRouter(serverRouter);
|
|
169
170
|
}
|
|
170
171
|
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
const
|
|
174
|
-
|
|
172
|
+
let disposed = false;
|
|
173
|
+
let prepared = false;
|
|
174
|
+
const onAbort = () => controller.abort(rawRequest.signal.reason);
|
|
175
|
+
const cleanup = () => {
|
|
176
|
+
if (disposed) return;
|
|
177
|
+
disposed = true;
|
|
178
|
+
rawRequest.signal.removeEventListener('abort', onAbort);
|
|
179
|
+
controller.abort();
|
|
180
|
+
serverRouter.serverSsr?.cleanup();
|
|
181
|
+
};
|
|
182
|
+
// Acquire the disposer before attachment: every subsequent failure,
|
|
183
|
+
// including partial attachment, has an owner. Successful preparation
|
|
184
|
+
// leaves disposal to the response lifetime in the SSR pipeline.
|
|
185
|
+
applyRouterRuntimeState(context, {
|
|
186
|
+
framework: 'tanstack',
|
|
187
|
+
basename: _basename,
|
|
188
|
+
instance: serverRouter,
|
|
189
|
+
cleanup,
|
|
190
|
+
});
|
|
191
|
+
rawRequest.signal.addEventListener('abort', onAbort, { once: true });
|
|
175
192
|
try {
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
193
|
+
rawRequest.signal.throwIfAborted();
|
|
194
|
+
await attachServerSsrUtils(serverRouter);
|
|
195
|
+
rawRequest.signal.throwIfAborted();
|
|
196
|
+
|
|
197
|
+
const end = time();
|
|
181
198
|
|
|
182
|
-
const serverLoadResult = serverRouter._serverResult;
|
|
183
|
-
if (!serverLoadResult) {
|
|
184
199
|
try {
|
|
185
|
-
|
|
186
|
-
}
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
}
|
|
200
|
+
await tanstackRouter.load({ sync: true });
|
|
201
|
+
} finally {
|
|
202
|
+
const cost = end();
|
|
203
|
+
context.ssrContext?.onTiming?.(LOADER_REPORTER_NAME, cost);
|
|
204
|
+
}
|
|
191
205
|
|
|
192
|
-
|
|
193
|
-
const
|
|
206
|
+
rawRequest.signal.throwIfAborted();
|
|
207
|
+
const serverLoadResult = serverRouter._serverResult;
|
|
208
|
+
if (!serverLoadResult) {
|
|
209
|
+
throw new Error(
|
|
210
|
+
'TanStack Router completed an SSR load without a server result.',
|
|
211
|
+
);
|
|
212
|
+
}
|
|
194
213
|
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
214
|
+
if (serverLoadResult.type === 'redirect') {
|
|
215
|
+
const { redirect } = serverLoadResult;
|
|
216
|
+
|
|
217
|
+
return interrupt(
|
|
218
|
+
isRSCNavigation
|
|
219
|
+
? handleTanstackRscRedirect(
|
|
220
|
+
redirect.headers,
|
|
221
|
+
_basename,
|
|
222
|
+
redirect.status,
|
|
223
|
+
)
|
|
224
|
+
: redirect,
|
|
225
|
+
);
|
|
226
|
+
}
|
|
227
|
+
|
|
228
|
+
const routerErrors = collectRouterErrors(tanstackRouter);
|
|
229
|
+
if (routerErrors && loaderFailureMode === 'clientRender') {
|
|
230
|
+
(
|
|
231
|
+
context.ssrContext?.response as
|
|
232
|
+
| { status: (code: number) => void }
|
|
233
|
+
| undefined
|
|
234
|
+
)?.status(200);
|
|
235
|
+
throw Object.values(routerErrors)[0];
|
|
236
|
+
}
|
|
237
|
+
|
|
238
|
+
await preloadMatchedRouteComponents(serverRouter);
|
|
209
239
|
|
|
210
|
-
const routerErrors = collectRouterErrors(tanstackRouter);
|
|
211
|
-
if (routerErrors && loaderFailureMode === 'clientRender') {
|
|
212
240
|
(
|
|
213
241
|
context.ssrContext?.response as
|
|
214
242
|
| { status: (code: number) => void }
|
|
215
243
|
| undefined
|
|
216
|
-
)?.status(
|
|
217
|
-
try {
|
|
218
|
-
serverRouter.serverSsr?.cleanup?.();
|
|
219
|
-
} catch {}
|
|
220
|
-
throw Object.values(routerErrors)[0];
|
|
221
|
-
}
|
|
222
|
-
|
|
223
|
-
await preloadMatchedRouteComponents(serverRouter);
|
|
244
|
+
)?.status(serverLoadResult.status);
|
|
224
245
|
|
|
225
|
-
|
|
226
|
-
context.ssrContext?.response as
|
|
227
|
-
| { status: (code: number) => void }
|
|
228
|
-
| undefined
|
|
229
|
-
)?.status(serverLoadResult.status);
|
|
246
|
+
await serverRouter.serverSsr?.dehydrate();
|
|
230
247
|
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
// because Modern's non-streaming hook has not rendered the app yet.
|
|
238
|
-
await waitForRouterSerialization(serverRouter);
|
|
248
|
+
if (enableRsc) {
|
|
249
|
+
setTanstackRscServerPayload(
|
|
250
|
+
createTanstackRscServerPayload(serverRouter, {
|
|
251
|
+
omitClientLoaderData: isRSCNavigation,
|
|
252
|
+
}),
|
|
253
|
+
);
|
|
239
254
|
}
|
|
240
255
|
|
|
241
|
-
|
|
242
|
-
|
|
243
|
-
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
|
|
247
|
-
|
|
248
|
-
|
|
249
|
-
|
|
250
|
-
|
|
251
|
-
const routerServerSnapshot: InternalRouterServerSnapshot =
|
|
252
|
-
createRouterServerSnapshot({
|
|
256
|
+
const initialScriptTags =
|
|
257
|
+
serverRouter.serverSsr?.takeInitialHydrationScriptTags();
|
|
258
|
+
const hydrationScripts = initialScriptTags
|
|
259
|
+
? routerManagedTagsToHtml([
|
|
260
|
+
...initialScriptTags.before,
|
|
261
|
+
initialScriptTags.boundary,
|
|
262
|
+
])
|
|
263
|
+
: [];
|
|
264
|
+
const matchedRouteIds = getModernRouteIdsFromMatches(serverRouter);
|
|
265
|
+
const routerServerSnapshot: InternalRouterServerSnapshot = {
|
|
253
266
|
framework: 'tanstack',
|
|
254
267
|
basename: _basename,
|
|
255
268
|
statusCode: serverLoadResult.status,
|
|
256
269
|
errors: routerErrors,
|
|
257
270
|
matchedRouteIds,
|
|
258
271
|
hydrationScripts,
|
|
259
|
-
}
|
|
260
|
-
|
|
261
|
-
|
|
262
|
-
|
|
263
|
-
|
|
264
|
-
|
|
265
|
-
|
|
266
|
-
|
|
267
|
-
|
|
268
|
-
|
|
269
|
-
|
|
270
|
-
|
|
271
|
-
serverSnapshot: routerServerSnapshot,
|
|
272
|
+
};
|
|
273
|
+
const runtimeContext = applyRouterServerPrepareResult(
|
|
274
|
+
context as TInternalRuntimeContext,
|
|
275
|
+
{
|
|
276
|
+
snapshot: routerServerSnapshot,
|
|
277
|
+
cleanup,
|
|
278
|
+
state: {
|
|
279
|
+
framework: 'tanstack',
|
|
280
|
+
basename: _basename,
|
|
281
|
+
instance: serverRouter,
|
|
282
|
+
navigation: createTanstackNavigation(tanstackRouter),
|
|
283
|
+
},
|
|
272
284
|
},
|
|
273
|
-
|
|
274
|
-
|
|
275
|
-
|
|
276
|
-
|
|
277
|
-
|
|
278
|
-
|
|
279
|
-
|
|
280
|
-
|
|
285
|
+
);
|
|
286
|
+
rawRequest.signal.throwIfAborted();
|
|
287
|
+
hooks.onAfterCreateRouter.call({
|
|
288
|
+
...routerLifecycleContext,
|
|
289
|
+
router: serverRouter,
|
|
290
|
+
serverSnapshot: getRouterServerSnapshot(runtimeContext),
|
|
291
|
+
runtimeContext,
|
|
292
|
+
});
|
|
293
|
+
prepared = true;
|
|
294
|
+
} finally {
|
|
295
|
+
if (!prepared) {
|
|
296
|
+
try {
|
|
297
|
+
cleanup();
|
|
298
|
+
} catch {}
|
|
299
|
+
}
|
|
300
|
+
}
|
|
281
301
|
});
|
|
282
302
|
|
|
283
303
|
api.wrapRoot(App => {
|
package/src/runtime/plugin.tsx
CHANGED
|
@@ -32,6 +32,7 @@ import {
|
|
|
32
32
|
applyRouterRuntimeState,
|
|
33
33
|
type RouterLifecycleContext,
|
|
34
34
|
} from './lifecycle';
|
|
35
|
+
import { createTanstackNavigation } from './navigation';
|
|
35
36
|
import {
|
|
36
37
|
createTanstackRouteObjects,
|
|
37
38
|
getMergedRouterConfig,
|
|
@@ -259,10 +260,15 @@ export const tanstackRouterPlugin = (
|
|
|
259
260
|
if (!router) {
|
|
260
261
|
return App ? <App /> : null;
|
|
261
262
|
}
|
|
263
|
+
const navigation = useMemo(
|
|
264
|
+
() => createTanstackNavigation(router),
|
|
265
|
+
[router],
|
|
266
|
+
);
|
|
262
267
|
const runtimeState = applyRouterRuntimeState(runtimeContext, {
|
|
263
268
|
framework: 'tanstack',
|
|
264
269
|
basename: _basename,
|
|
265
270
|
instance: router,
|
|
271
|
+
navigation,
|
|
266
272
|
});
|
|
267
273
|
const lifecycleContext: RouterLifecycleContext = {
|
|
268
274
|
framework: 'tanstack',
|
|
@@ -1,11 +1,14 @@
|
|
|
1
1
|
// @effect-diagnostics asyncFunction:off strictBooleanExpressions:off
|
|
2
2
|
|
|
3
|
-
import { canonicaliseLocalisedRoutes } from '@modern-js/i18n-runtime-extensions';
|
|
4
3
|
import { DefaultNotFound } from '@modern-js/runtime/context';
|
|
5
4
|
import type { RouteObject } from '@modern-js/runtime-utils/router';
|
|
6
5
|
import type { AnyRoute, AnyRouter } from '@tanstack/react-router';
|
|
7
6
|
import { rootRouteId } from '@tanstack/react-router';
|
|
8
7
|
|
|
8
|
+
import {
|
|
9
|
+
describeRouteTree,
|
|
10
|
+
type RouteDescriptor,
|
|
11
|
+
} from '../../shared/routeDescriptor';
|
|
9
12
|
import { createRouteStaticData } from '../../shared/routeStaticData';
|
|
10
13
|
import { withModernRouteMatchContext } from '../outlet';
|
|
11
14
|
import {
|
|
@@ -14,7 +17,6 @@ import {
|
|
|
14
17
|
toRouteComponent,
|
|
15
18
|
} from './components';
|
|
16
19
|
import { createModernShouldReload, wrapRouteObjectLoader } from './loaders';
|
|
17
|
-
import { isRouteObjectPathlessLayout, toTanstackPath } from './paths';
|
|
18
20
|
import { mergeModernRouteHandle } from './staticData';
|
|
19
21
|
import {
|
|
20
22
|
createTanstackRootRoute,
|
|
@@ -24,25 +26,16 @@ import {
|
|
|
24
26
|
import type {
|
|
25
27
|
ModernRouteObject,
|
|
26
28
|
ModernTanstackRootRoute,
|
|
27
|
-
MutableTanstackRoute,
|
|
28
29
|
RouteRevalidationState,
|
|
29
30
|
RouteTreeOptions,
|
|
30
31
|
TanstackRootRouteOptions,
|
|
31
32
|
TanstackRouteOptions,
|
|
32
33
|
} from './types';
|
|
33
34
|
|
|
34
|
-
function
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
routeObject: RouteObject;
|
|
39
|
-
}): AnyRoute {
|
|
40
|
-
const {
|
|
41
|
-
options = {},
|
|
42
|
-
parent,
|
|
43
|
-
pathlessFallbackId = 'pathless',
|
|
44
|
-
routeObject,
|
|
45
|
-
} = opts;
|
|
35
|
+
function createRouteOptions(
|
|
36
|
+
routeObject: RouteObject,
|
|
37
|
+
options: RouteTreeOptions,
|
|
38
|
+
): TanstackRouteOptions {
|
|
46
39
|
const modernRouteObject = routeObject as ModernRouteObject;
|
|
47
40
|
const revalidationState: RouteRevalidationState = {};
|
|
48
41
|
const shouldRevalidate = modernRouteObject.shouldRevalidate;
|
|
@@ -50,13 +43,8 @@ function createRouteFromRouteObject(opts: {
|
|
|
50
43
|
shouldRevalidate,
|
|
51
44
|
revalidationState,
|
|
52
45
|
);
|
|
53
|
-
|
|
54
|
-
const stableFallbackId =
|
|
55
|
-
routeObject.id || modernRouteObject.file || pathlessFallbackId;
|
|
56
|
-
|
|
57
46
|
const component = toRouteComponent(routeObject);
|
|
58
47
|
const base: TanstackRouteOptions = {
|
|
59
|
-
getParentRoute: () => parent,
|
|
60
48
|
component,
|
|
61
49
|
pendingComponent: toPendingComponent(routeObject),
|
|
62
50
|
errorComponent: toErrorComponent(routeObject),
|
|
@@ -87,117 +75,49 @@ function createRouteFromRouteObject(opts: {
|
|
|
87
75
|
base.shouldReload = shouldReload;
|
|
88
76
|
}
|
|
89
77
|
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
} else {
|
|
93
|
-
base.path = routeObject.index
|
|
94
|
-
? '/'
|
|
95
|
-
: toTanstackPath((routeObject.path as string) || '');
|
|
96
|
-
}
|
|
97
|
-
|
|
98
|
-
const route = createTanstackRoute(base);
|
|
99
|
-
wrapRouteComponentWithModernContext(route, component, routeObject.id);
|
|
78
|
+
return base;
|
|
79
|
+
}
|
|
100
80
|
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
81
|
+
function createRouteFromDescriptor(
|
|
82
|
+
descriptor: RouteDescriptor<RouteObject>,
|
|
83
|
+
parent: AnyRoute,
|
|
84
|
+
options: RouteTreeOptions,
|
|
85
|
+
): AnyRoute {
|
|
86
|
+
const { source, location, children } = descriptor;
|
|
87
|
+
const routeOptions = createRouteOptions(source, options);
|
|
88
|
+
const route = createTanstackRoute({
|
|
89
|
+
...routeOptions,
|
|
90
|
+
...location,
|
|
91
|
+
getParentRoute: () => parent,
|
|
92
|
+
});
|
|
93
|
+
wrapRouteComponentWithModernContext(route, routeOptions.component, source.id);
|
|
94
|
+
if (children.length) {
|
|
95
|
+
route.addChildren(
|
|
96
|
+
children.map(child => createRouteFromDescriptor(child, route, options)),
|
|
110
97
|
);
|
|
111
|
-
route.addChildren(childRoutes);
|
|
112
98
|
}
|
|
113
|
-
|
|
114
99
|
return route;
|
|
115
100
|
}
|
|
116
101
|
|
|
117
|
-
function getRootLikeRouteObject(routes: RouteObject[]) {
|
|
118
|
-
return routes.find(route => route.path === '/' && !route.index);
|
|
119
|
-
}
|
|
120
|
-
|
|
121
102
|
export function createRouteTreeFromRouteObjects(
|
|
122
103
|
routes: RouteObject[],
|
|
123
104
|
options: RouteTreeOptions = {},
|
|
124
105
|
): ModernTanstackRootRoute {
|
|
125
|
-
|
|
126
|
-
const rootLikeRoute = getRootLikeRouteObject(routes) as
|
|
127
|
-
| ModernRouteObject
|
|
128
|
-
| undefined;
|
|
129
|
-
const rootRevalidationState: RouteRevalidationState = {};
|
|
130
|
-
const rootShouldRevalidate = rootLikeRoute?.shouldRevalidate;
|
|
131
|
-
const rootShouldReload = createModernShouldReload(
|
|
132
|
-
rootShouldRevalidate,
|
|
133
|
-
rootRevalidationState,
|
|
134
|
-
);
|
|
135
|
-
|
|
136
|
-
const rootComponent = rootLikeRoute
|
|
137
|
-
? toRouteComponent(rootLikeRoute)
|
|
138
|
-
: undefined;
|
|
106
|
+
const { root, children } = describeRouteTree(routes);
|
|
139
107
|
const rootRouteOptions: TanstackRootRouteOptions = {
|
|
140
|
-
|
|
141
|
-
pendingComponent: rootLikeRoute
|
|
142
|
-
? toPendingComponent(rootLikeRoute)
|
|
143
|
-
: undefined,
|
|
144
|
-
errorComponent: rootLikeRoute ? toErrorComponent(rootLikeRoute) : undefined,
|
|
145
|
-
validateSearch: rootLikeRoute?.validateSearch,
|
|
146
|
-
loaderDeps: rootLikeRoute?.loaderDeps,
|
|
108
|
+
...(root ? createRouteOptions(root, options) : {}),
|
|
147
109
|
notFoundComponent: DefaultNotFound,
|
|
148
|
-
staticData: createRouteStaticData({
|
|
149
|
-
modernRouteId: rootLikeRoute?.id,
|
|
150
|
-
modernRouteAction: rootLikeRoute?.action,
|
|
151
|
-
modernRouteHandle: rootLikeRoute
|
|
152
|
-
? mergeModernRouteHandle(rootLikeRoute)
|
|
153
|
-
: undefined,
|
|
154
|
-
modernRouteHasAction:
|
|
155
|
-
rootLikeRoute?.hasAction || Boolean(rootLikeRoute?.action),
|
|
156
|
-
modernRouteHasClientLoader:
|
|
157
|
-
rootLikeRoute?.hasClientLoader ||
|
|
158
|
-
typeof rootLikeRoute?.clientData !== 'undefined',
|
|
159
|
-
modernRouteHasLoader:
|
|
160
|
-
rootLikeRoute?.hasLoader || typeof rootLikeRoute?.loader === 'function',
|
|
161
|
-
modernRouteIsClientComponent: rootLikeRoute?.isClientComponent,
|
|
162
|
-
modernRouteLoader: rootLikeRoute?.loader,
|
|
163
|
-
modernRouteShouldRevalidate: rootShouldRevalidate,
|
|
164
|
-
}),
|
|
165
|
-
loader: rootLikeRoute
|
|
166
|
-
? wrapRouteObjectLoader(rootLikeRoute, rootRevalidationState, options)
|
|
167
|
-
: undefined,
|
|
168
110
|
};
|
|
169
|
-
if (rootShouldReload) {
|
|
170
|
-
rootRouteOptions.shouldReload = rootShouldReload;
|
|
171
|
-
}
|
|
172
|
-
if (rootLikeRoute?.inValidSSRRoute) {
|
|
173
|
-
rootRouteOptions.ssr = false;
|
|
174
|
-
}
|
|
175
|
-
|
|
176
111
|
const rootRoute = createTanstackRootRoute(rootRouteOptions);
|
|
177
|
-
if (
|
|
112
|
+
if (rootRouteOptions.component) {
|
|
178
113
|
rootRoute.options.component = withModernRouteMatchContext(
|
|
179
|
-
|
|
114
|
+
rootRouteOptions.component,
|
|
180
115
|
rootRouteId,
|
|
181
116
|
) as typeof rootRoute.options.component;
|
|
182
117
|
}
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
? [
|
|
186
|
-
...((rootLikeRoute.children as RouteObject[] | undefined) || []),
|
|
187
|
-
...routes.filter(route => route !== rootLikeRoute),
|
|
188
|
-
]
|
|
189
|
-
: routes;
|
|
190
|
-
|
|
191
|
-
const childRoutes = topLevel.map((routeObject, index) =>
|
|
192
|
-
createRouteFromRouteObject({
|
|
193
|
-
options,
|
|
194
|
-
parent: rootRoute,
|
|
195
|
-
pathlessFallbackId: `pathless-${index}`,
|
|
196
|
-
routeObject,
|
|
197
|
-
}),
|
|
118
|
+
rootRoute.addChildren(
|
|
119
|
+
children.map(child => createRouteFromDescriptor(child, rootRoute, options)),
|
|
198
120
|
);
|
|
199
|
-
|
|
200
|
-
rootRoute.addChildren(childRoutes);
|
|
201
121
|
return rootRoute as unknown as ModernTanstackRootRoute;
|
|
202
122
|
}
|
|
203
123
|
|
|
@@ -3,6 +3,7 @@
|
|
|
3
3
|
import type { RouteObject } from '@modern-js/runtime-utils/router';
|
|
4
4
|
import {
|
|
5
5
|
getLoaderHref,
|
|
6
|
+
getLoaderSignal,
|
|
6
7
|
handleModernLoaderError,
|
|
7
8
|
handleModernLoaderResult,
|
|
8
9
|
mapSplatParamsForModernLoader,
|
|
@@ -118,10 +119,7 @@ export function wrapRouteObjectLoader(
|
|
|
118
119
|
} catch {}
|
|
119
120
|
}
|
|
120
121
|
|
|
121
|
-
const signal
|
|
122
|
-
ctx?.abortController?.signal ||
|
|
123
|
-
ctx?.signal ||
|
|
124
|
-
new AbortController().signal;
|
|
122
|
+
const signal = getLoaderSignal(ctx);
|
|
125
123
|
const baseRequest: Request | undefined =
|
|
126
124
|
ctx?.context?.request instanceof Request
|
|
127
125
|
? ctx.context.request
|
|
@@ -1,7 +1,5 @@
|
|
|
1
1
|
// @effect-diagnostics asyncFunction:off strictBooleanExpressions:off
|
|
2
2
|
|
|
3
|
-
import type { RouteObject } from '@modern-js/runtime-utils/router';
|
|
4
|
-
|
|
5
3
|
export function toTanstackPath(pathname: string): string {
|
|
6
4
|
// TanStack Router uses `$param` and `$` (splat) style params.
|
|
7
5
|
// Modern's conventional routing currently generates React Router style params (e.g. `:id`, `*`).
|
|
@@ -30,7 +28,3 @@ export function toTanstackPath(pathname: string): string {
|
|
|
30
28
|
})
|
|
31
29
|
.join('/');
|
|
32
30
|
}
|
|
33
|
-
|
|
34
|
-
export function isRouteObjectPathlessLayout(route: RouteObject) {
|
|
35
|
-
return !route.path && !route.index;
|
|
36
|
-
}
|
|
@@ -6,23 +6,6 @@ import type {
|
|
|
6
6
|
TanstackRouterWithServerSsr,
|
|
7
7
|
} from './ssrTypes';
|
|
8
8
|
|
|
9
|
-
export async function waitForRouterSerialization(
|
|
10
|
-
tanstackRouter: TanstackRouterWithServerSsr,
|
|
11
|
-
) {
|
|
12
|
-
const serverSsr = tanstackRouter.serverSsr;
|
|
13
|
-
if (
|
|
14
|
-
!serverSsr ||
|
|
15
|
-
typeof serverSsr.onSerializationFinished !== 'function' ||
|
|
16
|
-
serverSsr.isSerializationFinished?.()
|
|
17
|
-
) {
|
|
18
|
-
return;
|
|
19
|
-
}
|
|
20
|
-
|
|
21
|
-
await new Promise<void>(resolve => {
|
|
22
|
-
serverSsr.onSerializationFinished?.(resolve);
|
|
23
|
-
});
|
|
24
|
-
}
|
|
25
|
-
|
|
26
9
|
function htmlEscapeAttr(value: string) {
|
|
27
10
|
return value.replace(/&/g, '&').replace(/"/g, '"');
|
|
28
11
|
}
|
package/src/runtime/ssrTypes.ts
CHANGED
|
@@ -34,13 +34,6 @@ type RouterRouteWithOptions = {
|
|
|
34
34
|
|
|
35
35
|
export type TanstackRouterWithServerSsr = AnyRouter & {
|
|
36
36
|
routesById?: Record<string, RouterRouteWithOptions>;
|
|
37
|
-
serverSsr?: {
|
|
38
|
-
cleanup?: () => void;
|
|
39
|
-
dehydrate?: () => Promise<void> | void;
|
|
40
|
-
isSerializationFinished?: () => boolean;
|
|
41
|
-
onSerializationFinished?: (listener: () => void) => void;
|
|
42
|
-
takeBufferedScripts?: () => unknown;
|
|
43
|
-
};
|
|
44
37
|
state: AnyRouter['state'] & {
|
|
45
38
|
matches?: unknown;
|
|
46
39
|
};
|
package/src/runtime/utils.tsx
CHANGED
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
import { toTanstackPath } from '../runtime/routeTree/paths';
|
|
2
|
+
|
|
3
|
+
type RouteShape = {
|
|
4
|
+
id?: string;
|
|
5
|
+
file?: string;
|
|
6
|
+
path?: string;
|
|
7
|
+
index?: boolean;
|
|
8
|
+
isRoot?: boolean;
|
|
9
|
+
children?: RouteShape[];
|
|
10
|
+
};
|
|
11
|
+
|
|
12
|
+
/** Browser-safe structure shared by the executable tree and concrete TS emitter. */
|
|
13
|
+
export type RouteDescriptor<T extends RouteShape> = {
|
|
14
|
+
source: T;
|
|
15
|
+
location: { id: string; path?: never } | { path: string; id?: never };
|
|
16
|
+
hasSplat: boolean;
|
|
17
|
+
children: RouteDescriptor<T>[];
|
|
18
|
+
};
|
|
19
|
+
|
|
20
|
+
export function describeRouteTree<T extends RouteShape>(routes: T[]) {
|
|
21
|
+
const root = routes.find(
|
|
22
|
+
route =>
|
|
23
|
+
route.isRoot === true || (route.path === '/' && route.index !== true),
|
|
24
|
+
);
|
|
25
|
+
const describe = (route: T, index: number): RouteDescriptor<T> => ({
|
|
26
|
+
source: route,
|
|
27
|
+
location:
|
|
28
|
+
(route.path ?? '').length === 0 && route.index !== true
|
|
29
|
+
? { id: route.id || route.file || `pathless-${index}` }
|
|
30
|
+
: {
|
|
31
|
+
path: route.index === true ? '/' : toTanstackPath(route.path || ''),
|
|
32
|
+
},
|
|
33
|
+
hasSplat: Boolean(route.path?.includes('*')),
|
|
34
|
+
children: ((route.children ?? []) as T[]).map(describe),
|
|
35
|
+
});
|
|
36
|
+
return {
|
|
37
|
+
root,
|
|
38
|
+
children: (root !== undefined
|
|
39
|
+
? [
|
|
40
|
+
...((root.children ?? []) as T[]),
|
|
41
|
+
...routes.filter(route => route !== root),
|
|
42
|
+
]
|
|
43
|
+
: routes
|
|
44
|
+
).map(describe),
|
|
45
|
+
};
|
|
46
|
+
}
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
import type { AnyRouter } from '@tanstack/react-router';
|
|
2
|
+
|
|
3
|
+
// Router-core navigates only on the client. Node tests perform the same
|
|
4
|
+
// transition a mounted RouterProvider runs: push the rewritten public URL,
|
|
5
|
+
// then load it.
|
|
6
|
+
export async function navigateOnClient(
|
|
7
|
+
router: AnyRouter,
|
|
8
|
+
options: Parameters<AnyRouter['buildLocation']>[0],
|
|
9
|
+
) {
|
|
10
|
+
router.history.push(router.buildLocation(options).publicHref);
|
|
11
|
+
router.updateLatestLocation();
|
|
12
|
+
await router.load();
|
|
13
|
+
}
|