@bleedingdev/modern-js-plugin-tanstack 3.9.0-ultramodern.2 → 3.9.0-ultramodern.21
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 +12 -0
- package/dist/cjs/cli/routeMetadata.js +131 -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 +27 -60
- package/dist/cjs/runtime/basepathRewrite.js +13 -6
- package/dist/cjs/runtime/lifecycle.js +6 -9
- package/dist/cjs/runtime/loaderBridge.js +10 -4
- package/dist/cjs/runtime/navigation.js +102 -0
- package/dist/cjs/runtime/plugin.js +7 -2
- package/dist/cjs/runtime/plugin.node.js +86 -64
- package/dist/cjs/runtime/prefetchLink.js +2 -7
- package/dist/cjs/runtime/register.js +0 -2
- package/dist/cjs/runtime/routeTree/construction.js +19 -59
- package/dist/cjs/runtime/routeTree/loaders.js +1 -1
- package/dist/cjs/runtime/routeTree/paths.js +0 -6
- package/dist/cjs/runtime/router.js +25 -9
- package/dist/cjs/runtime/ssrManagedTags.js +2 -12
- package/dist/cjs/runtime/state.js +2 -2
- package/dist/cjs/runtime/utils.js +3 -0
- package/dist/cjs/shared/routeDescriptor.js +60 -0
- package/dist/esm/cli/artifacts.mjs +13 -2
- package/dist/esm/cli/index.mjs +12 -9
- package/dist/esm/cli/routeMetadata.mjs +71 -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 +28 -61
- package/dist/esm/runtime/basepathRewrite.mjs +10 -3
- 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 +7 -2
- package/dist/esm/runtime/plugin.node.mjs +88 -66
- package/dist/esm/runtime/prefetchLink.mjs +1 -6
- package/dist/esm/runtime/register.mjs +0 -2
- package/dist/esm/runtime/routeTree/construction.mjs +19 -59
- package/dist/esm/runtime/routeTree/loaders.mjs +2 -2
- package/dist/esm/runtime/routeTree/paths.mjs +1 -4
- package/dist/esm/runtime/router.mjs +27 -11
- package/dist/esm/runtime/ssrManagedTags.mjs +1 -8
- package/dist/esm/runtime/state.mjs +1 -1
- package/dist/esm/runtime/utils.mjs +3 -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 +12 -9
- package/dist/esm-node/cli/routeMetadata.mjs +72 -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 +28 -61
- package/dist/esm-node/runtime/basepathRewrite.mjs +10 -3
- 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 +7 -2
- package/dist/esm-node/runtime/plugin.node.mjs +88 -66
- package/dist/esm-node/runtime/prefetchLink.mjs +1 -6
- package/dist/esm-node/runtime/register.mjs +0 -2
- package/dist/esm-node/runtime/routeTree/construction.mjs +19 -59
- 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/router.mjs +27 -11
- package/dist/esm-node/runtime/ssrManagedTags.mjs +1 -8
- package/dist/esm-node/runtime/state.mjs +1 -1
- package/dist/esm-node/runtime/utils.mjs +3 -0
- package/dist/esm-node/shared/routeDescriptor.mjs +23 -0
- package/dist/types/cli/artifacts.d.ts +13 -5
- package/dist/types/cli/index.d.ts +1 -1
- package/dist/types/cli/routeMetadata.d.ts +18 -0
- package/dist/types/cli/tanstackTypes/shared.d.ts +0 -2
- package/dist/types/runtime/basepathRewrite.d.ts +2 -1
- package/dist/types/runtime/lifecycle.d.ts +9 -2
- package/dist/types/runtime/loaderBridge.d.ts +1 -0
- package/dist/types/runtime/navigation.d.ts +4 -0
- package/dist/types/runtime/register.d.ts +1 -9
- package/dist/types/runtime/routeTree/paths.d.ts +0 -2
- package/dist/types/runtime/router.d.ts +2 -13
- package/dist/types/runtime/ssrManagedTags.d.ts +0 -1
- package/dist/types/runtime/ssrTypes.d.ts +0 -7
- package/dist/types/runtime/state.d.ts +1 -1
- package/dist/types/runtime/types.d.ts +2 -1
- package/dist/types/shared/routeDescriptor.d.ts +26 -0
- package/package.json +22 -19
- package/rstest.config.mts +2 -24
- package/src/cli/artifacts.ts +53 -6
- package/src/cli/index.ts +11 -2
- package/src/cli/routeMetadata.ts +121 -0
- package/src/cli/tanstackTypes/canonicalRoutes.ts +17 -12
- package/src/cli/tanstackTypes/shared.ts +0 -14
- package/src/cli/tanstackTypes/source.ts +42 -116
- package/src/runtime/basepathRewrite.ts +11 -2
- package/src/runtime/lifecycle.ts +14 -4
- package/src/runtime/loaderBridge.ts +9 -9
- package/src/runtime/navigation.ts +78 -0
- package/src/runtime/plugin.node.tsx +120 -93
- package/src/runtime/plugin.tsx +11 -1
- package/src/runtime/prefetchLink.tsx +1 -23
- package/src/runtime/register.ts +1 -12
- package/src/runtime/routeTree/construction.ts +32 -110
- package/src/runtime/routeTree/loaders.ts +2 -4
- package/src/runtime/routeTree/paths.ts +0 -6
- package/src/runtime/router.ts +25 -40
- package/src/runtime/ssrManagedTags.ts +0 -17
- package/src/runtime/ssrTypes.ts +0 -7
- package/src/runtime/state.ts +1 -1
- package/src/runtime/types.ts +2 -2
- package/src/runtime/utils.tsx +4 -1
- package/src/shared/routeDescriptor.ts +46 -0
- package/tests/router/cli.test.ts +148 -824
- package/tests/router/clientNavigation.ts +13 -0
- package/tests/router/dataMutation.test.tsx +17 -85
- package/tests/router/flightSerialization.roundtrip.test.tsx +9 -6
- package/tests/router/generateRouteArtifacts.test.ts +139 -27
- package/tests/router/loaderBridge.test.ts +0 -25
- package/tests/router/localisedIdentity.test.tsx +100 -0
- package/tests/router/prefetchLink.test.tsx +46 -21
- package/tests/router/prefetchLinkPreload.test.tsx +11 -32
- package/tests/router/routeHooks.test.ts +42 -105
- package/tests/router/routeMetadata.test.ts +233 -0
- package/tests/router/routeTree.test.ts +144 -836
- package/tests/router/rsc.test.tsx +131 -166
- package/tests/router/serverPlugin.test.ts +193 -1
- package/tests/router/tanstackTypes.test.ts +218 -963
- package/dist/esm/rslib-runtime~1.mjs +0 -18
- package/dist/esm-node/rslib-runtime~0.mjs +0 -19
- package/tests/realm-isolation.test.ts +0 -114
- package/tests/router/fastDefaults.test.ts +0 -32
- package/tests/router/fixtures/legacyRuntimeRouter.ts +0 -10
- package/tests/router/fixtures/rscDecoderSecurityChild.cjs +0 -162
- package/tests/router/hooks.test.ts +0 -40
- package/tests/router/hydrationBoundary.test.tsx +0 -23
- package/tests/router/packageSurface.test.ts +0 -24
- package/tests/router/preloadRedirect.test.ts +0 -64
- package/tests/router/register.test.ts +0 -8
- package/tests/router/routerCompatibility.test.ts +0 -239
- package/tests/router/rscDecoderSecurity.test.ts +0 -113
- package/tests/router/rscPayloadRouterMatrix.test.ts +0 -197
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import "node:module";
|
|
2
|
+
import { describeRouteTree } from "../../shared/routeDescriptor.mjs";
|
|
2
3
|
import { toTanstackPath } from "./shared.mjs";
|
|
3
4
|
const LOCALE_PARAM_SEGMENTS = new Set([
|
|
4
5
|
':lang',
|
|
@@ -45,11 +46,13 @@ function collectCanonicalRoutesForEntry(routes, options = {}) {
|
|
|
45
46
|
const key = toTanstackPath(normalized);
|
|
46
47
|
if (!canonicalParams.has(key)) canonicalParams.set(key, paramsTypeForCanonicalPath(normalized));
|
|
47
48
|
};
|
|
48
|
-
const visit = (
|
|
49
|
+
const visit = (descriptor, parentPath)=>{
|
|
50
|
+
const { source: route, children } = descriptor;
|
|
49
51
|
let currentPath = parentPath;
|
|
50
|
-
|
|
52
|
+
const canonicalPath = route.modernLocalisedRoute?.canonicalPath ?? route.modernCanonicalPath;
|
|
53
|
+
if ('string' == typeof canonicalPath) {
|
|
51
54
|
hasI18nSurface = true;
|
|
52
|
-
currentPath = normalizeJoined(
|
|
55
|
+
currentPath = canonicalPath ? normalizeJoined(canonicalPath) : '';
|
|
53
56
|
} else if ('string' == typeof route.path && route.path.length > 0) {
|
|
54
57
|
const segments = route.path.replace(/\[(.+?)\]/g, ':$1').split('/').filter(Boolean);
|
|
55
58
|
if (localeParamHeuristic && '' === parentPath && LOCALE_PARAM_SEGMENTS.has(segments[0])) {
|
|
@@ -58,16 +61,13 @@ function collectCanonicalRoutesForEntry(routes, options = {}) {
|
|
|
58
61
|
}
|
|
59
62
|
currentPath = segments.length ? normalizeJoined(`${parentPath}/${segments.join('/')}`) : parentPath;
|
|
60
63
|
}
|
|
61
|
-
const children = route.children;
|
|
62
64
|
if (children && children.length > 0) {
|
|
63
65
|
for (const child of children)visit(child, currentPath);
|
|
64
66
|
return;
|
|
65
67
|
}
|
|
66
68
|
record(currentPath || '/');
|
|
67
69
|
};
|
|
68
|
-
const
|
|
69
|
-
const topLevel = rootModern ? rootModern.children ?? [] : routes;
|
|
70
|
-
for (const route of topLevel)visit(route, '');
|
|
70
|
+
for (const route of describeRouteTree(routes).children)visit(route, '');
|
|
71
71
|
if (!hasI18nSurface || 0 === canonicalParams.size) return null;
|
|
72
72
|
return Object.fromEntries([
|
|
73
73
|
...canonicalParams.entries()
|
|
@@ -43,14 +43,6 @@ function pickRouteSearchContractModules(route) {
|
|
|
43
43
|
loaderDepsPath: 'string' == typeof loaderDepsPath ? loaderDepsPath : null
|
|
44
44
|
};
|
|
45
45
|
}
|
|
46
|
-
function isPathlessLayout(route) {
|
|
47
|
-
const extras = route;
|
|
48
|
-
return 'nested' === extras.type && 'boolean' != typeof extras.index && void 0 === extras.path;
|
|
49
|
-
}
|
|
50
|
-
function isIndexRoute(route) {
|
|
51
|
-
const extras = route;
|
|
52
|
-
return 'nested' === extras.type && Boolean(extras.index);
|
|
53
|
-
}
|
|
54
46
|
function createRouteStaticDataSnippet(opts) {
|
|
55
47
|
const staticData = createRouteStaticData({
|
|
56
48
|
modernRouteId: opts.modernRouteId && quote(opts.modernRouteId),
|
|
@@ -61,4 +53,4 @@ function createRouteStaticDataSnippet(opts) {
|
|
|
61
53
|
return entries.length > 0 ? `staticData: createRouteStaticData({\n ${entries.map(([key, value])=>`${key}: ${value},`).join('\n ')}\n }),` : null;
|
|
62
54
|
}
|
|
63
55
|
export { toTanstackPath } from "../../runtime/routeTree/paths.mjs";
|
|
64
|
-
export { createRouteStaticDataSnippet,
|
|
56
|
+
export { createRouteStaticDataSnippet, normalizeRelativeImport, pickModernLoaderModule, pickRouteSearchContractModules, quote, resolveFileNoExt };
|
|
@@ -1,16 +1,12 @@
|
|
|
1
1
|
import "node:module";
|
|
2
2
|
import { makeLegalIdentifier } from "@modern-js/runtime/cli";
|
|
3
3
|
import { upath } from "@modern-js/utils";
|
|
4
|
-
import {
|
|
4
|
+
import { describeRouteTree } from "../../shared/routeDescriptor.mjs";
|
|
5
|
+
import { createRouteStaticDataSnippet, normalizeRelativeImport, pickModernLoaderModule, pickRouteSearchContractModules, quote, resolveFileNoExt } from "./shared.mjs";
|
|
5
6
|
async function generateTanstackRouterTypesSourceForEntry(opts) {
|
|
6
7
|
const { appContext, entryName, generatedDirName = 'modern-tanstack', routes } = opts;
|
|
7
8
|
const outDir = upath.join(appContext.srcDirectory, generatedDirName, entryName);
|
|
8
|
-
const rootModern = routes
|
|
9
|
-
const extras = r;
|
|
10
|
-
return r && 'nested' === extras.type && extras.isRoot;
|
|
11
|
-
});
|
|
12
|
-
const rootExtras = rootModern;
|
|
13
|
-
const topLevel = rootModern ? rootExtras?.children || [] : routes;
|
|
9
|
+
const { root: rootModern, children: topLevel } = describeRouteTree(routes);
|
|
14
10
|
const imports = [];
|
|
15
11
|
const statements = [];
|
|
16
12
|
const loaderImportMap = new Map();
|
|
@@ -27,9 +23,8 @@ async function generateTanstackRouterTypesSourceForEntry(opts) {
|
|
|
27
23
|
let pendingImportName = componentImportMap.get(componentPath);
|
|
28
24
|
if (!pendingImportName) {
|
|
29
25
|
pendingImportName = (async ()=>{
|
|
30
|
-
const
|
|
31
|
-
if (!
|
|
32
|
-
const relImport = normalizeRelativeImport(upath.relative(outDir, resolvedNoExt));
|
|
26
|
+
const relImport = await resolveRouteImport(componentPath);
|
|
27
|
+
if (!relImport) return null;
|
|
33
28
|
const componentName = `component_${componentIndex++}`;
|
|
34
29
|
imports.push(`import ${componentName} from ${quote(relImport)};`);
|
|
35
30
|
return componentName;
|
|
@@ -38,14 +33,15 @@ async function generateTanstackRouterTypesSourceForEntry(opts) {
|
|
|
38
33
|
}
|
|
39
34
|
return pendingImportName;
|
|
40
35
|
};
|
|
41
|
-
const
|
|
36
|
+
const resolveRouteImport = async (aliasedNoExtPath)=>{
|
|
42
37
|
const prefix = `${appContext.internalSrcAlias}/`;
|
|
43
38
|
let absNoExt;
|
|
44
39
|
if (aliasedNoExtPath.startsWith(prefix)) {
|
|
45
40
|
const rel = aliasedNoExtPath.slice(prefix.length);
|
|
46
41
|
absNoExt = upath.join(appContext.srcDirectory, rel);
|
|
47
42
|
} else absNoExt = upath.isAbsolute(aliasedNoExtPath) ? aliasedNoExtPath : upath.join(appContext.srcDirectory, aliasedNoExtPath);
|
|
48
|
-
|
|
43
|
+
const resolvedNoExt = await resolveFileNoExt(absNoExt);
|
|
44
|
+
return resolvedNoExt ? normalizeRelativeImport(upath.relative(outDir, resolvedNoExt)) : null;
|
|
49
45
|
};
|
|
50
46
|
const getImportNamesForLoader = async (aliasedNoExtPath, inline, hasAction)=>{
|
|
51
47
|
const key = `${inline ? 'inline' : 'default'}:${hasAction ? 'action' : 'loader'}:${aliasedNoExtPath}`;
|
|
@@ -54,9 +50,8 @@ async function generateTanstackRouterTypesSourceForEntry(opts) {
|
|
|
54
50
|
loaderName: existing,
|
|
55
51
|
actionName: hasAction ? existing.replace(/^loader_/, 'action_') : null
|
|
56
52
|
};
|
|
57
|
-
const
|
|
58
|
-
if (!
|
|
59
|
-
const relImport = normalizeRelativeImport(upath.relative(outDir, resolvedNoExt));
|
|
53
|
+
const relImport = await resolveRouteImport(aliasedNoExtPath);
|
|
54
|
+
if (!relImport) return null;
|
|
60
55
|
const importName = `loader_${loaderIndex++}`;
|
|
61
56
|
const actionName = hasAction ? importName.replace(/^loader_/, 'action_') : null;
|
|
62
57
|
if (inline) {
|
|
@@ -76,9 +71,8 @@ async function generateTanstackRouterTypesSourceForEntry(opts) {
|
|
|
76
71
|
const key = `${exportName}:${aliasedNoExtPath}`;
|
|
77
72
|
const existing = searchContractImportMap.get(key);
|
|
78
73
|
if (existing) return existing;
|
|
79
|
-
const
|
|
80
|
-
if (!
|
|
81
|
-
const relImport = normalizeRelativeImport(upath.relative(outDir, resolvedNoExt));
|
|
74
|
+
const relImport = await resolveRouteImport(aliasedNoExtPath);
|
|
75
|
+
if (!relImport) return null;
|
|
82
76
|
const importName = 'validateSearch' === exportName ? `validateSearch_${validateSearchIndex++}` : `loaderDeps_${loaderDepsIndex++}`;
|
|
83
77
|
imports.push(`import { ${exportName} as ${importName} } from ${quote(relImport)};`);
|
|
84
78
|
searchContractImportMap.set(key, importName);
|
|
@@ -96,9 +90,7 @@ async function generateTanstackRouterTypesSourceForEntry(opts) {
|
|
|
96
90
|
const base = id ? makeLegalIdentifier(id) : `r_${routeIndex++}`;
|
|
97
91
|
return reserveRouteVarName(`route_${base}`);
|
|
98
92
|
};
|
|
99
|
-
const
|
|
100
|
-
const { parentVar, route } = opts;
|
|
101
|
-
const varName = createRouteVarName(route);
|
|
93
|
+
const createRouteOptions = async (route, hasSplat)=>{
|
|
102
94
|
const routeExtras = route;
|
|
103
95
|
const loaderInfo = pickModernLoaderModule(route);
|
|
104
96
|
const routeAction = routeExtras.action;
|
|
@@ -108,20 +100,9 @@ async function generateTanstackRouterTypesSourceForEntry(opts) {
|
|
|
108
100
|
const searchContractInfo = pickRouteSearchContractModules(route);
|
|
109
101
|
const validateSearchName = searchContractInfo.validateSearchPath ? await getImportNameForSearchContract(searchContractInfo.validateSearchPath, 'validateSearch') : null;
|
|
110
102
|
const loaderDepsName = searchContractInfo.loaderDepsPath ? await getImportNameForSearchContract(searchContractInfo.loaderDepsPath, 'loaderDeps') : null;
|
|
111
|
-
const
|
|
112
|
-
const hasSplat = 'string' == typeof rawPath && rawPath.includes('*');
|
|
113
|
-
const routeOpts = [
|
|
114
|
-
`getParentRoute: () => ${parentVar},`
|
|
115
|
-
];
|
|
103
|
+
const routeOpts = [];
|
|
116
104
|
const componentName = await getImportNameForComponent(routeExtras._component);
|
|
117
105
|
if (componentName) routeOpts.push(`component: ${componentName},`);
|
|
118
|
-
if (isPathlessLayout(route)) {
|
|
119
|
-
const id = routeExtras.id;
|
|
120
|
-
routeOpts.push(`id: ${quote(id || 'pathless')},`);
|
|
121
|
-
} else {
|
|
122
|
-
const p = isIndexRoute(route) ? '/' : toTanstackPath(rawPath || '');
|
|
123
|
-
routeOpts.push(`path: ${quote(p)},`);
|
|
124
|
-
}
|
|
125
106
|
if (loaderName) routeOpts.push(`loader: modernLoaderToTanstack({ hasSplat: ${hasSplat} }, ${loaderName}),`);
|
|
126
107
|
if (validateSearchName) routeOpts.push(`validateSearch: ${validateSearchName},`);
|
|
127
108
|
if (loaderDepsName) routeOpts.push(`loaderDeps: ${loaderDepsName},`);
|
|
@@ -131,39 +112,29 @@ async function generateTanstackRouterTypesSourceForEntry(opts) {
|
|
|
131
112
|
actionName
|
|
132
113
|
});
|
|
133
114
|
if (staticDataSnippet) routeOpts.push(staticDataSnippet);
|
|
134
|
-
|
|
115
|
+
return routeOpts;
|
|
116
|
+
};
|
|
117
|
+
const buildRoute = async (descriptor, parentVar)=>{
|
|
118
|
+
const { source: route, location, hasSplat, children } = descriptor;
|
|
119
|
+
const varName = createRouteVarName(route);
|
|
120
|
+
const routeOpts = [
|
|
121
|
+
`getParentRoute: () => ${parentVar},`,
|
|
122
|
+
...Object.entries(location).map(([key, value])=>`${key}: ${quote(value)},`),
|
|
123
|
+
...await createRouteOptions(route, hasSplat)
|
|
124
|
+
];
|
|
135
125
|
const hasChildren = Boolean(children && children.length > 0);
|
|
136
126
|
const routeCtorVarName = hasChildren ? reserveRouteVarName(`${varName}__base`) : varName;
|
|
137
127
|
statements.push(`const ${routeCtorVarName} = createRoute({\n ${routeOpts.join('\n ')}\n});`);
|
|
138
128
|
if (children && children.length > 0) {
|
|
139
129
|
const childVars = [];
|
|
140
|
-
for (const child of children)childVars.push(await buildRoute(
|
|
141
|
-
parentVar: routeCtorVarName,
|
|
142
|
-
route: child
|
|
143
|
-
}));
|
|
130
|
+
for (const child of children)childVars.push(await buildRoute(child, routeCtorVarName));
|
|
144
131
|
statements.push(`const ${varName} = ${routeCtorVarName}.addChildren([${childVars.join(', ')}]);`);
|
|
145
132
|
}
|
|
146
133
|
return varName;
|
|
147
134
|
};
|
|
148
|
-
const rootLoaderInfo = rootModern ? pickModernLoaderModule(rootModern) : null;
|
|
149
|
-
const rootAction = rootExtras?.action;
|
|
150
|
-
const rootLoaderImports = rootLoaderInfo?.loaderPath ? await getImportNamesForLoader(rootLoaderInfo.loaderPath, rootLoaderInfo.inline, Boolean(rootLoaderInfo.inline && rootAction === rootLoaderInfo.loaderPath)) : null;
|
|
151
|
-
const rootLoaderName = rootLoaderImports?.loaderName || null;
|
|
152
|
-
const rootActionName = rootLoaderImports?.actionName || null;
|
|
153
|
-
const rootSearchContractInfo = rootModern ? pickRouteSearchContractModules(rootModern) : null;
|
|
154
|
-
const rootValidateSearchName = rootSearchContractInfo?.validateSearchPath ? await getImportNameForSearchContract(rootSearchContractInfo.validateSearchPath, 'validateSearch') : null;
|
|
155
|
-
const rootLoaderDepsName = rootSearchContractInfo?.loaderDepsPath ? await getImportNameForSearchContract(rootSearchContractInfo.loaderDepsPath, 'loaderDeps') : null;
|
|
156
135
|
const topLevelVars = [];
|
|
157
|
-
for (const route of topLevel)topLevelVars.push(await buildRoute(
|
|
158
|
-
|
|
159
|
-
route
|
|
160
|
-
}));
|
|
161
|
-
const rootOpts = [];
|
|
162
|
-
const rootComponentName = await getImportNameForComponent(rootExtras?._component);
|
|
163
|
-
if (rootComponentName) rootOpts.push(`component: ${rootComponentName},`);
|
|
164
|
-
if (rootLoaderName) rootOpts.push(`loader: modernLoaderToTanstack({ hasSplat: false }, ${rootLoaderName}),`);
|
|
165
|
-
if (rootValidateSearchName) rootOpts.push(`validateSearch: ${rootValidateSearchName},`);
|
|
166
|
-
if (rootLoaderDepsName) rootOpts.push(`loaderDeps: ${rootLoaderDepsName},`);
|
|
136
|
+
for (const route of topLevel)topLevelVars.push(await buildRoute(route, 'rootRoute'));
|
|
137
|
+
const rootOpts = rootModern ? await createRouteOptions(rootModern, false) : [];
|
|
167
138
|
const routerGenTs = `// This file is auto-generated by Modern.js. Do not edit manually.
|
|
168
139
|
|
|
169
140
|
import {
|
|
@@ -180,11 +151,7 @@ ${imports.join('\n')}
|
|
|
180
151
|
|
|
181
152
|
export const rootRoute = createRootRouteWithContext<ModernRouterContext>()({
|
|
182
153
|
${rootOpts.join('\n ')}
|
|
183
|
-
|
|
184
|
-
modernRouteId: rootExtras?.id,
|
|
185
|
-
loaderName: rootLoaderName,
|
|
186
|
-
actionName: rootActionName
|
|
187
|
-
}) || ''}
|
|
154
|
+
|
|
188
155
|
});
|
|
189
156
|
|
|
190
157
|
${statements.join('\n\n')}
|
|
@@ -1,17 +1,20 @@
|
|
|
1
1
|
import "node:module";
|
|
2
|
+
import { createLocalisedRouteRewrite } from "@modern-js/i18n-runtime-extensions";
|
|
3
|
+
import { composeRewrites } from "@tanstack/react-router";
|
|
2
4
|
function normalizeBasepath(basepath) {
|
|
3
5
|
if (!basepath) return '/';
|
|
4
6
|
let normalized = basepath.startsWith('/') ? basepath : `/${basepath}`;
|
|
5
7
|
if (normalized.length > 1 && normalized.endsWith('/')) normalized = normalized.slice(0, -1);
|
|
6
8
|
return normalized || '/';
|
|
7
9
|
}
|
|
8
|
-
function createModernBasepathRewrite(basepath, caseSensitive = false) {
|
|
10
|
+
function createModernBasepathRewrite(basepath, caseSensitive = false, routes = []) {
|
|
11
|
+
const localisedRewrite = createLocalisedRouteRewrite(routes);
|
|
9
12
|
const normalizedBasepath = normalizeBasepath(basepath);
|
|
10
|
-
if ('/' === normalizedBasepath) return;
|
|
13
|
+
if ('/' === normalizedBasepath) return localisedRewrite;
|
|
11
14
|
const normalizedBasepathWithSlash = `${normalizedBasepath}/`;
|
|
12
15
|
const checkBasepath = caseSensitive ? normalizedBasepath : normalizedBasepath.toLowerCase();
|
|
13
16
|
const checkBasepathWithSlash = caseSensitive ? normalizedBasepathWithSlash : normalizedBasepathWithSlash.toLowerCase();
|
|
14
|
-
|
|
17
|
+
const basepathRewrite = {
|
|
15
18
|
input: ({ url })=>{
|
|
16
19
|
const pathname = caseSensitive ? url.pathname : url.pathname.toLowerCase();
|
|
17
20
|
if (pathname === checkBasepath) url.pathname = '/';
|
|
@@ -25,5 +28,9 @@ function createModernBasepathRewrite(basepath, caseSensitive = false) {
|
|
|
25
28
|
return url;
|
|
26
29
|
}
|
|
27
30
|
};
|
|
31
|
+
return localisedRewrite ? composeRewrites([
|
|
32
|
+
basepathRewrite,
|
|
33
|
+
localisedRewrite
|
|
34
|
+
]) : basepathRewrite;
|
|
28
35
|
}
|
|
29
36
|
export { createModernBasepathRewrite };
|
|
@@ -1,2 +1,2 @@
|
|
|
1
1
|
import "node:module";
|
|
2
|
-
export { applyRouterRuntimeState, applyRouterServerPrepareResult,
|
|
2
|
+
export { applyRouterRuntimeState, applyRouterServerPrepareResult, createRouterServerSnapshot, getRouterRuntimeState, getRouterServerSnapshot } from "@modern-js/runtime-extensions/router-state";
|
|
@@ -37,10 +37,13 @@ function mapSplatParamsForModernLoader(params, hasSplat) {
|
|
|
37
37
|
return rest;
|
|
38
38
|
}
|
|
39
39
|
function getLoaderSignal(ctx) {
|
|
40
|
-
const
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
40
|
+
const matchSignal = ctx?.abortController?.signal ?? ctx?.signal;
|
|
41
|
+
const requestSignal = ctx?.context?.request?.signal;
|
|
42
|
+
const signals = [
|
|
43
|
+
matchSignal,
|
|
44
|
+
requestSignal
|
|
45
|
+
].filter((signal)=>signal instanceof AbortSignal);
|
|
46
|
+
return AbortSignal.any(signals);
|
|
44
47
|
}
|
|
45
48
|
function getLoaderHref(ctx) {
|
|
46
49
|
if ('string' == typeof ctx?.location) return ctx.location;
|
|
@@ -102,4 +105,4 @@ function modernLoaderToTanstack(opts, modernLoader) {
|
|
|
102
105
|
};
|
|
103
106
|
}
|
|
104
107
|
export { createRouteStaticData } from "../shared/routeStaticData.mjs";
|
|
105
|
-
export { getLoaderHref, handleModernLoaderError, handleModernLoaderResult, isAbsoluteUrl, isRedirectResponse, isResponse, isTanstackRedirect, mapSplatParamsForModernLoader, modernLoaderToTanstack, throwTanstackRedirect };
|
|
108
|
+
export { getLoaderHref, getLoaderSignal, handleModernLoaderError, handleModernLoaderResult, isAbsoluteUrl, isRedirectResponse, isResponse, isTanstackRedirect, mapSplatParamsForModernLoader, modernLoaderToTanstack, throwTanstackRedirect };
|
|
@@ -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";
|
|
@@ -78,7 +79,7 @@ const tanstackRouterPlugin = (userConfig = {})=>{
|
|
|
78
79
|
const mergedConfig = getMergedConfig();
|
|
79
80
|
const { supportHtml5History = true } = mergedConfig;
|
|
80
81
|
const history = supportHtml5History ? createBrowserHistory() : createHashHistory();
|
|
81
|
-
const rewrite = createModernBasepathRewrite(_basename);
|
|
82
|
+
const rewrite = createModernBasepathRewrite(_basename, false, getRouteObjects());
|
|
82
83
|
const serializationAdapters = getGlobalEnableRsc() ? getTanstackRscSerializationAdapters() : void 0;
|
|
83
84
|
const routerFastDefaults = getModernTanstackRouterFastDefaults(mergedConfig);
|
|
84
85
|
cachedRouter = createRouter({
|
|
@@ -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,12 +9,14 @@ 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";
|
|
15
|
+
import { Link } from "./prefetchLink.mjs";
|
|
14
16
|
import { createRouteTreeFromRouteObjects, getModernRouteIdsFromMatches } from "./routeTree/index.mjs";
|
|
15
17
|
import { createTanstackRscServerPayload, handleTanstackRscRedirect } from "./rsc/payloadRouter.mjs";
|
|
16
18
|
import { getTanstackRscRouter, setTanstackRscRouter, setTanstackRscServerPayload } from "./rsc/payloadStorage.mjs";
|
|
17
|
-
import { attachServerSsrUtils, collectRouterErrors, createGetSsrHref, routerManagedTagsToHtml
|
|
19
|
+
import { attachServerSsrUtils, collectRouterErrors, createGetSsrHref, routerManagedTagsToHtml } from "./ssrManagedTags.mjs";
|
|
18
20
|
import { preloadMatchedRouteComponents } from "./ssrPreload.mjs";
|
|
19
21
|
import { getModernTanstackRouterFastDefaults } from "./types.mjs";
|
|
20
22
|
const tanstackRouterPlugin = (userConfig = {})=>{
|
|
@@ -36,6 +38,9 @@ const tanstackRouterPlugin = (userConfig = {})=>{
|
|
|
36
38
|
routeConfig
|
|
37
39
|
});
|
|
38
40
|
if (!modifiedRouteObjects.length) return;
|
|
41
|
+
context.router = {
|
|
42
|
+
Link: Link
|
|
43
|
+
};
|
|
39
44
|
const { request, nonce, baseUrl, loaderFailureMode = 'errorBoundary' } = context.ssrContext;
|
|
40
45
|
const _basename = '/' === baseUrl ? joinBasename(baseUrl, basename || '') : baseUrl;
|
|
41
46
|
const rawRequest = request.raw;
|
|
@@ -58,7 +63,7 @@ const tanstackRouterPlugin = (userConfig = {})=>{
|
|
|
58
63
|
initialHref
|
|
59
64
|
]
|
|
60
65
|
});
|
|
61
|
-
const rewrite = createModernBasepathRewrite(_basename);
|
|
66
|
+
const rewrite = createModernBasepathRewrite(_basename, false, modifiedRouteObjects);
|
|
62
67
|
const routerLifecycleContext = {
|
|
63
68
|
framework: 'tanstack',
|
|
64
69
|
phase: 'ssr-prepare',
|
|
@@ -84,76 +89,93 @@ const tanstackRouterPlugin = (userConfig = {})=>{
|
|
|
84
89
|
});
|
|
85
90
|
const serverRouter = tanstackRouter;
|
|
86
91
|
if (enableRsc) setTanstackRscRouter(serverRouter);
|
|
87
|
-
|
|
88
|
-
|
|
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, {
|
|
103
|
+
framework: 'tanstack',
|
|
104
|
+
basename: _basename,
|
|
105
|
+
instance: serverRouter,
|
|
106
|
+
cleanup
|
|
107
|
+
});
|
|
108
|
+
rawRequest.signal.addEventListener('abort', onAbort, {
|
|
109
|
+
once: true
|
|
110
|
+
});
|
|
89
111
|
try {
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
const cost = end();
|
|
95
|
-
context.ssrContext?.onTiming?.(LOADER_REPORTER_NAME, cost);
|
|
96
|
-
}
|
|
97
|
-
const serverLoadResult = serverRouter._serverResult;
|
|
98
|
-
if (!serverLoadResult) {
|
|
112
|
+
rawRequest.signal.throwIfAborted();
|
|
113
|
+
await attachServerSsrUtils(serverRouter);
|
|
114
|
+
rawRequest.signal.throwIfAborted();
|
|
115
|
+
const end = time();
|
|
99
116
|
try {
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
if (isRSCNavigation) await waitForRouterSerialization(serverRouter);
|
|
124
|
-
setTanstackRscServerPayload(createTanstackRscServerPayload(serverRouter, {
|
|
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) setTanstackRscServerPayload(createTanstackRscServerPayload(serverRouter, {
|
|
125
140
|
omitClientLoaderData: isRSCNavigation
|
|
126
141
|
}));
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
statusCode: serverLoadResult.status,
|
|
135
|
-
errors: routerErrors,
|
|
136
|
-
matchedRouteIds,
|
|
137
|
-
hydrationScripts
|
|
138
|
-
});
|
|
139
|
-
const runtimeContext = applyRouterServerPrepareResult(context, {
|
|
140
|
-
snapshot: routerServerSnapshot,
|
|
141
|
-
cleanup: ()=>serverRouter.serverSsr?.cleanup?.(),
|
|
142
|
-
state: {
|
|
142
|
+
const initialScriptTags = serverRouter.serverSsr?.takeInitialHydrationScriptTags();
|
|
143
|
+
const hydrationScripts = initialScriptTags ? routerManagedTagsToHtml([
|
|
144
|
+
...initialScriptTags.before,
|
|
145
|
+
initialScriptTags.boundary
|
|
146
|
+
]) : [];
|
|
147
|
+
const matchedRouteIds = getModernRouteIdsFromMatches(serverRouter);
|
|
148
|
+
const routerServerSnapshot = {
|
|
143
149
|
framework: 'tanstack',
|
|
144
150
|
basename: _basename,
|
|
145
|
-
|
|
146
|
-
|
|
151
|
+
statusCode: serverLoadResult.status,
|
|
152
|
+
errors: routerErrors,
|
|
147
153
|
matchedRouteIds,
|
|
148
|
-
|
|
149
|
-
}
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
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
|
+
}
|
|
157
179
|
});
|
|
158
180
|
api.wrapRoot((App)=>{
|
|
159
181
|
const getRouteApp = ()=>{
|
|
@@ -1,12 +1,7 @@
|
|
|
1
1
|
import "node:module";
|
|
2
2
|
import { jsx } from "react/jsx-runtime";
|
|
3
|
+
import { resolvePreloadFromPrefetch } from "@modern-js/runtime-extensions";
|
|
3
4
|
import { useLinkProps } from "@tanstack/react-router";
|
|
4
|
-
function resolvePreloadFromPrefetch(prefetch, preload) {
|
|
5
|
-
if (void 0 !== preload) return preload;
|
|
6
|
-
if ('none' === prefetch) return false;
|
|
7
|
-
if ('intent' === prefetch || 'render' === prefetch || 'viewport' === prefetch) return prefetch;
|
|
8
|
-
return 'viewport';
|
|
9
|
-
}
|
|
10
5
|
const LinkComponentImpl = (props)=>{
|
|
11
6
|
const { prefetch, preload, 'aria-current': ariaCurrentProp, ref, children, ...rest } = props;
|
|
12
7
|
const hasAriaCurrentOverride = 'aria-current' in props;
|
|
@@ -1,6 +1,4 @@
|
|
|
1
1
|
import "node:module";
|
|
2
|
-
import { registerRouterProvider } from "@modern-js/runtime/context";
|
|
3
2
|
import { tanstackRouterPlugin } from "./plugin.mjs";
|
|
4
3
|
const tanstackRouterProviderFactory = (userConfig)=>tanstackRouterPlugin(userConfig);
|
|
5
|
-
registerRouterProvider('tanstack', tanstackRouterProviderFactory);
|
|
6
4
|
export { tanstackRouterProviderFactory };
|