@bleedingdev/modern-js-plugin-tanstack 3.9.0-ultramodern.9 → 3.9.3-ultramodern.1
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 +15 -1
- package/dist/cjs/cli/index.js +13 -2
- package/dist/cjs/cli/routeMetadata.js +131 -0
- package/dist/cjs/cli/rscRouteLayer.js +86 -0
- 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 +10 -1
- package/dist/cjs/runtime/plugin.node.js +89 -64
- 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 +13 -2
- package/dist/esm/cli/index.mjs +13 -11
- package/dist/esm/cli/routeMetadata.mjs +71 -0
- package/dist/esm/cli/rscRouteLayer.mjs +35 -0
- 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 +10 -1
- package/dist/esm/runtime/plugin.node.mjs +91 -66
- 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 +13 -2
- package/dist/esm-node/cli/index.mjs +13 -11
- package/dist/esm-node/cli/routeMetadata.mjs +72 -0
- package/dist/esm-node/cli/rscRouteLayer.mjs +36 -0
- 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 +10 -1
- package/dist/esm-node/runtime/plugin.node.mjs +91 -66
- 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/artifacts.d.ts +16 -7
- package/dist/types/cli/index.d.ts +1 -1
- package/dist/types/cli/routeMetadata.d.ts +18 -0
- package/dist/types/cli/rscRouteLayer.d.ts +11 -0
- package/dist/types/cli/tanstackTypes/shared.d.ts +0 -2
- package/dist/types/cli/tanstackTypes/source.d.ts +3 -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/pluginShared.d.ts +5 -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 +32 -26
- package/src/cli/artifacts.ts +59 -8
- package/src/cli/index.ts +17 -4
- package/src/cli/routeMetadata.ts +121 -0
- package/src/cli/rscRouteLayer.ts +93 -0
- package/src/cli/tanstackTypes/canonicalRoutes.ts +17 -12
- package/src/cli/tanstackTypes/shared.ts +0 -14
- package/src/cli/tanstackTypes/source.ts +48 -120
- 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 +121 -91
- package/src/runtime/plugin.tsx +10 -0
- package/src/runtime/pluginShared.ts +12 -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/dist/esm/rslib-runtime~1.mjs +0 -18
- package/dist/esm-node/rslib-runtime~0.mjs +0 -19
- package/rslib.config.mts +0 -4
- package/rstest.config.mts +0 -53
- package/tests/router/cli.test.ts +0 -420
- package/tests/router/clientHydration.test.tsx +0 -200
- package/tests/router/dataMutation.test.tsx +0 -428
- package/tests/router/fixtures/router-gen.oxlint.json +0 -5
- package/tests/router/flightSerialization.roundtrip.test.tsx +0 -140
- package/tests/router/generateRouteArtifacts.test.ts +0 -146
- package/tests/router/loaderBridge.test.ts +0 -207
- package/tests/router/localisedIdentity.test.tsx +0 -95
- package/tests/router/prefetchLink.test.tsx +0 -122
- package/tests/router/prefetchLinkPreload.test.tsx +0 -65
- package/tests/router/routeHooks.test.ts +0 -49
- package/tests/router/routeTree.test.ts +0 -240
- package/tests/router/rsc.test.tsx +0 -480
- package/tests/router/serverPlugin.test.ts +0 -157
- package/tests/router/slotUsageSanitizer.test.ts +0 -23
- package/tests/router/ssrPreload.test.ts +0 -30
- package/tests/router/tanstackTypes.test.ts +0 -384
- package/tsconfig.json +0 -12
- package/tsconfig.tsgo.json +0 -6
|
@@ -0,0 +1,78 @@
|
|
|
1
|
+
import type {
|
|
2
|
+
RouterNavigationCapability,
|
|
3
|
+
RouterNavigationSnapshot,
|
|
4
|
+
} from '@modern-js/runtime-extensions/router-state';
|
|
5
|
+
import type { AnyRouter } from '@tanstack/react-router';
|
|
6
|
+
import { Link } from './prefetchLink';
|
|
7
|
+
|
|
8
|
+
/** Native TanStack navigation, exposed through the provider contract. */
|
|
9
|
+
export function createTanstackNavigation(
|
|
10
|
+
router: AnyRouter,
|
|
11
|
+
): RouterNavigationCapability {
|
|
12
|
+
let location: AnyRouter['state']['location'] | undefined;
|
|
13
|
+
let matches: AnyRouter['state']['matches'] | undefined;
|
|
14
|
+
let snapshot: RouterNavigationSnapshot;
|
|
15
|
+
return {
|
|
16
|
+
Link: Link as RouterNavigationCapability['Link'],
|
|
17
|
+
getSnapshot() {
|
|
18
|
+
const state = router.state;
|
|
19
|
+
if (
|
|
20
|
+
location !== state.location ||
|
|
21
|
+
matches === undefined ||
|
|
22
|
+
matches.length !== state.matches.length ||
|
|
23
|
+
matches.some(
|
|
24
|
+
(match, index) => match.params !== state.matches[index]?.params,
|
|
25
|
+
)
|
|
26
|
+
) {
|
|
27
|
+
location = state.location;
|
|
28
|
+
matches = state.matches;
|
|
29
|
+
snapshot = {
|
|
30
|
+
location: {
|
|
31
|
+
pathname: location.pathname,
|
|
32
|
+
search: location.searchStr,
|
|
33
|
+
hash:
|
|
34
|
+
location.hash !== '' ? `#${location.hash.replace(/^#/, '')}` : '',
|
|
35
|
+
},
|
|
36
|
+
params: Object.assign({}, ...matches.map(match => match.params)),
|
|
37
|
+
};
|
|
38
|
+
}
|
|
39
|
+
return snapshot;
|
|
40
|
+
},
|
|
41
|
+
subscribe(listener) {
|
|
42
|
+
const stops = (
|
|
43
|
+
['onBeforeNavigate', 'onBeforeLoad', 'onLoad', 'onResolved'] as const
|
|
44
|
+
).map(event => router.subscribe(event, listener));
|
|
45
|
+
return () => {
|
|
46
|
+
for (const stop of stops) stop();
|
|
47
|
+
};
|
|
48
|
+
},
|
|
49
|
+
navigate(href, options) {
|
|
50
|
+
return router.navigate({
|
|
51
|
+
to: href,
|
|
52
|
+
replace: options?.replace,
|
|
53
|
+
...(options?.state === undefined
|
|
54
|
+
? {}
|
|
55
|
+
: { state: options.state as never }),
|
|
56
|
+
});
|
|
57
|
+
},
|
|
58
|
+
createLinkProps(target) {
|
|
59
|
+
const preload =
|
|
60
|
+
target.preload !== undefined
|
|
61
|
+
? target.preload
|
|
62
|
+
: target.prefetch === 'none'
|
|
63
|
+
? false
|
|
64
|
+
: target.prefetch;
|
|
65
|
+
return {
|
|
66
|
+
to: target.pathname,
|
|
67
|
+
...(target.search !== undefined ? { search: target.search } : {}),
|
|
68
|
+
...(target.hash !== undefined && target.hash !== ''
|
|
69
|
+
? { hash: target.hash }
|
|
70
|
+
: {}),
|
|
71
|
+
...(target.hashScrollIntoView === undefined
|
|
72
|
+
? {}
|
|
73
|
+
: { hashScrollIntoView: target.hashScrollIntoView }),
|
|
74
|
+
...(preload === undefined ? {} : { preload }),
|
|
75
|
+
};
|
|
76
|
+
},
|
|
77
|
+
};
|
|
78
|
+
}
|
|
@@ -5,6 +5,7 @@ import {
|
|
|
5
5
|
type TInternalRuntimeContext,
|
|
6
6
|
} from '@modern-js/runtime/context';
|
|
7
7
|
import type { InternalRouterServerSnapshot } from '@modern-js/runtime-extensions/router-state';
|
|
8
|
+
import { createRouterStatePlugin } from '@modern-js/runtime-extensions/router-state-plugin';
|
|
8
9
|
import {
|
|
9
10
|
createRequestContext,
|
|
10
11
|
type RequestContext,
|
|
@@ -23,11 +24,13 @@ import { createModernBasepathRewrite } from './basepathRewrite';
|
|
|
23
24
|
import { routerProviderRegistryHooks } from './hooks';
|
|
24
25
|
import { wrapTanstackSsrHydrationBoundary } from './hydrationBoundary';
|
|
25
26
|
import {
|
|
27
|
+
applyRouterRuntimeState,
|
|
26
28
|
applyRouterServerPrepareResult,
|
|
27
|
-
createRouterServerSnapshot,
|
|
28
29
|
getRouterRuntimeState,
|
|
30
|
+
getRouterServerSnapshot,
|
|
29
31
|
type RouterLifecycleContext,
|
|
30
32
|
} from './lifecycle';
|
|
33
|
+
import { createTanstackNavigation } from './navigation';
|
|
31
34
|
import {
|
|
32
35
|
createTanstackRouteObjects,
|
|
33
36
|
getTanstackRouteConfig,
|
|
@@ -54,7 +57,6 @@ import {
|
|
|
54
57
|
collectRouterErrors,
|
|
55
58
|
createGetSsrHref,
|
|
56
59
|
routerManagedTagsToHtml,
|
|
57
|
-
waitForRouterSerialization,
|
|
58
60
|
} from './ssrManagedTags';
|
|
59
61
|
import { preloadMatchedRouteComponents } from './ssrPreload';
|
|
60
62
|
import type {
|
|
@@ -73,6 +75,9 @@ export const tanstackRouterPlugin = (
|
|
|
73
75
|
name: '@modern-js/plugin-router-tanstack',
|
|
74
76
|
registryHooks: routerProviderRegistryHooks,
|
|
75
77
|
setup: (api: TanstackRouterPluginAPI) => {
|
|
78
|
+
createRouterStatePlugin({
|
|
79
|
+
registryHooks: routerProviderRegistryHooks,
|
|
80
|
+
}).setup(api);
|
|
76
81
|
api.onBeforeRender(async (context, interrupt) => {
|
|
77
82
|
const routeConfig = getTanstackRouteConfig(api, userConfig);
|
|
78
83
|
const { mergedConfig } = routeConfig;
|
|
@@ -168,116 +173,141 @@ export const tanstackRouterPlugin = (
|
|
|
168
173
|
setTanstackRscRouter(serverRouter);
|
|
169
174
|
}
|
|
170
175
|
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
const
|
|
174
|
-
|
|
176
|
+
let disposed = false;
|
|
177
|
+
let prepared = false;
|
|
178
|
+
const onAbort = () => controller.abort(rawRequest.signal.reason);
|
|
179
|
+
const cleanup = () => {
|
|
180
|
+
if (disposed) return;
|
|
181
|
+
disposed = true;
|
|
182
|
+
rawRequest.signal.removeEventListener('abort', onAbort);
|
|
183
|
+
controller.abort();
|
|
184
|
+
serverRouter.serverSsr?.cleanup();
|
|
185
|
+
};
|
|
186
|
+
// Acquire the disposer before attachment: every subsequent failure,
|
|
187
|
+
// including partial attachment, has an owner. Successful preparation
|
|
188
|
+
// leaves disposal to the response lifetime in the SSR pipeline.
|
|
189
|
+
applyRouterRuntimeState(context, {
|
|
190
|
+
framework: 'tanstack',
|
|
191
|
+
basename: _basename,
|
|
192
|
+
instance: serverRouter,
|
|
193
|
+
cleanup,
|
|
194
|
+
});
|
|
195
|
+
rawRequest.signal.addEventListener('abort', onAbort, { once: true });
|
|
175
196
|
try {
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
197
|
+
rawRequest.signal.throwIfAborted();
|
|
198
|
+
await attachServerSsrUtils(serverRouter);
|
|
199
|
+
rawRequest.signal.throwIfAborted();
|
|
200
|
+
|
|
201
|
+
const end = time();
|
|
181
202
|
|
|
182
|
-
const serverLoadResult = serverRouter._serverResult;
|
|
183
|
-
if (!serverLoadResult) {
|
|
184
203
|
try {
|
|
185
|
-
|
|
186
|
-
}
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
}
|
|
204
|
+
await tanstackRouter.load({ sync: true });
|
|
205
|
+
} finally {
|
|
206
|
+
const cost = end();
|
|
207
|
+
context.ssrContext?.onTiming?.(LOADER_REPORTER_NAME, cost);
|
|
208
|
+
}
|
|
191
209
|
|
|
192
|
-
|
|
193
|
-
const
|
|
210
|
+
rawRequest.signal.throwIfAborted();
|
|
211
|
+
const serverLoadResult = serverRouter._serverResult;
|
|
212
|
+
if (!serverLoadResult) {
|
|
213
|
+
throw new Error(
|
|
214
|
+
'TanStack Router completed an SSR load without a server result.',
|
|
215
|
+
);
|
|
216
|
+
}
|
|
194
217
|
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
218
|
+
if (serverLoadResult.type === 'redirect') {
|
|
219
|
+
const { redirect } = serverLoadResult;
|
|
220
|
+
|
|
221
|
+
return interrupt(
|
|
222
|
+
isRSCNavigation
|
|
223
|
+
? handleTanstackRscRedirect(
|
|
224
|
+
redirect.headers,
|
|
225
|
+
_basename,
|
|
226
|
+
redirect.status,
|
|
227
|
+
)
|
|
228
|
+
: redirect,
|
|
229
|
+
);
|
|
230
|
+
}
|
|
231
|
+
|
|
232
|
+
const routerErrors = collectRouterErrors(tanstackRouter);
|
|
233
|
+
if (routerErrors && loaderFailureMode === 'clientRender') {
|
|
234
|
+
(
|
|
235
|
+
context.ssrContext?.response as
|
|
236
|
+
| { status: (code: number) => void }
|
|
237
|
+
| undefined
|
|
238
|
+
)?.status(200);
|
|
239
|
+
throw Object.values(routerErrors)[0];
|
|
240
|
+
}
|
|
241
|
+
|
|
242
|
+
await preloadMatchedRouteComponents(serverRouter);
|
|
209
243
|
|
|
210
|
-
const routerErrors = collectRouterErrors(tanstackRouter);
|
|
211
|
-
if (routerErrors && loaderFailureMode === 'clientRender') {
|
|
212
244
|
(
|
|
213
245
|
context.ssrContext?.response as
|
|
214
246
|
| { status: (code: number) => void }
|
|
215
247
|
| undefined
|
|
216
|
-
)?.status(
|
|
217
|
-
try {
|
|
218
|
-
serverRouter.serverSsr?.cleanup?.();
|
|
219
|
-
} catch {}
|
|
220
|
-
throw Object.values(routerErrors)[0];
|
|
221
|
-
}
|
|
222
|
-
|
|
223
|
-
await preloadMatchedRouteComponents(serverRouter);
|
|
224
|
-
|
|
225
|
-
(
|
|
226
|
-
context.ssrContext?.response as
|
|
227
|
-
| { status: (code: number) => void }
|
|
228
|
-
| undefined
|
|
229
|
-
)?.status(serverLoadResult.status);
|
|
248
|
+
)?.status(serverLoadResult.status);
|
|
230
249
|
|
|
231
|
-
|
|
250
|
+
await serverRouter.serverSsr?.dehydrate();
|
|
232
251
|
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
|
|
252
|
+
if (enableRsc) {
|
|
253
|
+
setTanstackRscServerPayload(
|
|
254
|
+
createTanstackRscServerPayload(serverRouter, {
|
|
255
|
+
omitClientLoaderData: isRSCNavigation,
|
|
256
|
+
}),
|
|
257
|
+
);
|
|
258
|
+
if (isRSCNavigation) {
|
|
259
|
+
context.ssrContext!.response.setHeader(
|
|
260
|
+
'Content-Type',
|
|
261
|
+
'text/x-component',
|
|
262
|
+
);
|
|
263
|
+
}
|
|
239
264
|
}
|
|
240
265
|
|
|
241
|
-
|
|
242
|
-
|
|
243
|
-
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
|
|
247
|
-
|
|
248
|
-
|
|
249
|
-
|
|
250
|
-
|
|
251
|
-
const routerServerSnapshot: InternalRouterServerSnapshot =
|
|
252
|
-
createRouterServerSnapshot({
|
|
266
|
+
const initialScriptTags =
|
|
267
|
+
serverRouter.serverSsr?.takeInitialHydrationScriptTags();
|
|
268
|
+
const hydrationScripts = initialScriptTags
|
|
269
|
+
? routerManagedTagsToHtml([
|
|
270
|
+
...initialScriptTags.before,
|
|
271
|
+
initialScriptTags.boundary,
|
|
272
|
+
])
|
|
273
|
+
: [];
|
|
274
|
+
const matchedRouteIds = getModernRouteIdsFromMatches(serverRouter);
|
|
275
|
+
const routerServerSnapshot: InternalRouterServerSnapshot = {
|
|
253
276
|
framework: 'tanstack',
|
|
254
277
|
basename: _basename,
|
|
255
278
|
statusCode: serverLoadResult.status,
|
|
256
279
|
errors: routerErrors,
|
|
257
280
|
matchedRouteIds,
|
|
258
281
|
hydrationScripts,
|
|
259
|
-
}
|
|
260
|
-
|
|
261
|
-
|
|
262
|
-
|
|
263
|
-
|
|
264
|
-
|
|
265
|
-
|
|
266
|
-
|
|
267
|
-
|
|
268
|
-
|
|
269
|
-
|
|
270
|
-
|
|
271
|
-
serverSnapshot: routerServerSnapshot,
|
|
282
|
+
};
|
|
283
|
+
const runtimeContext = applyRouterServerPrepareResult(
|
|
284
|
+
context as TInternalRuntimeContext,
|
|
285
|
+
{
|
|
286
|
+
snapshot: routerServerSnapshot,
|
|
287
|
+
cleanup,
|
|
288
|
+
state: {
|
|
289
|
+
framework: 'tanstack',
|
|
290
|
+
basename: _basename,
|
|
291
|
+
instance: serverRouter,
|
|
292
|
+
navigation: createTanstackNavigation(tanstackRouter),
|
|
293
|
+
},
|
|
272
294
|
},
|
|
273
|
-
|
|
274
|
-
|
|
275
|
-
|
|
276
|
-
|
|
277
|
-
|
|
278
|
-
|
|
279
|
-
|
|
280
|
-
|
|
295
|
+
);
|
|
296
|
+
rawRequest.signal.throwIfAborted();
|
|
297
|
+
hooks.onAfterCreateRouter.call({
|
|
298
|
+
...routerLifecycleContext,
|
|
299
|
+
router: serverRouter,
|
|
300
|
+
serverSnapshot: getRouterServerSnapshot(runtimeContext),
|
|
301
|
+
runtimeContext,
|
|
302
|
+
});
|
|
303
|
+
prepared = true;
|
|
304
|
+
} finally {
|
|
305
|
+
if (!prepared) {
|
|
306
|
+
try {
|
|
307
|
+
cleanup();
|
|
308
|
+
} catch {}
|
|
309
|
+
}
|
|
310
|
+
}
|
|
281
311
|
});
|
|
282
312
|
|
|
283
313
|
api.wrapRoot(App => {
|
package/src/runtime/plugin.tsx
CHANGED
|
@@ -4,6 +4,7 @@ import {
|
|
|
4
4
|
InternalRuntimeContext,
|
|
5
5
|
type TInternalRuntimeContext,
|
|
6
6
|
} from '@modern-js/runtime/context';
|
|
7
|
+
import { createRouterStatePlugin } from '@modern-js/runtime-extensions/router-state-plugin';
|
|
7
8
|
import type { RouteObject } from '@modern-js/runtime-utils/router';
|
|
8
9
|
import { normalizePathname } from '@modern-js/runtime-utils/url';
|
|
9
10
|
import {
|
|
@@ -32,6 +33,7 @@ import {
|
|
|
32
33
|
applyRouterRuntimeState,
|
|
33
34
|
type RouterLifecycleContext,
|
|
34
35
|
} from './lifecycle';
|
|
36
|
+
import { createTanstackNavigation } from './navigation';
|
|
35
37
|
import {
|
|
36
38
|
createTanstackRouteObjects,
|
|
37
39
|
getMergedRouterConfig,
|
|
@@ -56,6 +58,9 @@ export const tanstackRouterPlugin = (
|
|
|
56
58
|
name: '@modern-js/plugin-router-tanstack',
|
|
57
59
|
registryHooks: routerProviderRegistryHooks,
|
|
58
60
|
setup: (api: TanstackRouterPluginAPI) => {
|
|
61
|
+
createRouterStatePlugin({
|
|
62
|
+
registryHooks: routerProviderRegistryHooks,
|
|
63
|
+
}).setup(api);
|
|
59
64
|
const hooks = api.getHooks();
|
|
60
65
|
let cachedRouteObjects: RouteObject[] | undefined;
|
|
61
66
|
let cachedRouteTree: ReturnType<
|
|
@@ -259,10 +264,15 @@ export const tanstackRouterPlugin = (
|
|
|
259
264
|
if (!router) {
|
|
260
265
|
return App ? <App /> : null;
|
|
261
266
|
}
|
|
267
|
+
const navigation = useMemo(
|
|
268
|
+
() => createTanstackNavigation(router),
|
|
269
|
+
[router],
|
|
270
|
+
);
|
|
262
271
|
const runtimeState = applyRouterRuntimeState(runtimeContext, {
|
|
263
272
|
framework: 'tanstack',
|
|
264
273
|
basename: _basename,
|
|
265
274
|
instance: router,
|
|
275
|
+
navigation,
|
|
266
276
|
});
|
|
267
277
|
const lifecycleContext: RouterLifecycleContext = {
|
|
268
278
|
framework: 'tanstack',
|
|
@@ -1,3 +1,7 @@
|
|
|
1
|
+
import type {
|
|
2
|
+
OnRenderPreparedFn,
|
|
3
|
+
OnRequestEndFn,
|
|
4
|
+
} from '@modern-js/plugin/runtime';
|
|
1
5
|
import {
|
|
2
6
|
getGlobalLayoutApp,
|
|
3
7
|
getGlobalRoutes,
|
|
@@ -6,6 +10,7 @@ import {
|
|
|
6
10
|
import { merge } from '@modern-js/runtime-utils/merge';
|
|
7
11
|
import type { RouteObject } from '@modern-js/runtime-utils/router';
|
|
8
12
|
import type { RouterExtendsHooks } from './hooks';
|
|
13
|
+
import type { RouterLifecycleContext } from './lifecycle';
|
|
9
14
|
import type { RouterConfig } from './types';
|
|
10
15
|
import { createTanstackRouteObjectsFromConfig } from './utils';
|
|
11
16
|
|
|
@@ -26,6 +31,13 @@ export type TanstackRouterPluginAPI = {
|
|
|
26
31
|
interrupt: RuntimeInterrupt,
|
|
27
32
|
) => unknown,
|
|
28
33
|
) => void;
|
|
34
|
+
onRenderPrepared: (
|
|
35
|
+
listener: OnRenderPreparedFn<TInternalRuntimeContext>,
|
|
36
|
+
) => void;
|
|
37
|
+
onRequestEnd: (listener: OnRequestEndFn<TInternalRuntimeContext>) => void;
|
|
38
|
+
onAfterCreateRouter: (
|
|
39
|
+
listener: (event: RouterLifecycleContext) => void,
|
|
40
|
+
) => void;
|
|
29
41
|
wrapRoot: (listener: (App: any) => any) => void;
|
|
30
42
|
[key: string]: any;
|
|
31
43
|
};
|
|
@@ -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
|
-
}
|