@bleedingdev/modern-js-plugin-tanstack 3.2.0-ultramodern.12 → 3.2.0-ultramodern.120
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/cjs/cli/index.js +47 -9
- package/dist/cjs/cli/routeSplitting.js +87 -0
- package/dist/cjs/cli/tanstackTypes.js +230 -63
- package/dist/cjs/cli.js +12 -8
- package/dist/cjs/runtime/DefaultNotFound.js +9 -5
- package/dist/cjs/runtime/basepathRewrite.js +12 -8
- package/dist/cjs/runtime/dataMutation.js +9 -5
- package/dist/cjs/runtime/hooks.js +9 -5
- package/dist/cjs/runtime/hydrationBoundary.js +48 -0
- package/dist/cjs/runtime/index.js +330 -74
- package/dist/cjs/runtime/lifecycle.js +15 -11
- package/dist/cjs/runtime/outlet.js +58 -0
- package/dist/cjs/runtime/plugin.js +203 -98
- package/dist/cjs/runtime/plugin.node.js +38 -16
- package/dist/cjs/runtime/plugin.worker.js +53 -0
- package/dist/cjs/runtime/prefetchLink.js +10 -6
- package/dist/cjs/runtime/routeTree.js +81 -17
- package/dist/cjs/runtime/rsc/ClientSlot.js +9 -5
- package/dist/cjs/runtime/rsc/CompositeComponent.js +9 -5
- package/dist/cjs/runtime/rsc/ReplayableStream.js +14 -9
- package/dist/cjs/runtime/rsc/RscNodeRenderer.js +9 -5
- package/dist/cjs/runtime/rsc/SlotContext.js +9 -5
- package/dist/cjs/runtime/rsc/client.js +9 -5
- package/dist/cjs/runtime/rsc/createRscProxy.js +9 -5
- package/dist/cjs/runtime/rsc/index.js +9 -5
- package/dist/cjs/runtime/rsc/payloadRouter.js +9 -5
- package/dist/cjs/runtime/rsc/server.js +9 -5
- package/dist/cjs/runtime/rsc/slotUsageSanitizer.js +9 -5
- package/dist/cjs/runtime/rsc/symbols.js +20 -15
- package/dist/cjs/runtime/types.js +31 -1
- package/dist/cjs/runtime/utils.js +9 -5
- package/dist/cjs/runtime.js +9 -5
- package/dist/esm/cli/index.mjs +28 -6
- package/dist/esm/cli/routeSplitting.mjs +43 -0
- package/dist/esm/cli/tanstackTypes.mjs +219 -59
- package/dist/esm/runtime/hydrationBoundary.mjs +10 -0
- package/dist/esm/runtime/index.mjs +3 -2
- package/dist/esm/runtime/outlet.mjs +17 -0
- package/dist/esm/runtime/plugin.mjs +197 -96
- package/dist/esm/runtime/plugin.node.mjs +30 -12
- package/dist/esm/runtime/plugin.worker.mjs +1 -0
- package/dist/esm/runtime/prefetchLink.mjs +1 -1
- package/dist/esm/runtime/routeTree.mjs +73 -13
- package/dist/esm/runtime/types.mjs +7 -0
- package/dist/esm-node/cli/index.mjs +28 -6
- package/dist/esm-node/cli/routeSplitting.mjs +44 -0
- package/dist/esm-node/cli/tanstackTypes.mjs +219 -59
- package/dist/esm-node/runtime/hydrationBoundary.mjs +11 -0
- package/dist/esm-node/runtime/index.mjs +3 -2
- package/dist/esm-node/runtime/outlet.mjs +18 -0
- package/dist/esm-node/runtime/plugin.mjs +197 -96
- package/dist/esm-node/runtime/plugin.node.mjs +30 -12
- package/dist/esm-node/runtime/plugin.worker.mjs +2 -0
- package/dist/esm-node/runtime/prefetchLink.mjs +1 -1
- package/dist/esm-node/runtime/routeTree.mjs +73 -13
- package/dist/esm-node/runtime/types.mjs +7 -0
- package/dist/types/cli/index.d.ts +7 -1
- package/dist/types/cli/routeSplitting.d.ts +29 -0
- package/dist/types/cli/tanstackTypes.d.ts +9 -0
- package/dist/types/runtime/hooks.d.ts +9 -24
- package/dist/types/runtime/hydrationBoundary.d.ts +2 -0
- package/dist/types/runtime/index.d.ts +5 -2
- package/dist/types/runtime/outlet.d.ts +2 -0
- package/dist/types/runtime/plugin.d.ts +1 -1
- package/dist/types/runtime/plugin.node.d.ts +1 -1
- package/dist/types/runtime/plugin.worker.d.ts +1 -0
- package/dist/types/runtime/types.d.ts +7 -0
- package/package.json +20 -20
- package/src/cli/index.ts +59 -2
- package/src/cli/routeSplitting.ts +81 -0
- package/src/cli/tanstackTypes.ts +347 -67
- package/src/runtime/hydrationBoundary.tsx +12 -0
- package/src/runtime/index.tsx +107 -2
- package/src/runtime/outlet.tsx +48 -0
- package/src/runtime/plugin.node.tsx +58 -8
- package/src/runtime/plugin.tsx +372 -157
- package/src/runtime/plugin.worker.tsx +4 -0
- package/src/runtime/prefetchLink.tsx +1 -1
- package/src/runtime/routeTree.ts +194 -23
- package/src/runtime/ssr-shim.d.ts +1 -3
- package/src/runtime/types.ts +13 -0
- package/tests/router/cli.test.ts +315 -0
- package/tests/router/fastDefaults.test.ts +25 -0
- package/tests/router/hydrationBoundary.test.tsx +23 -0
- package/tests/router/prefetchLink.test.tsx +43 -7
- package/tests/router/routeTree.test.ts +416 -1
- package/tests/router/tanstackTypes.test.ts +415 -1
package/dist/cjs/runtime.js
CHANGED
|
@@ -24,11 +24,15 @@ function __webpack_require__(moduleId) {
|
|
|
24
24
|
};
|
|
25
25
|
})();
|
|
26
26
|
(()=>{
|
|
27
|
-
__webpack_require__.d = (exports1,
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
27
|
+
__webpack_require__.d = (exports1, getters, values)=>{
|
|
28
|
+
var define = (defs, kind)=>{
|
|
29
|
+
for(var key in defs)if (__webpack_require__.o(defs, key) && !__webpack_require__.o(exports1, key)) Object.defineProperty(exports1, key, {
|
|
30
|
+
enumerable: true,
|
|
31
|
+
[kind]: defs[key]
|
|
32
|
+
});
|
|
33
|
+
};
|
|
34
|
+
define(getters, "get");
|
|
35
|
+
define(values, "value");
|
|
32
36
|
};
|
|
33
37
|
})();
|
|
34
38
|
(()=>{
|
package/dist/esm/cli/index.mjs
CHANGED
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import node_path from "node:path";
|
|
2
2
|
import { NESTED_ROUTE_SPEC_FILE, filterRoutesForServer, fs } from "@modern-js/utils";
|
|
3
|
-
import {
|
|
3
|
+
import { createTanstackRsbuildRouteSplittingProfile, isTanstackStartRouteModuleSource, resolveTanstackRouteCodeSplittingEnabled } from "./routeSplitting.mjs";
|
|
4
|
+
import { collectCanonicalRoutesForEntry, generateTanstackRouterTypesSourceForEntry, isTanstackRouterFrameworkEnabled } from "./tanstackTypes.mjs";
|
|
4
5
|
import { __webpack_require__ } from "../rslib-runtime.mjs";
|
|
5
6
|
import * as __rspack_external__modern_js_runtime_cli_401ee077 from "@modern-js/runtime/cli";
|
|
6
7
|
__webpack_require__.add({
|
|
@@ -31,6 +32,14 @@ async function writeFileIfChanged(filePath, content) {
|
|
|
31
32
|
function createRegisterDtsContent(opts) {
|
|
32
33
|
const importStatements = opts.entries.map((entryName, index)=>`import type { router as router${index} } from './${entryName}/router.gen';`).join('\n');
|
|
33
34
|
const routerUnionType = opts.entries.map((_, index)=>`typeof router${index}`).join(' | ');
|
|
35
|
+
const canonicalEntries = Object.entries(opts.canonicalRoutes ?? {});
|
|
36
|
+
const canonicalRoutesAugmentation = canonicalEntries.length > 0 ? `
|
|
37
|
+
declare module '${opts.i18nRuntimeModule || '@modern-js/plugin-i18n/runtime'}' {
|
|
38
|
+
interface UltramodernCanonicalRoutes {
|
|
39
|
+
${canonicalEntries.map(([routePath, paramsType])=>` '${routePath}': ${paramsType};`).join('\n')}
|
|
40
|
+
}
|
|
41
|
+
}
|
|
42
|
+
` : '';
|
|
34
43
|
return `// This file is auto-generated by Modern.js. Do not edit manually.
|
|
35
44
|
|
|
36
45
|
${importStatements}
|
|
@@ -40,15 +49,17 @@ declare module '${opts.runtimeModule}' {
|
|
|
40
49
|
router: ${routerUnionType};
|
|
41
50
|
}
|
|
42
51
|
}
|
|
43
|
-
`;
|
|
52
|
+
${canonicalRoutesAugmentation}`;
|
|
44
53
|
}
|
|
45
54
|
async function writeTanstackRegisterFile(opts) {
|
|
46
|
-
const { entries, generatedDirName = DEFAULT_GENERATED_DIR_NAME, runtimeModule = '@modern-js/plugin-tanstack/runtime', srcDirectory } = opts;
|
|
55
|
+
const { entries, generatedDirName = DEFAULT_GENERATED_DIR_NAME, runtimeModule = '@modern-js/plugin-tanstack/runtime', srcDirectory, canonicalRoutes, i18nRuntimeModule } = opts;
|
|
47
56
|
if (0 === entries.length) return;
|
|
48
57
|
const registerDtsPath = node_path.join(srcDirectory, generatedDirName, 'register.gen.d.ts');
|
|
49
58
|
await writeFileIfChanged(registerDtsPath, createRegisterDtsContent({
|
|
50
59
|
entries,
|
|
51
|
-
runtimeModule
|
|
60
|
+
runtimeModule,
|
|
61
|
+
canonicalRoutes,
|
|
62
|
+
i18nRuntimeModule
|
|
52
63
|
}));
|
|
53
64
|
}
|
|
54
65
|
async function writeTanstackRouterTypesForEntries(opts) {
|
|
@@ -69,15 +80,25 @@ async function writeTanstackRouterTypesForEntries(opts) {
|
|
|
69
80
|
if (mainEntryName && b === mainEntryName) return 1;
|
|
70
81
|
return a.localeCompare(b);
|
|
71
82
|
});
|
|
83
|
+
let canonicalRoutes = null;
|
|
84
|
+
for (const entryName of registerEntries){
|
|
85
|
+
const entryCanonicalRoutes = collectCanonicalRoutesForEntry(routesByEntry[entryName]);
|
|
86
|
+
if (entryCanonicalRoutes) canonicalRoutes = {
|
|
87
|
+
...entryCanonicalRoutes,
|
|
88
|
+
...canonicalRoutes ?? {}
|
|
89
|
+
};
|
|
90
|
+
}
|
|
72
91
|
await writeTanstackRegisterFile({
|
|
73
92
|
entries: registerEntries,
|
|
74
93
|
generatedDirName,
|
|
75
|
-
srcDirectory: appContext.srcDirectory
|
|
94
|
+
srcDirectory: appContext.srcDirectory,
|
|
95
|
+
canonicalRoutes
|
|
76
96
|
});
|
|
77
97
|
}
|
|
78
98
|
function tanstackRouterPlugin(options = {}) {
|
|
79
99
|
const routesDir = options.routesDir || DEFAULT_ROUTES_DIR;
|
|
80
100
|
const generatedDirName = options.generatedDirName || DEFAULT_GENERATED_DIR_NAME;
|
|
101
|
+
const routeSplittingProfile = createTanstackRsbuildRouteSplittingProfile(options);
|
|
81
102
|
return {
|
|
82
103
|
name: '@modern-js/plugin-tanstack',
|
|
83
104
|
required: [
|
|
@@ -113,6 +134,7 @@ function tanstackRouterPlugin(options = {}) {
|
|
|
113
134
|
entry: entry || getRuntimeRouterCli().isRouteEntry(entryPath, routesDir)
|
|
114
135
|
}));
|
|
115
136
|
api.config(()=>({
|
|
137
|
+
...routeSplittingProfile.defaultConfig,
|
|
116
138
|
source: {
|
|
117
139
|
include: [
|
|
118
140
|
/[\\/]node_modules[\\/]@tanstack[\\/]react-router[\\/]/,
|
|
@@ -195,4 +217,4 @@ function tanstackRouterPlugin(options = {}) {
|
|
|
195
217
|
}
|
|
196
218
|
const src_cli = tanstackRouterPlugin;
|
|
197
219
|
export default src_cli;
|
|
198
|
-
export { generateTanstackRouterTypesSourceForEntry, isTanstackRouterFrameworkEnabled, tanstackRouterPlugin, writeTanstackRegisterFile, writeTanstackRouterTypesForEntries };
|
|
220
|
+
export { collectCanonicalRoutesForEntry, createTanstackRsbuildRouteSplittingProfile, generateTanstackRouterTypesSourceForEntry, isTanstackRouterFrameworkEnabled, isTanstackStartRouteModuleSource, resolveTanstackRouteCodeSplittingEnabled, tanstackRouterPlugin, writeTanstackRegisterFile, writeTanstackRouterTypesForEntries };
|
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
const TANSTACK_START_ROUTE_FACTORY_CALLS = [
|
|
2
|
+
'createFileRoute',
|
|
3
|
+
'createRootRoute',
|
|
4
|
+
'createRootRouteWithContext'
|
|
5
|
+
];
|
|
6
|
+
const TANSTACK_START_ROUTE_FACTORY_REGEX = /\b(createFileRoute|createRootRoute|createRootRouteWithContext)\s*(?:<|\()/;
|
|
7
|
+
function isTanstackStartRouteModuleSource(source) {
|
|
8
|
+
return TANSTACK_START_ROUTE_FACTORY_REGEX.test(source);
|
|
9
|
+
}
|
|
10
|
+
function resolveTanstackRouteCodeSplittingEnabled(option) {
|
|
11
|
+
if ('boolean' == typeof option) return option;
|
|
12
|
+
return option?.enabled ?? true;
|
|
13
|
+
}
|
|
14
|
+
function createTanstackRsbuildRouteSplittingProfile(opts) {
|
|
15
|
+
return {
|
|
16
|
+
defaultConfig: {
|
|
17
|
+
output: {
|
|
18
|
+
splitRouteChunks: resolveTanstackRouteCodeSplittingEnabled(opts.routeCodeSplitting)
|
|
19
|
+
}
|
|
20
|
+
},
|
|
21
|
+
modernRouteChunks: {
|
|
22
|
+
enabled: resolveTanstackRouteCodeSplittingEnabled(opts.routeCodeSplitting),
|
|
23
|
+
owner: 'modern'
|
|
24
|
+
},
|
|
25
|
+
builderChunkSplit: {
|
|
26
|
+
owner: 'modern-rsbuild',
|
|
27
|
+
preserved: true
|
|
28
|
+
},
|
|
29
|
+
tanstackStartRspackSplitter: {
|
|
30
|
+
compatible: false,
|
|
31
|
+
reason: 'TanStack Start Rsbuild route splitting is tied to TanStack file-route factory modules; Modern generates TanStack route trees from Modern route metadata and owns route chunking through output.splitRouteChunks.',
|
|
32
|
+
clientDeleteNodes: [
|
|
33
|
+
'ssr',
|
|
34
|
+
'server',
|
|
35
|
+
'headers'
|
|
36
|
+
],
|
|
37
|
+
routeFactoryCalls: [
|
|
38
|
+
...TANSTACK_START_ROUTE_FACTORY_CALLS
|
|
39
|
+
]
|
|
40
|
+
}
|
|
41
|
+
};
|
|
42
|
+
}
|
|
43
|
+
export { createTanstackRsbuildRouteSplittingProfile, isTanstackStartRouteModuleSource, resolveTanstackRouteCodeSplittingEnabled };
|
|
@@ -55,6 +55,14 @@ function pickModernLoaderModule(route) {
|
|
|
55
55
|
inline
|
|
56
56
|
};
|
|
57
57
|
}
|
|
58
|
+
function pickRouteSearchContractModules(route) {
|
|
59
|
+
const validateSearchPath = route.validateSearch;
|
|
60
|
+
const loaderDepsPath = route.loaderDeps;
|
|
61
|
+
return {
|
|
62
|
+
validateSearchPath: 'string' == typeof validateSearchPath ? validateSearchPath : null,
|
|
63
|
+
loaderDepsPath: 'string' == typeof loaderDepsPath ? loaderDepsPath : null
|
|
64
|
+
};
|
|
65
|
+
}
|
|
58
66
|
function isPathlessLayout(route) {
|
|
59
67
|
return 'nested' === route.type && 'boolean' != typeof route.index && void 0 === route.path;
|
|
60
68
|
}
|
|
@@ -69,6 +77,78 @@ function createRouteStaticDataSnippet(opts) {
|
|
|
69
77
|
if (!staticDataLines.length) return null;
|
|
70
78
|
return `staticData: createRouteStaticData({\n ${staticDataLines.join('\n ')}\n }),`;
|
|
71
79
|
}
|
|
80
|
+
const LOCALE_PARAM_SEGMENTS = new Set([
|
|
81
|
+
':lang',
|
|
82
|
+
':locale',
|
|
83
|
+
':language',
|
|
84
|
+
'$lang',
|
|
85
|
+
'$locale',
|
|
86
|
+
'$language'
|
|
87
|
+
]);
|
|
88
|
+
function paramsTypeForCanonicalPath(canonicalPath) {
|
|
89
|
+
const fields = [];
|
|
90
|
+
for (const segment of canonicalPath.split('/'))if (segment) {
|
|
91
|
+
if ('*' === segment || '$' === segment) {
|
|
92
|
+
fields.push("'_splat'?: string");
|
|
93
|
+
continue;
|
|
94
|
+
}
|
|
95
|
+
if (segment.startsWith('{-$') && segment.endsWith('}')) {
|
|
96
|
+
fields.push(`${JSON.stringify(segment.slice(3, -1))}?: string`);
|
|
97
|
+
continue;
|
|
98
|
+
}
|
|
99
|
+
if (segment.startsWith('$')) {
|
|
100
|
+
fields.push(`${JSON.stringify(segment.slice(1))}: string`);
|
|
101
|
+
continue;
|
|
102
|
+
}
|
|
103
|
+
if (segment.startsWith(':')) {
|
|
104
|
+
const optional = segment.endsWith('?');
|
|
105
|
+
const name = segment.slice(1, optional ? void 0 : segment.length);
|
|
106
|
+
fields.push(`${JSON.stringify(optional ? name.slice(0, -1) : name)}${optional ? '?' : ''}: string`);
|
|
107
|
+
}
|
|
108
|
+
}
|
|
109
|
+
return fields.length > 0 ? `{ ${fields.join('; ')} }` : 'Record<string, never>';
|
|
110
|
+
}
|
|
111
|
+
function collectCanonicalRoutesForEntry(routes) {
|
|
112
|
+
const canonicalParams = new Map();
|
|
113
|
+
let hasI18nSurface = false;
|
|
114
|
+
const normalizeJoined = (joined)=>{
|
|
115
|
+
const collapsed = joined.replace(/\/+/g, '/');
|
|
116
|
+
const withLeading = collapsed.startsWith('/') ? collapsed : `/${collapsed}`;
|
|
117
|
+
return withLeading.length > 1 ? withLeading.replace(/\/+$/, '') : withLeading;
|
|
118
|
+
};
|
|
119
|
+
const record = (canonicalPath)=>{
|
|
120
|
+
const normalized = normalizeJoined(canonicalPath || '/');
|
|
121
|
+
const key = toTanstackPath(normalized);
|
|
122
|
+
if (!canonicalParams.has(key)) canonicalParams.set(key, paramsTypeForCanonicalPath(normalized));
|
|
123
|
+
};
|
|
124
|
+
const visit = (route, parentPath)=>{
|
|
125
|
+
let currentPath = parentPath;
|
|
126
|
+
if ('string' == typeof route.modernCanonicalPath) {
|
|
127
|
+
hasI18nSurface = true;
|
|
128
|
+
currentPath = normalizeJoined(route.modernCanonicalPath);
|
|
129
|
+
} else if ('string' == typeof route.path && route.path.length > 0) {
|
|
130
|
+
const segments = route.path.replace(/\[(.+?)\]/g, ':$1').split('/').filter(Boolean);
|
|
131
|
+
if ('' === parentPath && LOCALE_PARAM_SEGMENTS.has(segments[0])) {
|
|
132
|
+
hasI18nSurface = true;
|
|
133
|
+
segments.shift();
|
|
134
|
+
}
|
|
135
|
+
currentPath = segments.length ? normalizeJoined(`${parentPath}/${segments.join('/')}`) : parentPath;
|
|
136
|
+
}
|
|
137
|
+
const children = route.children;
|
|
138
|
+
if (children && children.length > 0) {
|
|
139
|
+
for (const child of children)visit(child, currentPath);
|
|
140
|
+
return;
|
|
141
|
+
}
|
|
142
|
+
record(currentPath || '/');
|
|
143
|
+
};
|
|
144
|
+
const rootModern = routes.find((route)=>route.isRoot);
|
|
145
|
+
const topLevel = rootModern ? rootModern.children ?? [] : routes;
|
|
146
|
+
for (const route of topLevel)visit(route, '');
|
|
147
|
+
if (!hasI18nSurface || 0 === canonicalParams.size) return null;
|
|
148
|
+
return Object.fromEntries([
|
|
149
|
+
...canonicalParams.entries()
|
|
150
|
+
].sort(([a], [b])=>a.localeCompare(b)));
|
|
151
|
+
}
|
|
72
152
|
async function isTanstackRouterFrameworkEnabled(appContext) {
|
|
73
153
|
const runtimeConfigBase = path.join(appContext.srcDirectory, appContext.runtimeConfigFile);
|
|
74
154
|
const runtimeConfigFile = findExists(JS_OR_TS_EXTS.map((ext)=>`${runtimeConfigBase}${ext}`));
|
|
@@ -88,8 +168,21 @@ async function generateTanstackRouterTypesSourceForEntry(opts) {
|
|
|
88
168
|
const imports = [];
|
|
89
169
|
const statements = [];
|
|
90
170
|
const loaderImportMap = new Map();
|
|
171
|
+
const searchContractImportMap = new Map();
|
|
172
|
+
const usedRouteVarNames = new Set();
|
|
91
173
|
let loaderIndex = 0;
|
|
174
|
+
let validateSearchIndex = 0;
|
|
175
|
+
let loaderDepsIndex = 0;
|
|
92
176
|
let routeIndex = 0;
|
|
177
|
+
const resolveRouteModuleNoExt = async (aliasedNoExtPath)=>{
|
|
178
|
+
const prefix = `${appContext.internalSrcAlias}/`;
|
|
179
|
+
let absNoExt;
|
|
180
|
+
if (aliasedNoExtPath.startsWith(prefix)) {
|
|
181
|
+
const rel = aliasedNoExtPath.slice(prefix.length);
|
|
182
|
+
absNoExt = path.join(appContext.srcDirectory, rel);
|
|
183
|
+
} else absNoExt = path.isAbsolute(aliasedNoExtPath) ? aliasedNoExtPath : path.join(appContext.srcDirectory, aliasedNoExtPath);
|
|
184
|
+
return resolveFileNoExt(absNoExt);
|
|
185
|
+
};
|
|
93
186
|
const getImportNamesForLoader = async (aliasedNoExtPath, inline, hasAction)=>{
|
|
94
187
|
const key = `${inline ? 'inline' : 'default'}:${hasAction ? 'action' : 'loader'}:${aliasedNoExtPath}`;
|
|
95
188
|
const existing = loaderImportMap.get(key);
|
|
@@ -97,13 +190,7 @@ async function generateTanstackRouterTypesSourceForEntry(opts) {
|
|
|
97
190
|
loaderName: existing,
|
|
98
191
|
actionName: hasAction ? existing.replace(/^loader_/, 'action_') : null
|
|
99
192
|
};
|
|
100
|
-
const
|
|
101
|
-
let absNoExt;
|
|
102
|
-
if (aliasedNoExtPath.startsWith(prefix)) {
|
|
103
|
-
const rel = aliasedNoExtPath.slice(prefix.length);
|
|
104
|
-
absNoExt = path.join(appContext.srcDirectory, rel);
|
|
105
|
-
} else absNoExt = path.isAbsolute(aliasedNoExtPath) ? aliasedNoExtPath : path.join(appContext.srcDirectory, aliasedNoExtPath);
|
|
106
|
-
const resolvedNoExt = await resolveFileNoExt(absNoExt);
|
|
193
|
+
const resolvedNoExt = await resolveRouteModuleNoExt(aliasedNoExtPath);
|
|
107
194
|
if (!resolvedNoExt) return null;
|
|
108
195
|
const relImport = normalizeRelativeImport(path.relative(outDir, resolvedNoExt));
|
|
109
196
|
const importName = `loader_${loaderIndex++}`;
|
|
@@ -121,10 +208,29 @@ async function generateTanstackRouterTypesSourceForEntry(opts) {
|
|
|
121
208
|
actionName
|
|
122
209
|
};
|
|
123
210
|
};
|
|
211
|
+
const getImportNameForSearchContract = async (aliasedNoExtPath, exportName)=>{
|
|
212
|
+
const key = `${exportName}:${aliasedNoExtPath}`;
|
|
213
|
+
const existing = searchContractImportMap.get(key);
|
|
214
|
+
if (existing) return existing;
|
|
215
|
+
const resolvedNoExt = await resolveRouteModuleNoExt(aliasedNoExtPath);
|
|
216
|
+
if (!resolvedNoExt) return null;
|
|
217
|
+
const relImport = normalizeRelativeImport(path.relative(outDir, resolvedNoExt));
|
|
218
|
+
const importName = 'validateSearch' === exportName ? `validateSearch_${validateSearchIndex++}` : `loaderDeps_${loaderDepsIndex++}`;
|
|
219
|
+
imports.push(`import { ${exportName} as ${importName} } from ${quote(relImport)};`);
|
|
220
|
+
searchContractImportMap.set(key, importName);
|
|
221
|
+
return importName;
|
|
222
|
+
};
|
|
223
|
+
const reserveRouteVarName = (preferred)=>{
|
|
224
|
+
let candidate = preferred;
|
|
225
|
+
let suffix = 1;
|
|
226
|
+
while(usedRouteVarNames.has(candidate))candidate = `${preferred}_${suffix++}`;
|
|
227
|
+
usedRouteVarNames.add(candidate);
|
|
228
|
+
return candidate;
|
|
229
|
+
};
|
|
124
230
|
const createRouteVarName = (route)=>{
|
|
125
231
|
const id = route.id;
|
|
126
232
|
const base = id ? makeLegalIdentifier(id) : `r_${routeIndex++}`;
|
|
127
|
-
return `route_${base}
|
|
233
|
+
return reserveRouteVarName(`route_${base}`);
|
|
128
234
|
};
|
|
129
235
|
const buildRoute = async (opts)=>{
|
|
130
236
|
const { parentVar, route } = opts;
|
|
@@ -134,6 +240,9 @@ async function generateTanstackRouterTypesSourceForEntry(opts) {
|
|
|
134
240
|
const loaderImports = loaderInfo ? await getImportNamesForLoader(loaderInfo.loaderPath, loaderInfo.inline, Boolean(loaderInfo.inline && routeAction === loaderInfo.loaderPath)) : null;
|
|
135
241
|
const loaderName = loaderImports?.loaderName || null;
|
|
136
242
|
const actionName = loaderImports?.actionName || null;
|
|
243
|
+
const searchContractInfo = pickRouteSearchContractModules(route);
|
|
244
|
+
const validateSearchName = searchContractInfo.validateSearchPath ? await getImportNameForSearchContract(searchContractInfo.validateSearchPath, 'validateSearch') : null;
|
|
245
|
+
const loaderDepsName = searchContractInfo.loaderDepsPath ? await getImportNameForSearchContract(searchContractInfo.loaderDepsPath, 'loaderDeps') : null;
|
|
137
246
|
const rawPath = route.path;
|
|
138
247
|
const hasSplat = 'string' == typeof rawPath && rawPath.includes('*');
|
|
139
248
|
const routeOpts = [
|
|
@@ -147,20 +256,24 @@ async function generateTanstackRouterTypesSourceForEntry(opts) {
|
|
|
147
256
|
routeOpts.push(`path: ${quote(p)},`);
|
|
148
257
|
}
|
|
149
258
|
if (loaderName) routeOpts.push(`loader: modernLoaderToTanstack({ hasSplat: ${hasSplat} }, ${loaderName}),`);
|
|
259
|
+
if (validateSearchName) routeOpts.push(`validateSearch: ${validateSearchName},`);
|
|
260
|
+
if (loaderDepsName) routeOpts.push(`loaderDeps: ${loaderDepsName},`);
|
|
150
261
|
const staticDataSnippet = createRouteStaticDataSnippet({
|
|
151
262
|
modernRouteId: route.id,
|
|
152
263
|
loaderName,
|
|
153
264
|
actionName
|
|
154
265
|
});
|
|
155
266
|
if (staticDataSnippet) routeOpts.push(staticDataSnippet);
|
|
156
|
-
statements.push(`const ${varName} = createRoute({\n ${routeOpts.join('\n ')}\n});`);
|
|
157
267
|
const children = route.children;
|
|
268
|
+
const hasChildren = Boolean(children && children.length > 0);
|
|
269
|
+
const routeCtorVarName = hasChildren ? reserveRouteVarName(`${varName}__base`) : varName;
|
|
270
|
+
statements.push(`const ${routeCtorVarName} = createRoute({\n ${routeOpts.join('\n ')}\n});`);
|
|
158
271
|
if (children && children.length > 0) {
|
|
159
272
|
const childVars = await Promise.all(children.map((child)=>buildRoute({
|
|
160
|
-
parentVar:
|
|
273
|
+
parentVar: routeCtorVarName,
|
|
161
274
|
route: child
|
|
162
275
|
})));
|
|
163
|
-
statements.push(
|
|
276
|
+
statements.push(`const ${varName} = ${routeCtorVarName}.addChildren([${childVars.join(', ')}]);`);
|
|
164
277
|
}
|
|
165
278
|
return varName;
|
|
166
279
|
};
|
|
@@ -169,17 +282,23 @@ async function generateTanstackRouterTypesSourceForEntry(opts) {
|
|
|
169
282
|
const rootLoaderImports = rootLoaderInfo?.loaderPath ? await getImportNamesForLoader(rootLoaderInfo.loaderPath, rootLoaderInfo.inline, Boolean(rootLoaderInfo.inline && rootAction === rootLoaderInfo.loaderPath)) : null;
|
|
170
283
|
const rootLoaderName = rootLoaderImports?.loaderName || null;
|
|
171
284
|
const rootActionName = rootLoaderImports?.actionName || null;
|
|
285
|
+
const rootSearchContractInfo = rootModern ? pickRouteSearchContractModules(rootModern) : null;
|
|
286
|
+
const rootValidateSearchName = rootSearchContractInfo?.validateSearchPath ? await getImportNameForSearchContract(rootSearchContractInfo.validateSearchPath, 'validateSearch') : null;
|
|
287
|
+
const rootLoaderDepsName = rootSearchContractInfo?.loaderDepsPath ? await getImportNameForSearchContract(rootSearchContractInfo.loaderDepsPath, 'loaderDeps') : null;
|
|
172
288
|
const topLevelVars = await Promise.all(topLevel.map((route)=>buildRoute({
|
|
173
289
|
parentVar: 'rootRoute',
|
|
174
290
|
route
|
|
175
291
|
})));
|
|
176
292
|
const rootOpts = [];
|
|
177
293
|
if (rootLoaderName) rootOpts.push(`loader: modernLoaderToTanstack({ hasSplat: false }, ${rootLoaderName}),`);
|
|
294
|
+
if (rootValidateSearchName) rootOpts.push(`validateSearch: ${rootValidateSearchName},`);
|
|
295
|
+
if (rootLoaderDepsName) rootOpts.push(`loaderDeps: ${rootLoaderDepsName},`);
|
|
178
296
|
const routerGenTs = `/* eslint-disable */
|
|
179
297
|
// This file is auto-generated by Modern.js. Do not edit manually.
|
|
180
298
|
|
|
181
299
|
import {
|
|
182
300
|
createMemoryHistory,
|
|
301
|
+
modernTanstackRouterFastDefaults,
|
|
183
302
|
createRootRouteWithContext,
|
|
184
303
|
createRoute,
|
|
185
304
|
createRouter,
|
|
@@ -207,7 +326,7 @@ function isRedirectResponse(res: Response) {
|
|
|
207
326
|
}
|
|
208
327
|
|
|
209
328
|
function throwTanstackRedirect(location: string) {
|
|
210
|
-
const target = location
|
|
329
|
+
const target = location.length > 0 ? location : '/';
|
|
211
330
|
try {
|
|
212
331
|
void new URL(target);
|
|
213
332
|
throw redirect({ href: target });
|
|
@@ -233,21 +352,87 @@ function createRouteStaticData(opts: {
|
|
|
233
352
|
modernRouteAction?: unknown;
|
|
234
353
|
modernRouteLoader?: unknown;
|
|
235
354
|
}) {
|
|
236
|
-
const staticData:
|
|
355
|
+
const staticData: {
|
|
356
|
+
modernRouteId?: string;
|
|
357
|
+
modernRouteAction?: unknown;
|
|
358
|
+
modernRouteLoader?: unknown;
|
|
359
|
+
} = {};
|
|
237
360
|
|
|
238
|
-
if (opts.modernRouteId) {
|
|
361
|
+
if (typeof opts.modernRouteId === 'string' && opts.modernRouteId.length > 0) {
|
|
239
362
|
staticData.modernRouteId = opts.modernRouteId;
|
|
240
363
|
}
|
|
241
364
|
|
|
242
|
-
if (opts.modernRouteLoader) {
|
|
365
|
+
if (typeof opts.modernRouteLoader !== 'undefined') {
|
|
243
366
|
staticData.modernRouteLoader = opts.modernRouteLoader;
|
|
244
367
|
}
|
|
245
368
|
|
|
246
|
-
if (opts.modernRouteAction) {
|
|
369
|
+
if (typeof opts.modernRouteAction !== 'undefined') {
|
|
247
370
|
staticData.modernRouteAction = opts.modernRouteAction;
|
|
248
371
|
}
|
|
249
372
|
|
|
250
|
-
return
|
|
373
|
+
return staticData;
|
|
374
|
+
}
|
|
375
|
+
|
|
376
|
+
function getLoaderSignal(ctx: any): AbortSignal {
|
|
377
|
+
const abortSignal = ctx?.abortController?.signal;
|
|
378
|
+
if (abortSignal instanceof AbortSignal) {
|
|
379
|
+
return abortSignal;
|
|
380
|
+
}
|
|
381
|
+
if (ctx?.signal instanceof AbortSignal) {
|
|
382
|
+
return ctx.signal;
|
|
383
|
+
}
|
|
384
|
+
return new AbortController().signal;
|
|
385
|
+
}
|
|
386
|
+
|
|
387
|
+
function getLoaderHref(ctx: any): string {
|
|
388
|
+
if (typeof ctx?.location === 'string') {
|
|
389
|
+
return ctx.location;
|
|
390
|
+
}
|
|
391
|
+
|
|
392
|
+
const publicHref = ctx?.location?.publicHref;
|
|
393
|
+
if (typeof publicHref === 'string') {
|
|
394
|
+
return publicHref;
|
|
395
|
+
}
|
|
396
|
+
|
|
397
|
+
const href = ctx?.location?.href;
|
|
398
|
+
if (typeof href === 'string') {
|
|
399
|
+
return href;
|
|
400
|
+
}
|
|
401
|
+
|
|
402
|
+
const urlHref = ctx?.location?.url?.href;
|
|
403
|
+
return typeof urlHref === 'string' ? urlHref : '';
|
|
404
|
+
}
|
|
405
|
+
|
|
406
|
+
function getLoaderParams(ctx: any): Record<string, string> {
|
|
407
|
+
return typeof ctx?.params === 'object' && ctx.params !== null ? ctx.params : {};
|
|
408
|
+
}
|
|
409
|
+
|
|
410
|
+
function handleModernLoaderResult<LoaderResult>(result: LoaderResult): LoaderResult {
|
|
411
|
+
if (isResponse(result)) {
|
|
412
|
+
if (isRedirectResponse(result)) {
|
|
413
|
+
const location = result.headers.get('Location') ?? '/';
|
|
414
|
+
throwTanstackRedirect(location);
|
|
415
|
+
}
|
|
416
|
+
if (result.status === 404) {
|
|
417
|
+
throw notFound();
|
|
418
|
+
}
|
|
419
|
+
}
|
|
420
|
+
|
|
421
|
+
return result;
|
|
422
|
+
}
|
|
423
|
+
|
|
424
|
+
function handleModernLoaderError(err: unknown): never {
|
|
425
|
+
if (isResponse(err)) {
|
|
426
|
+
if (isRedirectResponse(err)) {
|
|
427
|
+
const location = err.headers.get('Location') ?? '/';
|
|
428
|
+
throwTanstackRedirect(location);
|
|
429
|
+
}
|
|
430
|
+
if (err.status === 404) {
|
|
431
|
+
throw notFound();
|
|
432
|
+
}
|
|
433
|
+
}
|
|
434
|
+
|
|
435
|
+
throw err;
|
|
251
436
|
}
|
|
252
437
|
|
|
253
438
|
function modernLoaderToTanstack<TLoader extends (args: any) => any>(
|
|
@@ -256,57 +441,31 @@ function modernLoaderToTanstack<TLoader extends (args: any) => any>(
|
|
|
256
441
|
) {
|
|
257
442
|
type LoaderResult = Awaited<ReturnType<TLoader>>;
|
|
258
443
|
|
|
259
|
-
return
|
|
444
|
+
return (ctx: any): Promise<LoaderResult> => {
|
|
260
445
|
try {
|
|
261
|
-
const signal
|
|
262
|
-
ctx?.abortController?.signal ||
|
|
263
|
-
ctx?.signal ||
|
|
264
|
-
new AbortController().signal;
|
|
446
|
+
const signal = getLoaderSignal(ctx);
|
|
265
447
|
const baseRequest: Request | undefined =
|
|
266
448
|
ctx?.context?.request instanceof Request ? ctx.context.request : undefined;
|
|
267
449
|
|
|
268
|
-
const href =
|
|
269
|
-
typeof ctx?.location === 'string'
|
|
270
|
-
? ctx.location
|
|
271
|
-
: ctx?.location?.publicHref ||
|
|
272
|
-
ctx?.location?.href ||
|
|
273
|
-
ctx?.location?.url?.href ||
|
|
274
|
-
'';
|
|
450
|
+
const href = getLoaderHref(ctx);
|
|
275
451
|
|
|
276
|
-
const request = baseRequest
|
|
452
|
+
const request = baseRequest !== undefined
|
|
277
453
|
? new Request(baseRequest, { signal })
|
|
278
454
|
: new Request(href, { signal });
|
|
279
455
|
|
|
280
|
-
const params = mapParamsForModernLoader(ctx
|
|
281
|
-
|
|
282
|
-
const result = await (modernLoader as any)({
|
|
283
|
-
request,
|
|
284
|
-
params,
|
|
285
|
-
context: ctx?.context?.requestContext,
|
|
286
|
-
});
|
|
287
|
-
|
|
288
|
-
if (isResponse(result)) {
|
|
289
|
-
if (isRedirectResponse(result)) {
|
|
290
|
-
const location = result.headers.get('Location') || '/';
|
|
291
|
-
throwTanstackRedirect(location);
|
|
292
|
-
}
|
|
293
|
-
if (result.status === 404) {
|
|
294
|
-
throw notFound();
|
|
295
|
-
}
|
|
296
|
-
}
|
|
456
|
+
const params = mapParamsForModernLoader(getLoaderParams(ctx), opts.hasSplat);
|
|
297
457
|
|
|
298
|
-
return
|
|
458
|
+
return Promise.resolve(
|
|
459
|
+
(modernLoader as any)({
|
|
460
|
+
request,
|
|
461
|
+
params,
|
|
462
|
+
context: ctx?.context?.requestContext,
|
|
463
|
+
}),
|
|
464
|
+
)
|
|
465
|
+
.then((result: LoaderResult) => handleModernLoaderResult(result))
|
|
466
|
+
.catch(handleModernLoaderError);
|
|
299
467
|
} catch (err) {
|
|
300
|
-
|
|
301
|
-
if (isRedirectResponse(err)) {
|
|
302
|
-
const location = err.headers.get('Location') || '/';
|
|
303
|
-
throwTanstackRedirect(location);
|
|
304
|
-
}
|
|
305
|
-
if (err.status === 404) {
|
|
306
|
-
throw notFound();
|
|
307
|
-
}
|
|
308
|
-
}
|
|
309
|
-
throw err;
|
|
468
|
+
handleModernLoaderError(err);
|
|
310
469
|
}
|
|
311
470
|
};
|
|
312
471
|
}
|
|
@@ -327,6 +486,7 @@ ${statements.join('\n\n')}
|
|
|
327
486
|
export const routeTree = rootRoute.addChildren([${topLevelVars.join(', ')}]);
|
|
328
487
|
|
|
329
488
|
export const router = createRouter({
|
|
489
|
+
...modernTanstackRouterFastDefaults,
|
|
330
490
|
routeTree,
|
|
331
491
|
history: createMemoryHistory({
|
|
332
492
|
initialEntries: ['/'],
|
|
@@ -338,4 +498,4 @@ export const router = createRouter({
|
|
|
338
498
|
routerGenTs
|
|
339
499
|
};
|
|
340
500
|
}
|
|
341
|
-
export { generateTanstackRouterTypesSourceForEntry, isTanstackRouterFrameworkEnabled };
|
|
501
|
+
export { collectCanonicalRoutesForEntry, generateTanstackRouterTypesSourceForEntry, isTanstackRouterFrameworkEnabled };
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
import { jsx } from "react/jsx-runtime";
|
|
2
|
+
import { Suspense } from "react";
|
|
3
|
+
function wrapTanstackSsrHydrationBoundary(routerContent, shouldWrap) {
|
|
4
|
+
if (shouldWrap) return /*#__PURE__*/ jsx(Suspense, {
|
|
5
|
+
fallback: null,
|
|
6
|
+
children: routerContent
|
|
7
|
+
});
|
|
8
|
+
return routerContent;
|
|
9
|
+
}
|
|
10
|
+
export { wrapTanstackSsrHydrationBoundary };
|
|
@@ -1,6 +1,7 @@
|
|
|
1
|
-
export
|
|
2
|
-
export { useMatch } from "@tanstack/react-router";
|
|
1
|
+
export { Asset, Await, Block, CatchBoundary, CatchNotFound, ClientOnly, DEFAULT_PROTOCOL_ALLOWLIST, DefaultGlobalNotFound, ErrorComponent, FileRoute, FileRouteLoader, HeadContent, LazyRoute, Match, MatchRoute, Matches, Navigate, NotFoundRoute, RootRoute, Route, RouteApi, Router, RouterContextProvider, RouterProvider, ScriptOnce, Scripts, ScrollRestoration, SearchParamError, cleanPath, composeRewrites, createBrowserHistory, createControlledPromise, createFileRoute, createHashHistory, createHistory, createLazyFileRoute, createLazyRoute, createLink, createMemoryHistory, createRootRoute, createRootRouteWithContext, createRoute, createRouteMask, createRouter, createRouterConfig, createSerializationAdapter, deepEqual, defaultParseSearch, defaultStringifySearch, defer, functionalUpdate, getRouteApi, interpolatePath, isMatch, isNotFound, isPlainArray, isPlainObject, isRedirect, joinPaths, lazyFn, lazyRouteComponent, linkOptions, notFound, parseSearchWith, reactUse, redirect, replaceEqualDeep, resolvePath, retainSearchParams, rootRouteId, rootRouteWithContext, stringifySearchWith, stripSearchParams, trimPath, trimPathLeft, trimPathRight, useAwaited, useBlocker, useCanGoBack, useChildMatches, useElementScrollRestoration, useHydrated, useLayoutEffect, useLinkProps, useLoaderData, useLoaderDeps, useLocation, useMatch, useMatchRoute, useMatches, useNavigate, useParams, useParentMatches, useRouteContext, useRouter, useRouterState, useSearch, useTags } from "@tanstack/react-router";
|
|
3
2
|
export { Form, RouteActionResponseError, useFetcher } from "./dataMutation.mjs";
|
|
3
|
+
export { Outlet } from "./outlet.mjs";
|
|
4
4
|
export { tanstackRouterPlugin as default, tanstackRouterPlugin } from "./plugin.mjs";
|
|
5
5
|
export { Link, NavLink } from "./prefetchLink.mjs";
|
|
6
6
|
export { CompositeComponent } from "./rsc/client.mjs";
|
|
7
|
+
export { getModernTanstackRouterFastDefaults, modernTanstackRouterFastDefaults } from "./types.mjs";
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
import { jsx } from "react/jsx-runtime";
|
|
2
|
+
import { Outlet } from "@tanstack/react-router";
|
|
3
|
+
import { createElement, memo } from "react";
|
|
4
|
+
const outlet_Outlet = /*#__PURE__*/ memo(function() {
|
|
5
|
+
return /*#__PURE__*/ jsx(Outlet, {});
|
|
6
|
+
});
|
|
7
|
+
function withModernRouteMatchContext(component, _routeId) {
|
|
8
|
+
if (null == component) return component;
|
|
9
|
+
const Component = component;
|
|
10
|
+
const WrappedRouteComponent = (props)=>/*#__PURE__*/ createElement(Component, props);
|
|
11
|
+
const preloadable = component;
|
|
12
|
+
if ('function' == typeof preloadable.load) WrappedRouteComponent.load = preloadable.load.bind(preloadable);
|
|
13
|
+
if ('function' == typeof preloadable.preload) WrappedRouteComponent.preload = preloadable.preload.bind(preloadable);
|
|
14
|
+
else if ('function' == typeof preloadable.load) WrappedRouteComponent.preload = WrappedRouteComponent.load;
|
|
15
|
+
return WrappedRouteComponent;
|
|
16
|
+
}
|
|
17
|
+
export { outlet_Outlet as Outlet, withModernRouteMatchContext };
|