@bleedingdev/modern-js-plugin-tanstack 3.9.0-ultramodern.11 → 3.9.0-ultramodern.12
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 +82 -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/utils.js +1 -0
- package/dist/cjs/shared/routeDescriptor.js +60 -0
- package/dist/esm/cli/artifacts.mjs +2 -1
- 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/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/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/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/shared/routeDescriptor.d.ts +26 -0
- package/package.json +12 -12
- 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 -89
- 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/utils.tsx +1 -0
- package/src/shared/routeDescriptor.ts +46 -0
- package/tests/router/generateRouteArtifacts.test.ts +36 -2
- package/tests/router/localisedIdentity.test.tsx +1 -0
- package/tests/router/prefetchLink.test.tsx +29 -0
- package/tests/router/serverPlugin.test.ts +145 -0
- package/tests/router/tanstackTypes.test.ts +120 -2
|
@@ -0,0 +1,65 @@
|
|
|
1
|
+
import "node:module";
|
|
2
|
+
import { Link } from "./prefetchLink.mjs";
|
|
3
|
+
function createTanstackNavigation(router) {
|
|
4
|
+
let location;
|
|
5
|
+
let matches;
|
|
6
|
+
let snapshot;
|
|
7
|
+
return {
|
|
8
|
+
Link: Link,
|
|
9
|
+
getSnapshot () {
|
|
10
|
+
const state = router.state;
|
|
11
|
+
if (location !== state.location || void 0 === matches || matches.length !== state.matches.length || matches.some((match, index)=>match.params !== state.matches[index]?.params)) {
|
|
12
|
+
location = state.location;
|
|
13
|
+
matches = state.matches;
|
|
14
|
+
snapshot = {
|
|
15
|
+
location: {
|
|
16
|
+
pathname: location.pathname,
|
|
17
|
+
search: location.searchStr,
|
|
18
|
+
hash: '' !== location.hash ? `#${location.hash.replace(/^#/, '')}` : ''
|
|
19
|
+
},
|
|
20
|
+
params: Object.assign({}, ...matches.map((match)=>match.params))
|
|
21
|
+
};
|
|
22
|
+
}
|
|
23
|
+
return snapshot;
|
|
24
|
+
},
|
|
25
|
+
subscribe (listener) {
|
|
26
|
+
const stops = [
|
|
27
|
+
'onBeforeNavigate',
|
|
28
|
+
'onBeforeLoad',
|
|
29
|
+
'onLoad',
|
|
30
|
+
'onResolved'
|
|
31
|
+
].map((event)=>router.subscribe(event, listener));
|
|
32
|
+
return ()=>{
|
|
33
|
+
for (const stop of stops)stop();
|
|
34
|
+
};
|
|
35
|
+
},
|
|
36
|
+
navigate (href, options) {
|
|
37
|
+
return router.navigate({
|
|
38
|
+
to: href,
|
|
39
|
+
replace: options?.replace,
|
|
40
|
+
...options?.state === void 0 ? {} : {
|
|
41
|
+
state: options.state
|
|
42
|
+
}
|
|
43
|
+
});
|
|
44
|
+
},
|
|
45
|
+
createLinkProps (target) {
|
|
46
|
+
const preload = void 0 !== target.preload ? target.preload : 'none' === target.prefetch ? false : target.prefetch;
|
|
47
|
+
return {
|
|
48
|
+
to: target.pathname,
|
|
49
|
+
...void 0 !== target.search ? {
|
|
50
|
+
search: target.search
|
|
51
|
+
} : {},
|
|
52
|
+
...void 0 !== target.hash && '' !== target.hash ? {
|
|
53
|
+
hash: target.hash
|
|
54
|
+
} : {},
|
|
55
|
+
...void 0 === target.hashScrollIntoView ? {} : {
|
|
56
|
+
hashScrollIntoView: target.hashScrollIntoView
|
|
57
|
+
},
|
|
58
|
+
...void 0 === preload ? {} : {
|
|
59
|
+
preload
|
|
60
|
+
}
|
|
61
|
+
};
|
|
62
|
+
}
|
|
63
|
+
};
|
|
64
|
+
}
|
|
65
|
+
export { createTanstackNavigation };
|
|
@@ -11,6 +11,7 @@ import { ModernRouterClient, getTanstackSsrHydrationPromise, hasTanstackSsrHydra
|
|
|
11
11
|
import { routerProviderRegistryHooks } from "./hooks.mjs";
|
|
12
12
|
import { wrapTanstackSsrHydrationBoundary } from "./hydrationBoundary.mjs";
|
|
13
13
|
import { applyRouterRuntimeState } from "./lifecycle.mjs";
|
|
14
|
+
import { createTanstackNavigation } from "./navigation.mjs";
|
|
14
15
|
import { createTanstackRouteObjects, getMergedRouterConfig, getTanstackRouteConfig, joinBasename } from "./pluginShared.mjs";
|
|
15
16
|
import { Link } from "./prefetchLink.mjs";
|
|
16
17
|
import { useMatches } from "./routeHooks.mjs";
|
|
@@ -143,10 +144,14 @@ const tanstackRouterPlugin = (userConfig = {})=>{
|
|
|
143
144
|
runtimeContext
|
|
144
145
|
]);
|
|
145
146
|
if (!router) return App ? /*#__PURE__*/ jsx(App, {}) : null;
|
|
147
|
+
const navigation = useMemo(()=>createTanstackNavigation(router), [
|
|
148
|
+
router
|
|
149
|
+
]);
|
|
146
150
|
const runtimeState = applyRouterRuntimeState(runtimeContext, {
|
|
147
151
|
framework: 'tanstack',
|
|
148
152
|
basename: _basename,
|
|
149
|
-
instance: router
|
|
153
|
+
instance: router,
|
|
154
|
+
navigation
|
|
150
155
|
});
|
|
151
156
|
const lifecycleContext = {
|
|
152
157
|
framework: 'tanstack',
|
|
@@ -9,7 +9,8 @@ import { useContext } from "react";
|
|
|
9
9
|
import { createModernBasepathRewrite } from "./basepathRewrite.mjs";
|
|
10
10
|
import { routerProviderRegistryHooks } from "./hooks.mjs";
|
|
11
11
|
import { wrapTanstackSsrHydrationBoundary } from "./hydrationBoundary.mjs";
|
|
12
|
-
import {
|
|
12
|
+
import { applyRouterRuntimeState, applyRouterServerPrepareResult, getRouterRuntimeState, getRouterServerSnapshot } from "./lifecycle.mjs";
|
|
13
|
+
import { createTanstackNavigation } from "./navigation.mjs";
|
|
13
14
|
import { createTanstackRouteObjects, getTanstackRouteConfig, joinBasename } from "./pluginShared.mjs";
|
|
14
15
|
import { Link } from "./prefetchLink.mjs";
|
|
15
16
|
import { createRouteTreeFromRouteObjects, getModernRouteIdsFromMatches } from "./routeTree/index.mjs";
|
|
@@ -88,76 +89,93 @@ const tanstackRouterPlugin = (userConfig = {})=>{
|
|
|
88
89
|
});
|
|
89
90
|
const serverRouter = tanstackRouter;
|
|
90
91
|
if (enableRsc) setTanstackRscRouter(serverRouter);
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
}
|
|
101
|
-
|
|
102
|
-
if (!serverLoadResult) {
|
|
103
|
-
try {
|
|
104
|
-
serverRouter.serverSsr?.cleanup?.();
|
|
105
|
-
} catch {}
|
|
106
|
-
throw new Error('TanStack Router completed an SSR load without a server result.');
|
|
107
|
-
}
|
|
108
|
-
if ('redirect' === serverLoadResult.type) {
|
|
109
|
-
const { redirect } = serverLoadResult;
|
|
110
|
-
try {
|
|
111
|
-
serverRouter.serverSsr?.cleanup?.();
|
|
112
|
-
} catch {}
|
|
113
|
-
return interrupt(isRSCNavigation ? handleTanstackRscRedirect(redirect.headers, _basename, redirect.status) : redirect);
|
|
114
|
-
}
|
|
115
|
-
const routerErrors = collectRouterErrors(tanstackRouter);
|
|
116
|
-
if (routerErrors && 'clientRender' === loaderFailureMode) {
|
|
117
|
-
context.ssrContext?.response?.status(200);
|
|
118
|
-
try {
|
|
119
|
-
serverRouter.serverSsr?.cleanup?.();
|
|
120
|
-
} catch {}
|
|
121
|
-
throw Object.values(routerErrors)[0];
|
|
122
|
-
}
|
|
123
|
-
await preloadMatchedRouteComponents(serverRouter);
|
|
124
|
-
context.ssrContext?.response?.status(serverLoadResult.status);
|
|
125
|
-
await serverRouter.serverSsr?.dehydrate?.();
|
|
126
|
-
if (enableRsc) {
|
|
127
|
-
if (isRSCNavigation) await waitForRouterSerialization(serverRouter);
|
|
128
|
-
setTanstackRscServerPayload(createTanstackRscServerPayload(serverRouter, {
|
|
129
|
-
omitClientLoaderData: isRSCNavigation
|
|
130
|
-
}));
|
|
131
|
-
}
|
|
132
|
-
const ssrScriptTags = serverRouter.serverSsr?.takeBufferedScripts?.();
|
|
133
|
-
const hydrationScripts = routerManagedTagsToHtml(ssrScriptTags);
|
|
134
|
-
const matchedRouteIds = getModernRouteIdsFromMatches(serverRouter);
|
|
135
|
-
const routerServerSnapshot = createRouterServerSnapshot({
|
|
92
|
+
let disposed = false;
|
|
93
|
+
let prepared = false;
|
|
94
|
+
const onAbort = ()=>controller.abort(rawRequest.signal.reason);
|
|
95
|
+
const cleanup = ()=>{
|
|
96
|
+
if (disposed) return;
|
|
97
|
+
disposed = true;
|
|
98
|
+
rawRequest.signal.removeEventListener('abort', onAbort);
|
|
99
|
+
controller.abort();
|
|
100
|
+
serverRouter.serverSsr?.cleanup?.();
|
|
101
|
+
};
|
|
102
|
+
applyRouterRuntimeState(context, {
|
|
136
103
|
framework: 'tanstack',
|
|
137
104
|
basename: _basename,
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
105
|
+
instance: serverRouter,
|
|
106
|
+
cleanup
|
|
107
|
+
});
|
|
108
|
+
rawRequest.signal.addEventListener('abort', onAbort, {
|
|
109
|
+
once: true
|
|
142
110
|
});
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
111
|
+
try {
|
|
112
|
+
rawRequest.signal.throwIfAborted();
|
|
113
|
+
await attachServerSsrUtils(serverRouter);
|
|
114
|
+
rawRequest.signal.throwIfAborted();
|
|
115
|
+
const end = time();
|
|
116
|
+
try {
|
|
117
|
+
await tanstackRouter.load({
|
|
118
|
+
sync: true
|
|
119
|
+
});
|
|
120
|
+
} finally{
|
|
121
|
+
const cost = end();
|
|
122
|
+
context.ssrContext?.onTiming?.(LOADER_REPORTER_NAME, cost);
|
|
123
|
+
}
|
|
124
|
+
rawRequest.signal.throwIfAborted();
|
|
125
|
+
const serverLoadResult = serverRouter._serverResult;
|
|
126
|
+
if (!serverLoadResult) throw new Error('TanStack Router completed an SSR load without a server result.');
|
|
127
|
+
if ('redirect' === serverLoadResult.type) {
|
|
128
|
+
const { redirect } = serverLoadResult;
|
|
129
|
+
return interrupt(isRSCNavigation ? handleTanstackRscRedirect(redirect.headers, _basename, redirect.status) : redirect);
|
|
130
|
+
}
|
|
131
|
+
const routerErrors = collectRouterErrors(tanstackRouter);
|
|
132
|
+
if (routerErrors && 'clientRender' === loaderFailureMode) {
|
|
133
|
+
context.ssrContext?.response?.status(200);
|
|
134
|
+
throw Object.values(routerErrors)[0];
|
|
135
|
+
}
|
|
136
|
+
await preloadMatchedRouteComponents(serverRouter);
|
|
137
|
+
context.ssrContext?.response?.status(serverLoadResult.status);
|
|
138
|
+
await serverRouter.serverSsr?.dehydrate?.();
|
|
139
|
+
if (enableRsc) {
|
|
140
|
+
if (isRSCNavigation) await waitForRouterSerialization(serverRouter);
|
|
141
|
+
setTanstackRscServerPayload(createTanstackRscServerPayload(serverRouter, {
|
|
142
|
+
omitClientLoaderData: isRSCNavigation
|
|
143
|
+
}));
|
|
144
|
+
}
|
|
145
|
+
const ssrScriptTags = serverRouter.serverSsr?.takeBufferedScripts?.();
|
|
146
|
+
const hydrationScripts = routerManagedTagsToHtml(ssrScriptTags);
|
|
147
|
+
const matchedRouteIds = getModernRouteIdsFromMatches(serverRouter);
|
|
148
|
+
const routerServerSnapshot = {
|
|
147
149
|
framework: 'tanstack',
|
|
148
150
|
basename: _basename,
|
|
149
|
-
|
|
150
|
-
|
|
151
|
+
statusCode: serverLoadResult.status,
|
|
152
|
+
errors: routerErrors,
|
|
151
153
|
matchedRouteIds,
|
|
152
|
-
|
|
153
|
-
}
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
154
|
+
hydrationScripts
|
|
155
|
+
};
|
|
156
|
+
const runtimeContext = applyRouterServerPrepareResult(context, {
|
|
157
|
+
snapshot: routerServerSnapshot,
|
|
158
|
+
cleanup,
|
|
159
|
+
state: {
|
|
160
|
+
framework: 'tanstack',
|
|
161
|
+
basename: _basename,
|
|
162
|
+
instance: serverRouter,
|
|
163
|
+
navigation: createTanstackNavigation(tanstackRouter)
|
|
164
|
+
}
|
|
165
|
+
});
|
|
166
|
+
rawRequest.signal.throwIfAborted();
|
|
167
|
+
hooks.onAfterCreateRouter.call({
|
|
168
|
+
...routerLifecycleContext,
|
|
169
|
+
router: serverRouter,
|
|
170
|
+
serverSnapshot: getRouterServerSnapshot(runtimeContext),
|
|
171
|
+
runtimeContext
|
|
172
|
+
});
|
|
173
|
+
prepared = true;
|
|
174
|
+
} finally{
|
|
175
|
+
if (!prepared) try {
|
|
176
|
+
cleanup();
|
|
177
|
+
} catch {}
|
|
178
|
+
}
|
|
161
179
|
});
|
|
162
180
|
api.wrapRoot((App)=>{
|
|
163
181
|
const getRouteApp = ()=>{
|
|
@@ -1,24 +1,20 @@
|
|
|
1
1
|
import "node:module";
|
|
2
|
-
import { canonicaliseLocalisedRoutes } from "@modern-js/i18n-runtime-extensions";
|
|
3
2
|
import { DefaultNotFound } from "@modern-js/runtime/context";
|
|
4
3
|
import { rootRouteId } from "@tanstack/react-router";
|
|
4
|
+
import { describeRouteTree } from "../../shared/routeDescriptor.mjs";
|
|
5
5
|
import { createRouteStaticData } from "../../shared/routeStaticData.mjs";
|
|
6
6
|
import { withModernRouteMatchContext } from "../outlet.mjs";
|
|
7
7
|
import { toErrorComponent, toPendingComponent, toRouteComponent } from "./components.mjs";
|
|
8
8
|
import { createModernShouldReload, wrapRouteObjectLoader } from "./loaders.mjs";
|
|
9
|
-
import { isRouteObjectPathlessLayout, toTanstackPath } from "./paths.mjs";
|
|
10
9
|
import { mergeModernRouteHandle } from "./staticData.mjs";
|
|
11
10
|
import { createTanstackRootRoute, createTanstackRoute, wrapRouteComponentWithModernContext } from "./tanstackRoutes.mjs";
|
|
12
|
-
function
|
|
13
|
-
const { options = {}, parent, pathlessFallbackId = 'pathless', routeObject } = opts;
|
|
11
|
+
function createRouteOptions(routeObject, options) {
|
|
14
12
|
const modernRouteObject = routeObject;
|
|
15
13
|
const revalidationState = {};
|
|
16
14
|
const shouldRevalidate = modernRouteObject.shouldRevalidate;
|
|
17
15
|
const shouldReload = createModernShouldReload(shouldRevalidate, revalidationState);
|
|
18
|
-
const stableFallbackId = routeObject.id || modernRouteObject.file || pathlessFallbackId;
|
|
19
16
|
const component = toRouteComponent(routeObject);
|
|
20
17
|
const base = {
|
|
21
|
-
getParentRoute: ()=>parent,
|
|
22
18
|
component,
|
|
23
19
|
pendingComponent: toPendingComponent(routeObject),
|
|
24
20
|
errorComponent: toErrorComponent(routeObject),
|
|
@@ -39,67 +35,29 @@ function createRouteFromRouteObject(opts) {
|
|
|
39
35
|
};
|
|
40
36
|
if (modernRouteObject.inValidSSRRoute) base.ssr = false;
|
|
41
37
|
if (shouldReload) base.shouldReload = shouldReload;
|
|
42
|
-
|
|
43
|
-
else base.path = routeObject.index ? '/' : toTanstackPath(routeObject.path || '');
|
|
44
|
-
const route = createTanstackRoute(base);
|
|
45
|
-
wrapRouteComponentWithModernContext(route, component, routeObject.id);
|
|
46
|
-
const children = routeObject.children;
|
|
47
|
-
if (children && children.length > 0) {
|
|
48
|
-
const childRoutes = children.map((child, index)=>createRouteFromRouteObject({
|
|
49
|
-
options,
|
|
50
|
-
parent: route,
|
|
51
|
-
pathlessFallbackId: `pathless-${index}`,
|
|
52
|
-
routeObject: child
|
|
53
|
-
}));
|
|
54
|
-
route.addChildren(childRoutes);
|
|
55
|
-
}
|
|
56
|
-
return route;
|
|
38
|
+
return base;
|
|
57
39
|
}
|
|
58
|
-
function
|
|
59
|
-
|
|
40
|
+
function createRouteFromDescriptor(descriptor, parent, options) {
|
|
41
|
+
const { source, location, children } = descriptor;
|
|
42
|
+
const routeOptions = createRouteOptions(source, options);
|
|
43
|
+
const route = createTanstackRoute({
|
|
44
|
+
...routeOptions,
|
|
45
|
+
...location,
|
|
46
|
+
getParentRoute: ()=>parent
|
|
47
|
+
});
|
|
48
|
+
wrapRouteComponentWithModernContext(route, routeOptions.component, source.id);
|
|
49
|
+
if (children.length) route.addChildren(children.map((child)=>createRouteFromDescriptor(child, route, options)));
|
|
50
|
+
return route;
|
|
60
51
|
}
|
|
61
52
|
function createRouteTreeFromRouteObjects(routes, options = {}) {
|
|
62
|
-
|
|
63
|
-
const rootLikeRoute = getRootLikeRouteObject(routes);
|
|
64
|
-
const rootRevalidationState = {};
|
|
65
|
-
const rootShouldRevalidate = rootLikeRoute?.shouldRevalidate;
|
|
66
|
-
const rootShouldReload = createModernShouldReload(rootShouldRevalidate, rootRevalidationState);
|
|
67
|
-
const rootComponent = rootLikeRoute ? toRouteComponent(rootLikeRoute) : void 0;
|
|
53
|
+
const { root, children } = describeRouteTree(routes);
|
|
68
54
|
const rootRouteOptions = {
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
errorComponent: rootLikeRoute ? toErrorComponent(rootLikeRoute) : void 0,
|
|
72
|
-
validateSearch: rootLikeRoute?.validateSearch,
|
|
73
|
-
loaderDeps: rootLikeRoute?.loaderDeps,
|
|
74
|
-
notFoundComponent: DefaultNotFound,
|
|
75
|
-
staticData: createRouteStaticData({
|
|
76
|
-
modernRouteId: rootLikeRoute?.id,
|
|
77
|
-
modernRouteAction: rootLikeRoute?.action,
|
|
78
|
-
modernRouteHandle: rootLikeRoute ? mergeModernRouteHandle(rootLikeRoute) : void 0,
|
|
79
|
-
modernRouteHasAction: rootLikeRoute?.hasAction || Boolean(rootLikeRoute?.action),
|
|
80
|
-
modernRouteHasClientLoader: rootLikeRoute?.hasClientLoader || void 0 !== rootLikeRoute?.clientData,
|
|
81
|
-
modernRouteHasLoader: rootLikeRoute?.hasLoader || 'function' == typeof rootLikeRoute?.loader,
|
|
82
|
-
modernRouteIsClientComponent: rootLikeRoute?.isClientComponent,
|
|
83
|
-
modernRouteLoader: rootLikeRoute?.loader,
|
|
84
|
-
modernRouteShouldRevalidate: rootShouldRevalidate
|
|
85
|
-
}),
|
|
86
|
-
loader: rootLikeRoute ? wrapRouteObjectLoader(rootLikeRoute, rootRevalidationState, options) : void 0
|
|
55
|
+
...root ? createRouteOptions(root, options) : {},
|
|
56
|
+
notFoundComponent: DefaultNotFound
|
|
87
57
|
};
|
|
88
|
-
if (rootShouldReload) rootRouteOptions.shouldReload = rootShouldReload;
|
|
89
|
-
if (rootLikeRoute?.inValidSSRRoute) rootRouteOptions.ssr = false;
|
|
90
58
|
const rootRoute = createTanstackRootRoute(rootRouteOptions);
|
|
91
|
-
if (
|
|
92
|
-
|
|
93
|
-
...rootLikeRoute.children || [],
|
|
94
|
-
...routes.filter((route)=>route !== rootLikeRoute)
|
|
95
|
-
] : routes;
|
|
96
|
-
const childRoutes = topLevel.map((routeObject, index)=>createRouteFromRouteObject({
|
|
97
|
-
options,
|
|
98
|
-
parent: rootRoute,
|
|
99
|
-
pathlessFallbackId: `pathless-${index}`,
|
|
100
|
-
routeObject
|
|
101
|
-
}));
|
|
102
|
-
rootRoute.addChildren(childRoutes);
|
|
59
|
+
if (rootRouteOptions.component) rootRoute.options.component = withModernRouteMatchContext(rootRouteOptions.component, rootRouteId);
|
|
60
|
+
rootRoute.addChildren(children.map((child)=>createRouteFromDescriptor(child, rootRoute, options)));
|
|
103
61
|
return rootRoute;
|
|
104
62
|
}
|
|
105
63
|
function getModernRouteIdsFromMatches(router) {
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import "node:module";
|
|
2
|
-
import { getLoaderHref, handleModernLoaderError, handleModernLoaderResult, mapSplatParamsForModernLoader } from "../loaderBridge.mjs";
|
|
2
|
+
import { getLoaderHref, getLoaderSignal, handleModernLoaderError, handleModernLoaderResult, mapSplatParamsForModernLoader } from "../loaderBridge.mjs";
|
|
3
3
|
import { isTanstackRscPayloadNavigationEnabled, loadTanstackRscRouteData } from "../rsc/payloadRouter.mjs";
|
|
4
4
|
function isModernDeferredData(value) {
|
|
5
5
|
if (!value || 'object' != typeof value) return false;
|
|
@@ -50,7 +50,7 @@ function wrapRouteObjectLoader(route, revalidationState, options = {}) {
|
|
|
50
50
|
if ('function' == typeof modernRoute.lazyImport) try {
|
|
51
51
|
await modernRoute.lazyImport();
|
|
52
52
|
} catch {}
|
|
53
|
-
const signal = ctx
|
|
53
|
+
const signal = getLoaderSignal(ctx);
|
|
54
54
|
const baseRequest = ctx?.context?.request instanceof Request ? ctx.context.request : void 0;
|
|
55
55
|
const href = getLoaderHref(ctx);
|
|
56
56
|
const request = void 0 !== baseRequest ? new Request(baseRequest, {
|
|
@@ -15,6 +15,7 @@ function withGlobalLayout(Component, globalApp) {
|
|
|
15
15
|
function toTanstackRouteObject(route, globalApp) {
|
|
16
16
|
if ('nested' === route.type) return {
|
|
17
17
|
modernLocalisedRoute: Reflect.get(route, 'modernLocalisedRoute'),
|
|
18
|
+
isRoot: Reflect.get(route, 'isRoot'),
|
|
18
19
|
path: route.path,
|
|
19
20
|
id: route.id,
|
|
20
21
|
loader: route.loader,
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
import "node:module";
|
|
2
|
+
import { toTanstackPath } from "../runtime/routeTree/paths.mjs";
|
|
3
|
+
function describeRouteTree(routes) {
|
|
4
|
+
const root = routes.find((route)=>true === route.isRoot || '/' === route.path && true !== route.index);
|
|
5
|
+
const describe = (route, index)=>({
|
|
6
|
+
source: route,
|
|
7
|
+
location: 0 === (route.path ?? '').length && true !== route.index ? {
|
|
8
|
+
id: route.id || route.file || `pathless-${index}`
|
|
9
|
+
} : {
|
|
10
|
+
path: true === route.index ? '/' : toTanstackPath(route.path || '')
|
|
11
|
+
},
|
|
12
|
+
hasSplat: Boolean(route.path?.includes('*')),
|
|
13
|
+
children: (route.children ?? []).map(describe)
|
|
14
|
+
});
|
|
15
|
+
return {
|
|
16
|
+
root,
|
|
17
|
+
children: (void 0 !== root ? [
|
|
18
|
+
...root.children ?? [],
|
|
19
|
+
...routes.filter((route)=>route !== root)
|
|
20
|
+
] : routes).map(describe)
|
|
21
|
+
};
|
|
22
|
+
}
|
|
23
|
+
export { describeRouteTree };
|
|
@@ -11,8 +11,6 @@ export declare function pickRouteSearchContractModules(route: NestedRouteForCli
|
|
|
11
11
|
validateSearchPath: string | null;
|
|
12
12
|
loaderDepsPath: string | null;
|
|
13
13
|
};
|
|
14
|
-
export declare function isPathlessLayout(route: NestedRouteForCli | PageRoute): boolean;
|
|
15
|
-
export declare function isIndexRoute(route: NestedRouteForCli | PageRoute): boolean;
|
|
16
14
|
export declare function createRouteStaticDataSnippet(opts: {
|
|
17
15
|
modernRouteId?: string;
|
|
18
16
|
loaderName?: string | null;
|
|
@@ -11,4 +11,4 @@ export type RouterLifecycleContext = NativeRouterLifecycleContext & {
|
|
|
11
11
|
cleanup?: () => void | Promise<void>;
|
|
12
12
|
serverSnapshot?: InternalRouterServerSnapshot;
|
|
13
13
|
};
|
|
14
|
-
export { applyRouterRuntimeState, applyRouterServerPrepareResult,
|
|
14
|
+
export { applyRouterRuntimeState, applyRouterServerPrepareResult, createRouterServerSnapshot, getRouterRuntimeState, getRouterServerSnapshot, type RouterLifecyclePhase, } from '@modern-js/runtime-extensions/router-state';
|
|
@@ -39,6 +39,7 @@ type LoaderLikeContext = {
|
|
|
39
39
|
};
|
|
40
40
|
params?: Record<string, string>;
|
|
41
41
|
};
|
|
42
|
+
export declare function getLoaderSignal(ctx: LoaderLikeContext | undefined): AbortSignal;
|
|
42
43
|
export declare function getLoaderHref(ctx: LoaderLikeContext | undefined): string;
|
|
43
44
|
export declare function handleModernLoaderResult<LoaderResult>(result: LoaderResult): LoaderResult;
|
|
44
45
|
export declare function handleModernLoaderError(err: unknown): never;
|
|
@@ -0,0 +1,4 @@
|
|
|
1
|
+
import type { RouterNavigationCapability } from '@modern-js/runtime-extensions/router-state';
|
|
2
|
+
import type { AnyRouter } from '@tanstack/react-router';
|
|
3
|
+
/** Native TanStack navigation, exposed through the provider contract. */
|
|
4
|
+
export declare function createTanstackNavigation(router: AnyRouter): RouterNavigationCapability;
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
type RouteShape = {
|
|
2
|
+
id?: string;
|
|
3
|
+
file?: string;
|
|
4
|
+
path?: string;
|
|
5
|
+
index?: boolean;
|
|
6
|
+
isRoot?: boolean;
|
|
7
|
+
children?: RouteShape[];
|
|
8
|
+
};
|
|
9
|
+
/** Browser-safe structure shared by the executable tree and concrete TS emitter. */
|
|
10
|
+
export type RouteDescriptor<T extends RouteShape> = {
|
|
11
|
+
source: T;
|
|
12
|
+
location: {
|
|
13
|
+
id: string;
|
|
14
|
+
path?: never;
|
|
15
|
+
} | {
|
|
16
|
+
path: string;
|
|
17
|
+
id?: never;
|
|
18
|
+
};
|
|
19
|
+
hasSplat: boolean;
|
|
20
|
+
children: RouteDescriptor<T>[];
|
|
21
|
+
};
|
|
22
|
+
export declare function describeRouteTree<T extends RouteShape>(routes: T[]): {
|
|
23
|
+
root: T | undefined;
|
|
24
|
+
children: RouteDescriptor<T>[];
|
|
25
|
+
};
|
|
26
|
+
export {};
|
package/package.json
CHANGED
|
@@ -18,7 +18,7 @@
|
|
|
18
18
|
"modern.js",
|
|
19
19
|
"tanstack-router"
|
|
20
20
|
],
|
|
21
|
-
"version": "3.9.0-ultramodern.
|
|
21
|
+
"version": "3.9.0-ultramodern.12",
|
|
22
22
|
"engines": {
|
|
23
23
|
"node": ">=20"
|
|
24
24
|
},
|
|
@@ -94,19 +94,19 @@
|
|
|
94
94
|
}
|
|
95
95
|
},
|
|
96
96
|
"dependencies": {
|
|
97
|
-
"@modern-js/i18n-runtime-extensions": "npm:@bleedingdev/modern-js-i18n-runtime-extensions@3.9.0-ultramodern.
|
|
98
|
-
"@modern-js/plugin": "npm:@bleedingdev/modern-js-plugin@3.9.0-ultramodern.
|
|
99
|
-
"@modern-js/runtime-extensions": "npm:@bleedingdev/modern-js-runtime-extensions@3.9.0-ultramodern.
|
|
100
|
-
"@modern-js/runtime-utils": "npm:@bleedingdev/modern-js-runtime-utils@3.9.0-ultramodern.
|
|
101
|
-
"@modern-js/types": "npm:@bleedingdev/modern-js-types@3.9.0-ultramodern.
|
|
102
|
-
"@modern-js/utils": "npm:@bleedingdev/modern-js-utils@3.9.0-ultramodern.
|
|
97
|
+
"@modern-js/i18n-runtime-extensions": "npm:@bleedingdev/modern-js-i18n-runtime-extensions@3.9.0-ultramodern.12",
|
|
98
|
+
"@modern-js/plugin": "npm:@bleedingdev/modern-js-plugin@3.9.0-ultramodern.12",
|
|
99
|
+
"@modern-js/runtime-extensions": "npm:@bleedingdev/modern-js-runtime-extensions@3.9.0-ultramodern.12",
|
|
100
|
+
"@modern-js/runtime-utils": "npm:@bleedingdev/modern-js-runtime-utils@3.9.0-ultramodern.12",
|
|
101
|
+
"@modern-js/types": "npm:@bleedingdev/modern-js-types@3.9.0-ultramodern.12",
|
|
102
|
+
"@modern-js/utils": "npm:@bleedingdev/modern-js-utils@3.9.0-ultramodern.12",
|
|
103
103
|
"@swc/helpers": "^0.5.23",
|
|
104
104
|
"@tanstack/react-router": "1.170.33",
|
|
105
105
|
"@tanstack/router-core": "1.171.28"
|
|
106
106
|
},
|
|
107
107
|
"peerDependencies": {
|
|
108
|
-
"@modern-js/app-tools": "3.9.0-ultramodern.
|
|
109
|
-
"@modern-js/runtime": "3.9.0-ultramodern.
|
|
108
|
+
"@modern-js/app-tools": "3.9.0-ultramodern.12",
|
|
109
|
+
"@modern-js/runtime": "3.9.0-ultramodern.12",
|
|
110
110
|
"react": "^19.2.8",
|
|
111
111
|
"react-dom": "^19.2.8",
|
|
112
112
|
"react-server-dom-rspack": "0.1.0"
|
|
@@ -117,9 +117,9 @@
|
|
|
117
117
|
}
|
|
118
118
|
},
|
|
119
119
|
"devDependencies": {
|
|
120
|
-
"@modern-js/app-tools": "npm:@bleedingdev/modern-js-app-tools@3.9.0-ultramodern.
|
|
121
|
-
"@modern-js/runtime": "npm:@bleedingdev/modern-js-runtime@3.9.0-ultramodern.
|
|
122
|
-
"@modern-js/server-utils": "npm:@bleedingdev/modern-js-server-utils@3.9.0-ultramodern.
|
|
120
|
+
"@modern-js/app-tools": "npm:@bleedingdev/modern-js-app-tools@3.9.0-ultramodern.12",
|
|
121
|
+
"@modern-js/runtime": "npm:@bleedingdev/modern-js-runtime@3.9.0-ultramodern.12",
|
|
122
|
+
"@modern-js/server-utils": "npm:@bleedingdev/modern-js-server-utils@3.9.0-ultramodern.12",
|
|
123
123
|
"@rslib/core": "1.0.0",
|
|
124
124
|
"@scripts/rstest-config": "2.66.0",
|
|
125
125
|
"@tanstack/history": "1.162.2",
|
package/src/cli/artifacts.ts
CHANGED
|
@@ -251,5 +251,10 @@ export async function generateTanstackRouteArtifacts(opts: {
|
|
|
251
251
|
internalPlugins: (utils as { INTERNAL_RUNTIME_PLUGINS: unknown })
|
|
252
252
|
.INTERNAL_RUNTIME_PLUGINS as never,
|
|
253
253
|
});
|
|
254
|
-
await cli.init({ ...runOptions, command: 'build' });
|
|
254
|
+
const { appContext } = await cli.init({ ...runOptions, command: 'build' });
|
|
255
|
+
// Preparation owns the artifact writes; there is no dev server or bundler
|
|
256
|
+
// phase after it. Release plugin resources before the headless caller exits.
|
|
257
|
+
// Failed initialization propagates unchanged: it has not returned a context
|
|
258
|
+
// whose lifecycle this caller can close.
|
|
259
|
+
await appContext.hooks.onBeforeExit.call();
|
|
255
260
|
}
|
|
@@ -1,7 +1,10 @@
|
|
|
1
1
|
// @effect-diagnostics asyncFunction:off strictBooleanExpressions:off
|
|
2
2
|
|
|
3
3
|
import type { NestedRouteForCli, PageRoute } from '@modern-js/types';
|
|
4
|
-
import {
|
|
4
|
+
import {
|
|
5
|
+
describeRouteTree,
|
|
6
|
+
type RouteDescriptor,
|
|
7
|
+
} from '../../shared/routeDescriptor';
|
|
5
8
|
|
|
6
9
|
import { toTanstackPath } from './shared';
|
|
7
10
|
|
|
@@ -16,6 +19,7 @@ const LOCALE_PARAM_SEGMENTS = new Set([
|
|
|
16
19
|
|
|
17
20
|
type CanonicalAwareRoute = (NestedRouteForCli | PageRoute) & {
|
|
18
21
|
modernCanonicalPath?: string;
|
|
22
|
+
modernLocalisedRoute?: { canonicalPath: string };
|
|
19
23
|
index?: boolean;
|
|
20
24
|
isRoot?: boolean;
|
|
21
25
|
children?: CanonicalAwareRoute[];
|
|
@@ -101,12 +105,18 @@ export function collectCanonicalRoutesForEntry(
|
|
|
101
105
|
}
|
|
102
106
|
};
|
|
103
107
|
|
|
104
|
-
const visit = (
|
|
108
|
+
const visit = (
|
|
109
|
+
descriptor: RouteDescriptor<CanonicalAwareRoute>,
|
|
110
|
+
parentPath: string,
|
|
111
|
+
) => {
|
|
112
|
+
const { source: route, children } = descriptor;
|
|
105
113
|
let currentPath = parentPath;
|
|
106
114
|
|
|
107
|
-
|
|
115
|
+
const canonicalPath =
|
|
116
|
+
route.modernLocalisedRoute?.canonicalPath ?? route.modernCanonicalPath;
|
|
117
|
+
if (typeof canonicalPath === 'string') {
|
|
108
118
|
hasI18nSurface = true;
|
|
109
|
-
currentPath = normalizeJoined(
|
|
119
|
+
currentPath = canonicalPath ? normalizeJoined(canonicalPath) : '';
|
|
110
120
|
} else if (typeof route.path === 'string' && route.path.length > 0) {
|
|
111
121
|
const segments = route.path
|
|
112
122
|
.replace(/\[(.+?)\]/g, ':$1')
|
|
@@ -125,7 +135,6 @@ export function collectCanonicalRoutesForEntry(
|
|
|
125
135
|
: parentPath;
|
|
126
136
|
}
|
|
127
137
|
|
|
128
|
-
const children = route.children;
|
|
129
138
|
if (children && children.length > 0) {
|
|
130
139
|
for (const child of children) {
|
|
131
140
|
visit(child, currentPath);
|
|
@@ -137,13 +146,9 @@ export function collectCanonicalRoutesForEntry(
|
|
|
137
146
|
record(currentPath || '/');
|
|
138
147
|
};
|
|
139
148
|
|
|
140
|
-
const
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
const topLevel = rootModern ? (rootModern.children ?? []) : routes;
|
|
144
|
-
|
|
145
|
-
for (const route of topLevel) {
|
|
146
|
-
visit(route as CanonicalAwareRoute, '');
|
|
149
|
+
for (const route of describeRouteTree(routes as CanonicalAwareRoute[])
|
|
150
|
+
.children) {
|
|
151
|
+
visit(route, '');
|
|
147
152
|
}
|
|
148
153
|
|
|
149
154
|
if (!hasI18nSurface || canonicalParams.size === 0) {
|
|
@@ -71,20 +71,6 @@ export function pickRouteSearchContractModules(
|
|
|
71
71
|
};
|
|
72
72
|
}
|
|
73
73
|
|
|
74
|
-
export function isPathlessLayout(route: NestedRouteForCli | PageRoute) {
|
|
75
|
-
const extras = route as RouteExtras;
|
|
76
|
-
return (
|
|
77
|
-
extras.type === 'nested' &&
|
|
78
|
-
typeof extras.index !== 'boolean' &&
|
|
79
|
-
typeof extras.path === 'undefined'
|
|
80
|
-
);
|
|
81
|
-
}
|
|
82
|
-
|
|
83
|
-
export function isIndexRoute(route: NestedRouteForCli | PageRoute) {
|
|
84
|
-
const extras = route as RouteExtras;
|
|
85
|
-
return extras.type === 'nested' && Boolean(extras.index);
|
|
86
|
-
}
|
|
87
|
-
|
|
88
74
|
export function createRouteStaticDataSnippet(opts: {
|
|
89
75
|
modernRouteId?: string;
|
|
90
76
|
loaderName?: string | null;
|