@bleedingdev/modern-js-plugin-tanstack 3.2.0-ultramodern.89 → 3.2.0-ultramodern.90
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 +12 -0
- package/dist/cjs/cli/routeSplitting.js +83 -0
- package/dist/cjs/cli/tanstackTypes.js +45 -7
- package/dist/cjs/runtime/index.js +12 -0
- package/dist/cjs/runtime/plugin.js +2 -0
- package/dist/cjs/runtime/plugin.node.js +2 -0
- package/dist/cjs/runtime/routeTree.js +8 -0
- package/dist/cjs/runtime/types.js +27 -1
- package/dist/esm/cli/index.mjs +4 -1
- package/dist/esm/cli/routeSplitting.mjs +43 -0
- package/dist/esm/cli/tanstackTypes.mjs +45 -7
- package/dist/esm/runtime/index.mjs +1 -0
- package/dist/esm/runtime/plugin.mjs +2 -0
- package/dist/esm/runtime/plugin.node.mjs +2 -0
- package/dist/esm/runtime/routeTree.mjs +8 -0
- package/dist/esm/runtime/types.mjs +7 -0
- package/dist/esm-node/cli/index.mjs +4 -1
- package/dist/esm-node/cli/routeSplitting.mjs +44 -0
- package/dist/esm-node/cli/tanstackTypes.mjs +45 -7
- package/dist/esm-node/runtime/index.mjs +1 -0
- package/dist/esm-node/runtime/plugin.mjs +2 -0
- package/dist/esm-node/runtime/plugin.node.mjs +2 -0
- package/dist/esm-node/runtime/routeTree.mjs +8 -0
- package/dist/esm-node/runtime/types.mjs +7 -0
- package/dist/types/cli/index.d.ts +4 -0
- package/dist/types/cli/routeSplitting.d.ts +29 -0
- package/dist/types/runtime/index.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/types.d.ts +7 -0
- package/package.json +10 -10
- package/src/cli/index.ts +17 -0
- package/src/cli/routeSplitting.ts +81 -0
- package/src/cli/tanstackTypes.ts +102 -13
- package/src/runtime/index.tsx +5 -0
- package/src/runtime/plugin.node.tsx +6 -1
- package/src/runtime/plugin.tsx +5 -1
- package/src/runtime/routeTree.ts +12 -0
- package/src/runtime/types.ts +13 -0
- package/tests/router/cli.test.ts +239 -0
- package/tests/router/fastDefaults.test.ts +25 -0
- package/tests/router/routeTree.test.ts +87 -0
- package/tests/router/tanstackTypes.test.ts +120 -0
|
@@ -12,6 +12,7 @@ import { modifyRoutes, onAfterCreateRouter, onAfterHydrateRouter, onBeforeCreate
|
|
|
12
12
|
import { applyRouterServerPrepareResult, createRouterServerSnapshot } from "./lifecycle.mjs";
|
|
13
13
|
import { createRouteTreeFromRouteObjects, getModernRouteIdsFromMatches } from "./routeTree.mjs";
|
|
14
14
|
import { createTanstackRscServerPayload, handleTanstackRscRedirect } from "./rsc/payloadRouter.mjs";
|
|
15
|
+
import { getModernTanstackRouterFastDefaults } from "./types.mjs";
|
|
15
16
|
import { createRouteObjectsFromConfig, urlJoin } from "./utils.mjs";
|
|
16
17
|
const setTanstackRscServerPayload = (payload)=>{
|
|
17
18
|
const storageContext = storage.useContext?.();
|
|
@@ -177,6 +178,7 @@ const tanstackRouterPlugin = (userConfig = {})=>{
|
|
|
177
178
|
};
|
|
178
179
|
hooks.onBeforeCreateRouter.call(routerLifecycleContext);
|
|
179
180
|
const tanstackRouter = createRouter({
|
|
181
|
+
...getModernTanstackRouterFastDefaults(mergedConfig),
|
|
180
182
|
routeTree,
|
|
181
183
|
history,
|
|
182
184
|
basepath: '/',
|
|
@@ -317,6 +317,8 @@ function createRouteFromRouteObject(opts) {
|
|
|
317
317
|
component: toRouteComponent(routeObject),
|
|
318
318
|
pendingComponent: toPendingComponent(routeObject),
|
|
319
319
|
errorComponent: toErrorComponent(routeObject),
|
|
320
|
+
validateSearch: modernRouteObject.validateSearch,
|
|
321
|
+
loaderDeps: modernRouteObject.loaderDeps,
|
|
320
322
|
wrapInSuspense: true,
|
|
321
323
|
staticData: createRouteStaticData({
|
|
322
324
|
modernRouteId: routeObject.id,
|
|
@@ -367,6 +369,8 @@ function createRouteFromModernRoute(opts) {
|
|
|
367
369
|
component: component || void 0,
|
|
368
370
|
pendingComponent: pendingComponent || void 0,
|
|
369
371
|
errorComponent: errorComponent || void 0,
|
|
372
|
+
validateSearch: route.validateSearch,
|
|
373
|
+
loaderDeps: route.loaderDeps,
|
|
370
374
|
wrapInSuspense: true,
|
|
371
375
|
staticData: createRouteStaticData({
|
|
372
376
|
modernRouteId: modernId,
|
|
@@ -415,6 +419,8 @@ function createRouteTreeFromModernRoutes(routes, options = {}) {
|
|
|
415
419
|
component: rootComponent || void 0,
|
|
416
420
|
pendingComponent: pendingComponent || void 0,
|
|
417
421
|
errorComponent: errorComponent || void 0,
|
|
422
|
+
validateSearch: rootModern?.validateSearch,
|
|
423
|
+
loaderDeps: rootModern?.loaderDeps,
|
|
418
424
|
wrapInSuspense: true,
|
|
419
425
|
notFoundComponent: DefaultNotFound,
|
|
420
426
|
staticData: createRouteStaticData({
|
|
@@ -454,6 +460,8 @@ function createRouteTreeFromRouteObjects(routes, options = {}) {
|
|
|
454
460
|
component: rootLikeRoute ? toRouteComponent(rootLikeRoute) : void 0,
|
|
455
461
|
pendingComponent: rootLikeRoute ? toPendingComponent(rootLikeRoute) : void 0,
|
|
456
462
|
errorComponent: rootLikeRoute ? toErrorComponent(rootLikeRoute) : void 0,
|
|
463
|
+
validateSearch: rootLikeRoute?.validateSearch,
|
|
464
|
+
loaderDeps: rootLikeRoute?.loaderDeps,
|
|
457
465
|
wrapInSuspense: true,
|
|
458
466
|
notFoundComponent: DefaultNotFound,
|
|
459
467
|
staticData: createRouteStaticData({
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
const modernTanstackRouterFastDefaults = {
|
|
2
|
+
defaultStructuralSharing: true
|
|
3
|
+
};
|
|
4
|
+
const getModernTanstackRouterFastDefaults = (config = {})=>({
|
|
5
|
+
defaultStructuralSharing: config.defaultStructuralSharing ?? modernTanstackRouterFastDefaults.defaultStructuralSharing
|
|
6
|
+
});
|
|
7
|
+
export { getModernTanstackRouterFastDefaults, modernTanstackRouterFastDefaults };
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import "node:module";
|
|
2
2
|
import node_path from "node:path";
|
|
3
3
|
import { NESTED_ROUTE_SPEC_FILE, filterRoutesForServer, fs } from "@modern-js/utils";
|
|
4
|
+
import { createTanstackRsbuildRouteSplittingProfile, isTanstackStartRouteModuleSource, resolveTanstackRouteCodeSplittingEnabled } from "./routeSplitting.mjs";
|
|
4
5
|
import { generateTanstackRouterTypesSourceForEntry, isTanstackRouterFrameworkEnabled } from "./tanstackTypes.mjs";
|
|
5
6
|
import { __webpack_require__ } from "../rslib-runtime.mjs";
|
|
6
7
|
import { fileURLToPath as __rspack_fileURLToPath } from "node:url";
|
|
@@ -82,6 +83,7 @@ async function writeTanstackRouterTypesForEntries(opts) {
|
|
|
82
83
|
function tanstackRouterPlugin(options = {}) {
|
|
83
84
|
const routesDir = options.routesDir || DEFAULT_ROUTES_DIR;
|
|
84
85
|
const generatedDirName = options.generatedDirName || DEFAULT_GENERATED_DIR_NAME;
|
|
86
|
+
const routeSplittingProfile = createTanstackRsbuildRouteSplittingProfile(options);
|
|
85
87
|
return {
|
|
86
88
|
name: '@modern-js/plugin-tanstack',
|
|
87
89
|
required: [
|
|
@@ -117,6 +119,7 @@ function tanstackRouterPlugin(options = {}) {
|
|
|
117
119
|
entry: entry || getRuntimeRouterCli().isRouteEntry(entryPath, routesDir)
|
|
118
120
|
}));
|
|
119
121
|
api.config(()=>({
|
|
122
|
+
...routeSplittingProfile.defaultConfig,
|
|
120
123
|
source: {
|
|
121
124
|
include: [
|
|
122
125
|
/[\\/]node_modules[\\/]@tanstack[\\/]react-router[\\/]/,
|
|
@@ -199,4 +202,4 @@ function tanstackRouterPlugin(options = {}) {
|
|
|
199
202
|
}
|
|
200
203
|
const src_cli = tanstackRouterPlugin;
|
|
201
204
|
export default src_cli;
|
|
202
|
-
export { generateTanstackRouterTypesSourceForEntry, isTanstackRouterFrameworkEnabled, tanstackRouterPlugin, writeTanstackRegisterFile, writeTanstackRouterTypesForEntries };
|
|
205
|
+
export { createTanstackRsbuildRouteSplittingProfile, generateTanstackRouterTypesSourceForEntry, isTanstackRouterFrameworkEnabled, isTanstackStartRouteModuleSource, resolveTanstackRouteCodeSplittingEnabled, tanstackRouterPlugin, writeTanstackRegisterFile, writeTanstackRouterTypesForEntries };
|
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
import "node:module";
|
|
2
|
+
const TANSTACK_START_ROUTE_FACTORY_CALLS = [
|
|
3
|
+
'createFileRoute',
|
|
4
|
+
'createRootRoute',
|
|
5
|
+
'createRootRouteWithContext'
|
|
6
|
+
];
|
|
7
|
+
const TANSTACK_START_ROUTE_FACTORY_REGEX = /\b(createFileRoute|createRootRoute|createRootRouteWithContext)\s*(?:<|\()/;
|
|
8
|
+
function isTanstackStartRouteModuleSource(source) {
|
|
9
|
+
return TANSTACK_START_ROUTE_FACTORY_REGEX.test(source);
|
|
10
|
+
}
|
|
11
|
+
function resolveTanstackRouteCodeSplittingEnabled(option) {
|
|
12
|
+
if ('boolean' == typeof option) return option;
|
|
13
|
+
return option?.enabled ?? true;
|
|
14
|
+
}
|
|
15
|
+
function createTanstackRsbuildRouteSplittingProfile(opts) {
|
|
16
|
+
return {
|
|
17
|
+
defaultConfig: {
|
|
18
|
+
output: {
|
|
19
|
+
splitRouteChunks: resolveTanstackRouteCodeSplittingEnabled(opts.routeCodeSplitting)
|
|
20
|
+
}
|
|
21
|
+
},
|
|
22
|
+
modernRouteChunks: {
|
|
23
|
+
enabled: resolveTanstackRouteCodeSplittingEnabled(opts.routeCodeSplitting),
|
|
24
|
+
owner: 'modern'
|
|
25
|
+
},
|
|
26
|
+
builderChunkSplit: {
|
|
27
|
+
owner: 'modern-rsbuild',
|
|
28
|
+
preserved: true
|
|
29
|
+
},
|
|
30
|
+
tanstackStartRspackSplitter: {
|
|
31
|
+
compatible: false,
|
|
32
|
+
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.',
|
|
33
|
+
clientDeleteNodes: [
|
|
34
|
+
'ssr',
|
|
35
|
+
'server',
|
|
36
|
+
'headers'
|
|
37
|
+
],
|
|
38
|
+
routeFactoryCalls: [
|
|
39
|
+
...TANSTACK_START_ROUTE_FACTORY_CALLS
|
|
40
|
+
]
|
|
41
|
+
}
|
|
42
|
+
};
|
|
43
|
+
}
|
|
44
|
+
export { createTanstackRsbuildRouteSplittingProfile, isTanstackStartRouteModuleSource, resolveTanstackRouteCodeSplittingEnabled };
|
|
@@ -56,6 +56,14 @@ function pickModernLoaderModule(route) {
|
|
|
56
56
|
inline
|
|
57
57
|
};
|
|
58
58
|
}
|
|
59
|
+
function pickRouteSearchContractModules(route) {
|
|
60
|
+
const validateSearchPath = route.validateSearch;
|
|
61
|
+
const loaderDepsPath = route.loaderDeps;
|
|
62
|
+
return {
|
|
63
|
+
validateSearchPath: 'string' == typeof validateSearchPath ? validateSearchPath : null,
|
|
64
|
+
loaderDepsPath: 'string' == typeof loaderDepsPath ? loaderDepsPath : null
|
|
65
|
+
};
|
|
66
|
+
}
|
|
59
67
|
function isPathlessLayout(route) {
|
|
60
68
|
return 'nested' === route.type && 'boolean' != typeof route.index && void 0 === route.path;
|
|
61
69
|
}
|
|
@@ -89,9 +97,21 @@ async function generateTanstackRouterTypesSourceForEntry(opts) {
|
|
|
89
97
|
const imports = [];
|
|
90
98
|
const statements = [];
|
|
91
99
|
const loaderImportMap = new Map();
|
|
100
|
+
const searchContractImportMap = new Map();
|
|
92
101
|
const usedRouteVarNames = new Set();
|
|
93
102
|
let loaderIndex = 0;
|
|
103
|
+
let validateSearchIndex = 0;
|
|
104
|
+
let loaderDepsIndex = 0;
|
|
94
105
|
let routeIndex = 0;
|
|
106
|
+
const resolveRouteModuleNoExt = async (aliasedNoExtPath)=>{
|
|
107
|
+
const prefix = `${appContext.internalSrcAlias}/`;
|
|
108
|
+
let absNoExt;
|
|
109
|
+
if (aliasedNoExtPath.startsWith(prefix)) {
|
|
110
|
+
const rel = aliasedNoExtPath.slice(prefix.length);
|
|
111
|
+
absNoExt = path.join(appContext.srcDirectory, rel);
|
|
112
|
+
} else absNoExt = path.isAbsolute(aliasedNoExtPath) ? aliasedNoExtPath : path.join(appContext.srcDirectory, aliasedNoExtPath);
|
|
113
|
+
return resolveFileNoExt(absNoExt);
|
|
114
|
+
};
|
|
95
115
|
const getImportNamesForLoader = async (aliasedNoExtPath, inline, hasAction)=>{
|
|
96
116
|
const key = `${inline ? 'inline' : 'default'}:${hasAction ? 'action' : 'loader'}:${aliasedNoExtPath}`;
|
|
97
117
|
const existing = loaderImportMap.get(key);
|
|
@@ -99,13 +119,7 @@ async function generateTanstackRouterTypesSourceForEntry(opts) {
|
|
|
99
119
|
loaderName: existing,
|
|
100
120
|
actionName: hasAction ? existing.replace(/^loader_/, 'action_') : null
|
|
101
121
|
};
|
|
102
|
-
const
|
|
103
|
-
let absNoExt;
|
|
104
|
-
if (aliasedNoExtPath.startsWith(prefix)) {
|
|
105
|
-
const rel = aliasedNoExtPath.slice(prefix.length);
|
|
106
|
-
absNoExt = path.join(appContext.srcDirectory, rel);
|
|
107
|
-
} else absNoExt = path.isAbsolute(aliasedNoExtPath) ? aliasedNoExtPath : path.join(appContext.srcDirectory, aliasedNoExtPath);
|
|
108
|
-
const resolvedNoExt = await resolveFileNoExt(absNoExt);
|
|
122
|
+
const resolvedNoExt = await resolveRouteModuleNoExt(aliasedNoExtPath);
|
|
109
123
|
if (!resolvedNoExt) return null;
|
|
110
124
|
const relImport = normalizeRelativeImport(path.relative(outDir, resolvedNoExt));
|
|
111
125
|
const importName = `loader_${loaderIndex++}`;
|
|
@@ -123,6 +137,18 @@ async function generateTanstackRouterTypesSourceForEntry(opts) {
|
|
|
123
137
|
actionName
|
|
124
138
|
};
|
|
125
139
|
};
|
|
140
|
+
const getImportNameForSearchContract = async (aliasedNoExtPath, exportName)=>{
|
|
141
|
+
const key = `${exportName}:${aliasedNoExtPath}`;
|
|
142
|
+
const existing = searchContractImportMap.get(key);
|
|
143
|
+
if (existing) return existing;
|
|
144
|
+
const resolvedNoExt = await resolveRouteModuleNoExt(aliasedNoExtPath);
|
|
145
|
+
if (!resolvedNoExt) return null;
|
|
146
|
+
const relImport = normalizeRelativeImport(path.relative(outDir, resolvedNoExt));
|
|
147
|
+
const importName = 'validateSearch' === exportName ? `validateSearch_${validateSearchIndex++}` : `loaderDeps_${loaderDepsIndex++}`;
|
|
148
|
+
imports.push(`import { ${exportName} as ${importName} } from ${quote(relImport)};`);
|
|
149
|
+
searchContractImportMap.set(key, importName);
|
|
150
|
+
return importName;
|
|
151
|
+
};
|
|
126
152
|
const reserveRouteVarName = (preferred)=>{
|
|
127
153
|
let candidate = preferred;
|
|
128
154
|
let suffix = 1;
|
|
@@ -143,6 +169,9 @@ async function generateTanstackRouterTypesSourceForEntry(opts) {
|
|
|
143
169
|
const loaderImports = loaderInfo ? await getImportNamesForLoader(loaderInfo.loaderPath, loaderInfo.inline, Boolean(loaderInfo.inline && routeAction === loaderInfo.loaderPath)) : null;
|
|
144
170
|
const loaderName = loaderImports?.loaderName || null;
|
|
145
171
|
const actionName = loaderImports?.actionName || null;
|
|
172
|
+
const searchContractInfo = pickRouteSearchContractModules(route);
|
|
173
|
+
const validateSearchName = searchContractInfo.validateSearchPath ? await getImportNameForSearchContract(searchContractInfo.validateSearchPath, 'validateSearch') : null;
|
|
174
|
+
const loaderDepsName = searchContractInfo.loaderDepsPath ? await getImportNameForSearchContract(searchContractInfo.loaderDepsPath, 'loaderDeps') : null;
|
|
146
175
|
const rawPath = route.path;
|
|
147
176
|
const hasSplat = 'string' == typeof rawPath && rawPath.includes('*');
|
|
148
177
|
const routeOpts = [
|
|
@@ -156,6 +185,8 @@ async function generateTanstackRouterTypesSourceForEntry(opts) {
|
|
|
156
185
|
routeOpts.push(`path: ${quote(p)},`);
|
|
157
186
|
}
|
|
158
187
|
if (loaderName) routeOpts.push(`loader: modernLoaderToTanstack({ hasSplat: ${hasSplat} }, ${loaderName}),`);
|
|
188
|
+
if (validateSearchName) routeOpts.push(`validateSearch: ${validateSearchName},`);
|
|
189
|
+
if (loaderDepsName) routeOpts.push(`loaderDeps: ${loaderDepsName},`);
|
|
159
190
|
const staticDataSnippet = createRouteStaticDataSnippet({
|
|
160
191
|
modernRouteId: route.id,
|
|
161
192
|
loaderName,
|
|
@@ -180,17 +211,23 @@ async function generateTanstackRouterTypesSourceForEntry(opts) {
|
|
|
180
211
|
const rootLoaderImports = rootLoaderInfo?.loaderPath ? await getImportNamesForLoader(rootLoaderInfo.loaderPath, rootLoaderInfo.inline, Boolean(rootLoaderInfo.inline && rootAction === rootLoaderInfo.loaderPath)) : null;
|
|
181
212
|
const rootLoaderName = rootLoaderImports?.loaderName || null;
|
|
182
213
|
const rootActionName = rootLoaderImports?.actionName || null;
|
|
214
|
+
const rootSearchContractInfo = rootModern ? pickRouteSearchContractModules(rootModern) : null;
|
|
215
|
+
const rootValidateSearchName = rootSearchContractInfo?.validateSearchPath ? await getImportNameForSearchContract(rootSearchContractInfo.validateSearchPath, 'validateSearch') : null;
|
|
216
|
+
const rootLoaderDepsName = rootSearchContractInfo?.loaderDepsPath ? await getImportNameForSearchContract(rootSearchContractInfo.loaderDepsPath, 'loaderDeps') : null;
|
|
183
217
|
const topLevelVars = await Promise.all(topLevel.map((route)=>buildRoute({
|
|
184
218
|
parentVar: 'rootRoute',
|
|
185
219
|
route
|
|
186
220
|
})));
|
|
187
221
|
const rootOpts = [];
|
|
188
222
|
if (rootLoaderName) rootOpts.push(`loader: modernLoaderToTanstack({ hasSplat: false }, ${rootLoaderName}),`);
|
|
223
|
+
if (rootValidateSearchName) rootOpts.push(`validateSearch: ${rootValidateSearchName},`);
|
|
224
|
+
if (rootLoaderDepsName) rootOpts.push(`loaderDeps: ${rootLoaderDepsName},`);
|
|
189
225
|
const routerGenTs = `/* eslint-disable */
|
|
190
226
|
// This file is auto-generated by Modern.js. Do not edit manually.
|
|
191
227
|
|
|
192
228
|
import {
|
|
193
229
|
createMemoryHistory,
|
|
230
|
+
modernTanstackRouterFastDefaults,
|
|
194
231
|
createRootRouteWithContext,
|
|
195
232
|
createRoute,
|
|
196
233
|
createRouter,
|
|
@@ -378,6 +415,7 @@ ${statements.join('\n\n')}
|
|
|
378
415
|
export const routeTree = rootRoute.addChildren([${topLevelVars.join(', ')}]);
|
|
379
416
|
|
|
380
417
|
export const router = createRouter({
|
|
418
|
+
...modernTanstackRouterFastDefaults,
|
|
381
419
|
routeTree,
|
|
382
420
|
history: createMemoryHistory({
|
|
383
421
|
initialEntries: ['/'],
|
|
@@ -5,3 +5,4 @@ export { Form, RouteActionResponseError, useFetcher } from "./dataMutation.mjs";
|
|
|
5
5
|
export { tanstackRouterPlugin as default, tanstackRouterPlugin } from "./plugin.mjs";
|
|
6
6
|
export { Link, NavLink } from "./prefetchLink.mjs";
|
|
7
7
|
export { CompositeComponent } from "./rsc/client.mjs";
|
|
8
|
+
export { getModernTanstackRouterFastDefaults, modernTanstackRouterFastDefaults } from "./types.mjs";
|
|
@@ -12,6 +12,7 @@ import { applyRouterRuntimeState } from "./lifecycle.mjs";
|
|
|
12
12
|
import { Link } from "./prefetchLink.mjs";
|
|
13
13
|
import { createRouteTreeFromRouteObjects } from "./routeTree.mjs";
|
|
14
14
|
import { getTanstackRscSerializationAdapters } from "./rsc/client.mjs";
|
|
15
|
+
import { getModernTanstackRouterFastDefaults } from "./types.mjs";
|
|
15
16
|
import { createRouteObjectsFromConfig, urlJoin } from "./utils.mjs";
|
|
16
17
|
const BLOCKING_SUBSCRIBE_SYMBOL = Symbol.for('@modern-js/plugin-tanstack:blocking-subscribe');
|
|
17
18
|
const BLOCKING_STATE_SYMBOL = Symbol.for('@modern-js/plugin-tanstack:blocking-state');
|
|
@@ -145,6 +146,7 @@ const tanstackRouterPlugin = (userConfig = {})=>{
|
|
|
145
146
|
const rewrite = createModernBasepathRewrite(_basename);
|
|
146
147
|
const serializationAdapters = getGlobalEnableRsc() ? getTanstackRscSerializationAdapters() : void 0;
|
|
147
148
|
cachedRouter = createRouter({
|
|
149
|
+
...getModernTanstackRouterFastDefaults(mergedConfig),
|
|
148
150
|
routeTree,
|
|
149
151
|
basepath: '/',
|
|
150
152
|
rewrite,
|
|
@@ -13,6 +13,7 @@ import { modifyRoutes, onAfterCreateRouter, onAfterHydrateRouter, onBeforeCreate
|
|
|
13
13
|
import { applyRouterServerPrepareResult, createRouterServerSnapshot } from "./lifecycle.mjs";
|
|
14
14
|
import { createRouteTreeFromRouteObjects, getModernRouteIdsFromMatches } from "./routeTree.mjs";
|
|
15
15
|
import { createTanstackRscServerPayload, handleTanstackRscRedirect } from "./rsc/payloadRouter.mjs";
|
|
16
|
+
import { getModernTanstackRouterFastDefaults } from "./types.mjs";
|
|
16
17
|
import { createRouteObjectsFromConfig, urlJoin } from "./utils.mjs";
|
|
17
18
|
const setTanstackRscServerPayload = (payload)=>{
|
|
18
19
|
const storageContext = storage.useContext?.();
|
|
@@ -178,6 +179,7 @@ const tanstackRouterPlugin = (userConfig = {})=>{
|
|
|
178
179
|
};
|
|
179
180
|
hooks.onBeforeCreateRouter.call(routerLifecycleContext);
|
|
180
181
|
const tanstackRouter = createRouter({
|
|
182
|
+
...getModernTanstackRouterFastDefaults(mergedConfig),
|
|
181
183
|
routeTree,
|
|
182
184
|
history,
|
|
183
185
|
basepath: '/',
|
|
@@ -318,6 +318,8 @@ function createRouteFromRouteObject(opts) {
|
|
|
318
318
|
component: toRouteComponent(routeObject),
|
|
319
319
|
pendingComponent: toPendingComponent(routeObject),
|
|
320
320
|
errorComponent: toErrorComponent(routeObject),
|
|
321
|
+
validateSearch: modernRouteObject.validateSearch,
|
|
322
|
+
loaderDeps: modernRouteObject.loaderDeps,
|
|
321
323
|
wrapInSuspense: true,
|
|
322
324
|
staticData: createRouteStaticData({
|
|
323
325
|
modernRouteId: routeObject.id,
|
|
@@ -368,6 +370,8 @@ function createRouteFromModernRoute(opts) {
|
|
|
368
370
|
component: component || void 0,
|
|
369
371
|
pendingComponent: pendingComponent || void 0,
|
|
370
372
|
errorComponent: errorComponent || void 0,
|
|
373
|
+
validateSearch: route.validateSearch,
|
|
374
|
+
loaderDeps: route.loaderDeps,
|
|
371
375
|
wrapInSuspense: true,
|
|
372
376
|
staticData: createRouteStaticData({
|
|
373
377
|
modernRouteId: modernId,
|
|
@@ -416,6 +420,8 @@ function createRouteTreeFromModernRoutes(routes, options = {}) {
|
|
|
416
420
|
component: rootComponent || void 0,
|
|
417
421
|
pendingComponent: pendingComponent || void 0,
|
|
418
422
|
errorComponent: errorComponent || void 0,
|
|
423
|
+
validateSearch: rootModern?.validateSearch,
|
|
424
|
+
loaderDeps: rootModern?.loaderDeps,
|
|
419
425
|
wrapInSuspense: true,
|
|
420
426
|
notFoundComponent: DefaultNotFound,
|
|
421
427
|
staticData: createRouteStaticData({
|
|
@@ -455,6 +461,8 @@ function createRouteTreeFromRouteObjects(routes, options = {}) {
|
|
|
455
461
|
component: rootLikeRoute ? toRouteComponent(rootLikeRoute) : void 0,
|
|
456
462
|
pendingComponent: rootLikeRoute ? toPendingComponent(rootLikeRoute) : void 0,
|
|
457
463
|
errorComponent: rootLikeRoute ? toErrorComponent(rootLikeRoute) : void 0,
|
|
464
|
+
validateSearch: rootLikeRoute?.validateSearch,
|
|
465
|
+
loaderDeps: rootLikeRoute?.loaderDeps,
|
|
458
466
|
wrapInSuspense: true,
|
|
459
467
|
notFoundComponent: DefaultNotFound,
|
|
460
468
|
staticData: createRouteStaticData({
|
|
@@ -1 +1,8 @@
|
|
|
1
1
|
import "node:module";
|
|
2
|
+
const modernTanstackRouterFastDefaults = {
|
|
3
|
+
defaultStructuralSharing: true
|
|
4
|
+
};
|
|
5
|
+
const getModernTanstackRouterFastDefaults = (config = {})=>({
|
|
6
|
+
defaultStructuralSharing: config.defaultStructuralSharing ?? modernTanstackRouterFastDefaults.defaultStructuralSharing
|
|
7
|
+
});
|
|
8
|
+
export { getModernTanstackRouterFastDefaults, modernTanstackRouterFastDefaults };
|
|
@@ -1,9 +1,13 @@
|
|
|
1
1
|
import type { AppTools, AppToolsContext, CliPlugin } from '@modern-js/app-tools';
|
|
2
2
|
import type { NestedRouteForCli, PageRoute } from '@modern-js/types';
|
|
3
|
+
import { type TanstackRouteCodeSplittingOption } from './routeSplitting';
|
|
4
|
+
export type { TanstackRouteCodeSplittingOption, TanstackRsbuildRouteSplittingProfile, } from './routeSplitting';
|
|
5
|
+
export { createTanstackRsbuildRouteSplittingProfile, isTanstackStartRouteModuleSource, resolveTanstackRouteCodeSplittingEnabled, } from './routeSplitting';
|
|
3
6
|
export { generateTanstackRouterTypesSourceForEntry, isTanstackRouterFrameworkEnabled, } from './tanstackTypes';
|
|
4
7
|
export type TanstackRouterPluginOptions = {
|
|
5
8
|
routesDir?: string;
|
|
6
9
|
generatedDirName?: string;
|
|
10
|
+
routeCodeSplitting?: TanstackRouteCodeSplittingOption;
|
|
7
11
|
};
|
|
8
12
|
export declare function writeTanstackRegisterFile(opts: {
|
|
9
13
|
entries: string[];
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
export type TanstackRouteCodeSplittingOption = boolean | {
|
|
2
|
+
enabled?: boolean;
|
|
3
|
+
};
|
|
4
|
+
export type TanstackRsbuildRouteSplittingProfile = {
|
|
5
|
+
defaultConfig: {
|
|
6
|
+
output: {
|
|
7
|
+
splitRouteChunks: boolean;
|
|
8
|
+
};
|
|
9
|
+
};
|
|
10
|
+
modernRouteChunks: {
|
|
11
|
+
enabled: boolean;
|
|
12
|
+
owner: 'modern';
|
|
13
|
+
};
|
|
14
|
+
builderChunkSplit: {
|
|
15
|
+
owner: 'modern-rsbuild';
|
|
16
|
+
preserved: true;
|
|
17
|
+
};
|
|
18
|
+
tanstackStartRspackSplitter: {
|
|
19
|
+
compatible: boolean;
|
|
20
|
+
reason: string;
|
|
21
|
+
clientDeleteNodes: string[];
|
|
22
|
+
routeFactoryCalls: string[];
|
|
23
|
+
};
|
|
24
|
+
};
|
|
25
|
+
export declare function isTanstackStartRouteModuleSource(source: string): boolean;
|
|
26
|
+
export declare function resolveTanstackRouteCodeSplittingEnabled(option?: TanstackRouteCodeSplittingOption): boolean;
|
|
27
|
+
export declare function createTanstackRsbuildRouteSplittingProfile(opts: {
|
|
28
|
+
routeCodeSplitting?: TanstackRouteCodeSplittingOption;
|
|
29
|
+
}): TanstackRsbuildRouteSplittingProfile;
|
|
@@ -7,3 +7,5 @@ export type { LinkProps, NavLinkProps, PrefetchBehavior, } from './prefetchLink'
|
|
|
7
7
|
export { Link, NavLink } from './prefetchLink';
|
|
8
8
|
export type { AnyCompositeComponent, AnyRenderableServerComponent, CompositeComponentProps, } from './rsc/client';
|
|
9
9
|
export { CompositeComponent } from './rsc/client';
|
|
10
|
+
export type { RouterConfig } from './types';
|
|
11
|
+
export { getModernTanstackRouterFastDefaults, modernTanstackRouterFastDefaults, } from './types';
|
|
@@ -2,7 +2,7 @@ import type { Plugin, RuntimePluginExtends } from '@modern-js/plugin';
|
|
|
2
2
|
import type { RuntimePluginAPI } from '@modern-js/plugin/runtime';
|
|
3
3
|
import { type TInternalRuntimeContext } from '@modern-js/runtime/context';
|
|
4
4
|
import { type RouterExtendsHooks } from './hooks';
|
|
5
|
-
import type
|
|
5
|
+
import { type RouterConfig } from './types';
|
|
6
6
|
type TanstackRouterRuntimeConfig = {
|
|
7
7
|
plugins?: TanstackRouterRuntimePlugin[];
|
|
8
8
|
router?: Partial<RouterConfig>;
|
|
@@ -2,7 +2,7 @@ import type { Plugin, RuntimePluginExtends } from '@modern-js/plugin';
|
|
|
2
2
|
import type { RuntimePluginAPI } from '@modern-js/plugin/runtime';
|
|
3
3
|
import { type TInternalRuntimeContext } from '@modern-js/runtime/context';
|
|
4
4
|
import { type RouterExtendsHooks } from './hooks';
|
|
5
|
-
import type
|
|
5
|
+
import { type RouterConfig } from './types';
|
|
6
6
|
type TanstackRouterRuntimeConfig = {
|
|
7
7
|
plugins?: TanstackRouterRuntimePlugin[];
|
|
8
8
|
router?: Partial<RouterConfig>;
|
|
@@ -18,8 +18,15 @@ export type RouterConfig = {
|
|
|
18
18
|
future?: Partial<{
|
|
19
19
|
v7_startTransition: boolean;
|
|
20
20
|
}>;
|
|
21
|
+
defaultStructuralSharing?: boolean;
|
|
21
22
|
unstable_reloadOnURLMismatch?: boolean;
|
|
22
23
|
};
|
|
24
|
+
export declare const modernTanstackRouterFastDefaults: {
|
|
25
|
+
readonly defaultStructuralSharing: true;
|
|
26
|
+
};
|
|
27
|
+
export declare const getModernTanstackRouterFastDefaults: (config?: Partial<Pick<RouterConfig, 'defaultStructuralSharing'>>) => {
|
|
28
|
+
defaultStructuralSharing: boolean;
|
|
29
|
+
};
|
|
23
30
|
export interface RouterRouteMatchSnapshot {
|
|
24
31
|
routeId: string;
|
|
25
32
|
assetRouteId?: string;
|
package/package.json
CHANGED
|
@@ -18,7 +18,7 @@
|
|
|
18
18
|
"modern.js",
|
|
19
19
|
"tanstack-router"
|
|
20
20
|
],
|
|
21
|
-
"version": "3.2.0-ultramodern.
|
|
21
|
+
"version": "3.2.0-ultramodern.90",
|
|
22
22
|
"engines": {
|
|
23
23
|
"node": ">=20"
|
|
24
24
|
},
|
|
@@ -86,15 +86,15 @@
|
|
|
86
86
|
},
|
|
87
87
|
"dependencies": {
|
|
88
88
|
"@swc/helpers": "^0.5.23",
|
|
89
|
-
"@tanstack/react-router": "1.170.
|
|
90
|
-
"@tanstack/router-core": "1.171.
|
|
91
|
-
"@modern-js/plugin": "npm:@bleedingdev/modern-js-plugin@3.2.0-ultramodern.
|
|
92
|
-
"@modern-js/
|
|
93
|
-
"@modern-js/utils": "npm:@bleedingdev/modern-js-utils@3.2.0-ultramodern.
|
|
94
|
-
"@modern-js/
|
|
89
|
+
"@tanstack/react-router": "1.170.11",
|
|
90
|
+
"@tanstack/router-core": "1.171.9",
|
|
91
|
+
"@modern-js/plugin": "npm:@bleedingdev/modern-js-plugin@3.2.0-ultramodern.90",
|
|
92
|
+
"@modern-js/utils": "npm:@bleedingdev/modern-js-utils@3.2.0-ultramodern.90",
|
|
93
|
+
"@modern-js/runtime-utils": "npm:@bleedingdev/modern-js-runtime-utils@3.2.0-ultramodern.90",
|
|
94
|
+
"@modern-js/types": "npm:@bleedingdev/modern-js-types@3.2.0-ultramodern.90"
|
|
95
95
|
},
|
|
96
96
|
"peerDependencies": {
|
|
97
|
-
"@modern-js/runtime": "3.2.0-ultramodern.
|
|
97
|
+
"@modern-js/runtime": "3.2.0-ultramodern.90",
|
|
98
98
|
"react": "^19.2.6",
|
|
99
99
|
"react-dom": "^19.2.6"
|
|
100
100
|
},
|
|
@@ -109,8 +109,8 @@
|
|
|
109
109
|
"@typescript/native-preview": "7.0.0-dev.20260527.2",
|
|
110
110
|
"react": "^19.2.6",
|
|
111
111
|
"react-dom": "^19.2.6",
|
|
112
|
-
"@modern-js/
|
|
113
|
-
"@modern-js/
|
|
112
|
+
"@modern-js/runtime": "npm:@bleedingdev/modern-js-runtime@3.2.0-ultramodern.90",
|
|
113
|
+
"@modern-js/app-tools": "npm:@bleedingdev/modern-js-app-tools@3.2.0-ultramodern.90",
|
|
114
114
|
"@scripts/rstest-config": "2.66.0"
|
|
115
115
|
},
|
|
116
116
|
"sideEffects": false,
|
package/src/cli/index.ts
CHANGED
|
@@ -18,11 +18,24 @@ import {
|
|
|
18
18
|
fs,
|
|
19
19
|
NESTED_ROUTE_SPEC_FILE,
|
|
20
20
|
} from '@modern-js/utils';
|
|
21
|
+
import {
|
|
22
|
+
createTanstackRsbuildRouteSplittingProfile,
|
|
23
|
+
type TanstackRouteCodeSplittingOption,
|
|
24
|
+
} from './routeSplitting';
|
|
21
25
|
import {
|
|
22
26
|
generateTanstackRouterTypesSourceForEntry,
|
|
23
27
|
isTanstackRouterFrameworkEnabled,
|
|
24
28
|
} from './tanstackTypes';
|
|
25
29
|
|
|
30
|
+
export type {
|
|
31
|
+
TanstackRouteCodeSplittingOption,
|
|
32
|
+
TanstackRsbuildRouteSplittingProfile,
|
|
33
|
+
} from './routeSplitting';
|
|
34
|
+
export {
|
|
35
|
+
createTanstackRsbuildRouteSplittingProfile,
|
|
36
|
+
isTanstackStartRouteModuleSource,
|
|
37
|
+
resolveTanstackRouteCodeSplittingEnabled,
|
|
38
|
+
} from './routeSplitting';
|
|
26
39
|
export {
|
|
27
40
|
generateTanstackRouterTypesSourceForEntry,
|
|
28
41
|
isTanstackRouterFrameworkEnabled,
|
|
@@ -35,6 +48,7 @@ const ENTRYPOINTS_KEY = '@modern-js/plugin-tanstack';
|
|
|
35
48
|
export type TanstackRouterPluginOptions = {
|
|
36
49
|
routesDir?: string;
|
|
37
50
|
generatedDirName?: string;
|
|
51
|
+
routeCodeSplitting?: TanstackRouteCodeSplittingOption;
|
|
38
52
|
};
|
|
39
53
|
|
|
40
54
|
type RuntimeRouterCliHelpers = {
|
|
@@ -224,6 +238,8 @@ export function tanstackRouterPlugin(
|
|
|
224
238
|
const routesDir = options.routesDir || DEFAULT_ROUTES_DIR;
|
|
225
239
|
const generatedDirName =
|
|
226
240
|
options.generatedDirName || DEFAULT_GENERATED_DIR_NAME;
|
|
241
|
+
const routeSplittingProfile =
|
|
242
|
+
createTanstackRsbuildRouteSplittingProfile(options);
|
|
227
243
|
|
|
228
244
|
return {
|
|
229
245
|
name: '@modern-js/plugin-tanstack',
|
|
@@ -265,6 +281,7 @@ export function tanstackRouterPlugin(
|
|
|
265
281
|
}));
|
|
266
282
|
|
|
267
283
|
api.config(() => ({
|
|
284
|
+
...routeSplittingProfile.defaultConfig,
|
|
268
285
|
source: {
|
|
269
286
|
include: [
|
|
270
287
|
/[\\/]node_modules[\\/]@tanstack[\\/]react-router[\\/]/,
|
|
@@ -0,0 +1,81 @@
|
|
|
1
|
+
export type TanstackRouteCodeSplittingOption =
|
|
2
|
+
| boolean
|
|
3
|
+
| {
|
|
4
|
+
enabled?: boolean;
|
|
5
|
+
};
|
|
6
|
+
|
|
7
|
+
export type TanstackRsbuildRouteSplittingProfile = {
|
|
8
|
+
defaultConfig: {
|
|
9
|
+
output: {
|
|
10
|
+
splitRouteChunks: boolean;
|
|
11
|
+
};
|
|
12
|
+
};
|
|
13
|
+
modernRouteChunks: {
|
|
14
|
+
enabled: boolean;
|
|
15
|
+
owner: 'modern';
|
|
16
|
+
};
|
|
17
|
+
builderChunkSplit: {
|
|
18
|
+
owner: 'modern-rsbuild';
|
|
19
|
+
preserved: true;
|
|
20
|
+
};
|
|
21
|
+
tanstackStartRspackSplitter: {
|
|
22
|
+
compatible: boolean;
|
|
23
|
+
reason: string;
|
|
24
|
+
clientDeleteNodes: string[];
|
|
25
|
+
routeFactoryCalls: string[];
|
|
26
|
+
};
|
|
27
|
+
};
|
|
28
|
+
|
|
29
|
+
const TANSTACK_START_ROUTE_FACTORY_CALLS = [
|
|
30
|
+
'createFileRoute',
|
|
31
|
+
'createRootRoute',
|
|
32
|
+
'createRootRouteWithContext',
|
|
33
|
+
] as const;
|
|
34
|
+
|
|
35
|
+
const TANSTACK_START_ROUTE_FACTORY_REGEX =
|
|
36
|
+
/\b(createFileRoute|createRootRoute|createRootRouteWithContext)\s*(?:<|\()/;
|
|
37
|
+
|
|
38
|
+
export function isTanstackStartRouteModuleSource(source: string) {
|
|
39
|
+
return TANSTACK_START_ROUTE_FACTORY_REGEX.test(source);
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
export function resolveTanstackRouteCodeSplittingEnabled(
|
|
43
|
+
option?: TanstackRouteCodeSplittingOption,
|
|
44
|
+
) {
|
|
45
|
+
if (typeof option === 'boolean') {
|
|
46
|
+
return option;
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
return option?.enabled ?? true;
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
export function createTanstackRsbuildRouteSplittingProfile(opts: {
|
|
53
|
+
routeCodeSplitting?: TanstackRouteCodeSplittingOption;
|
|
54
|
+
}): TanstackRsbuildRouteSplittingProfile {
|
|
55
|
+
return {
|
|
56
|
+
defaultConfig: {
|
|
57
|
+
output: {
|
|
58
|
+
splitRouteChunks: resolveTanstackRouteCodeSplittingEnabled(
|
|
59
|
+
opts.routeCodeSplitting,
|
|
60
|
+
),
|
|
61
|
+
},
|
|
62
|
+
},
|
|
63
|
+
modernRouteChunks: {
|
|
64
|
+
enabled: resolveTanstackRouteCodeSplittingEnabled(
|
|
65
|
+
opts.routeCodeSplitting,
|
|
66
|
+
),
|
|
67
|
+
owner: 'modern',
|
|
68
|
+
},
|
|
69
|
+
builderChunkSplit: {
|
|
70
|
+
owner: 'modern-rsbuild',
|
|
71
|
+
preserved: true,
|
|
72
|
+
},
|
|
73
|
+
tanstackStartRspackSplitter: {
|
|
74
|
+
compatible: false,
|
|
75
|
+
reason:
|
|
76
|
+
'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.',
|
|
77
|
+
clientDeleteNodes: ['ssr', 'server', 'headers'],
|
|
78
|
+
routeFactoryCalls: [...TANSTACK_START_ROUTE_FACTORY_CALLS],
|
|
79
|
+
},
|
|
80
|
+
};
|
|
81
|
+
}
|