@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
package/src/cli/tanstackTypes.ts
CHANGED
|
@@ -86,6 +86,17 @@ function pickModernLoaderModule(route: NestedRouteForCli | PageRoute) {
|
|
|
86
86
|
return { loaderPath, inline };
|
|
87
87
|
}
|
|
88
88
|
|
|
89
|
+
function pickRouteSearchContractModules(route: NestedRouteForCli | PageRoute) {
|
|
90
|
+
const validateSearchPath = (route as any).validateSearch;
|
|
91
|
+
const loaderDepsPath = (route as any).loaderDeps;
|
|
92
|
+
|
|
93
|
+
return {
|
|
94
|
+
validateSearchPath:
|
|
95
|
+
typeof validateSearchPath === 'string' ? validateSearchPath : null,
|
|
96
|
+
loaderDepsPath: typeof loaderDepsPath === 'string' ? loaderDepsPath : null,
|
|
97
|
+
};
|
|
98
|
+
}
|
|
99
|
+
|
|
89
100
|
function isPathlessLayout(route: NestedRouteForCli | PageRoute) {
|
|
90
101
|
return (
|
|
91
102
|
(route as any).type === 'nested' &&
|
|
@@ -182,10 +193,29 @@ export async function generateTanstackRouterTypesSourceForEntry(opts: {
|
|
|
182
193
|
const statements: string[] = [];
|
|
183
194
|
|
|
184
195
|
const loaderImportMap = new Map<string, string>();
|
|
196
|
+
const searchContractImportMap = new Map<string, string>();
|
|
185
197
|
const usedRouteVarNames = new Set<string>();
|
|
186
198
|
let loaderIndex = 0;
|
|
199
|
+
let validateSearchIndex = 0;
|
|
200
|
+
let loaderDepsIndex = 0;
|
|
187
201
|
let routeIndex = 0;
|
|
188
202
|
|
|
203
|
+
const resolveRouteModuleNoExt = async (aliasedNoExtPath: string) => {
|
|
204
|
+
const prefix = `${appContext.internalSrcAlias}/`;
|
|
205
|
+
let absNoExt: string;
|
|
206
|
+
if (aliasedNoExtPath.startsWith(prefix)) {
|
|
207
|
+
const rel = aliasedNoExtPath.slice(prefix.length);
|
|
208
|
+
absNoExt = path.join(appContext.srcDirectory, rel);
|
|
209
|
+
} else if (path.isAbsolute(aliasedNoExtPath)) {
|
|
210
|
+
absNoExt = aliasedNoExtPath;
|
|
211
|
+
} else {
|
|
212
|
+
// Unknown format; treat as already relative to src.
|
|
213
|
+
absNoExt = path.join(appContext.srcDirectory, aliasedNoExtPath);
|
|
214
|
+
}
|
|
215
|
+
|
|
216
|
+
return resolveFileNoExt(absNoExt);
|
|
217
|
+
};
|
|
218
|
+
|
|
189
219
|
const getImportNamesForLoader = async (
|
|
190
220
|
aliasedNoExtPath: string,
|
|
191
221
|
inline: boolean,
|
|
@@ -202,19 +232,7 @@ export async function generateTanstackRouterTypesSourceForEntry(opts: {
|
|
|
202
232
|
};
|
|
203
233
|
}
|
|
204
234
|
|
|
205
|
-
const
|
|
206
|
-
let absNoExt: string;
|
|
207
|
-
if (aliasedNoExtPath.startsWith(prefix)) {
|
|
208
|
-
const rel = aliasedNoExtPath.slice(prefix.length);
|
|
209
|
-
absNoExt = path.join(appContext.srcDirectory, rel);
|
|
210
|
-
} else if (path.isAbsolute(aliasedNoExtPath)) {
|
|
211
|
-
absNoExt = aliasedNoExtPath;
|
|
212
|
-
} else {
|
|
213
|
-
// Unknown format; treat as already relative to src.
|
|
214
|
-
absNoExt = path.join(appContext.srcDirectory, aliasedNoExtPath);
|
|
215
|
-
}
|
|
216
|
-
|
|
217
|
-
const resolvedNoExt = await resolveFileNoExt(absNoExt);
|
|
235
|
+
const resolvedNoExt = await resolveRouteModuleNoExt(aliasedNoExtPath);
|
|
218
236
|
if (!resolvedNoExt) {
|
|
219
237
|
return null;
|
|
220
238
|
}
|
|
@@ -243,6 +261,35 @@ export async function generateTanstackRouterTypesSourceForEntry(opts: {
|
|
|
243
261
|
return { loaderName: importName, actionName };
|
|
244
262
|
};
|
|
245
263
|
|
|
264
|
+
const getImportNameForSearchContract = async (
|
|
265
|
+
aliasedNoExtPath: string,
|
|
266
|
+
exportName: 'validateSearch' | 'loaderDeps',
|
|
267
|
+
) => {
|
|
268
|
+
const key = `${exportName}:${aliasedNoExtPath}`;
|
|
269
|
+
const existing = searchContractImportMap.get(key);
|
|
270
|
+
if (existing) {
|
|
271
|
+
return existing;
|
|
272
|
+
}
|
|
273
|
+
|
|
274
|
+
const resolvedNoExt = await resolveRouteModuleNoExt(aliasedNoExtPath);
|
|
275
|
+
if (!resolvedNoExt) {
|
|
276
|
+
return null;
|
|
277
|
+
}
|
|
278
|
+
|
|
279
|
+
const relImport = normalizeRelativeImport(
|
|
280
|
+
path.relative(outDir, resolvedNoExt),
|
|
281
|
+
);
|
|
282
|
+
const importName =
|
|
283
|
+
exportName === 'validateSearch'
|
|
284
|
+
? `validateSearch_${validateSearchIndex++}`
|
|
285
|
+
: `loaderDeps_${loaderDepsIndex++}`;
|
|
286
|
+
imports.push(
|
|
287
|
+
`import { ${exportName} as ${importName} } from ${quote(relImport)};`,
|
|
288
|
+
);
|
|
289
|
+
searchContractImportMap.set(key, importName);
|
|
290
|
+
return importName;
|
|
291
|
+
};
|
|
292
|
+
|
|
246
293
|
const reserveRouteVarName = (preferred: string) => {
|
|
247
294
|
let candidate = preferred;
|
|
248
295
|
let suffix = 1;
|
|
@@ -278,6 +325,19 @@ export async function generateTanstackRouterTypesSourceForEntry(opts: {
|
|
|
278
325
|
: null;
|
|
279
326
|
const loaderName = loaderImports?.loaderName || null;
|
|
280
327
|
const actionName = loaderImports?.actionName || null;
|
|
328
|
+
const searchContractInfo = pickRouteSearchContractModules(route);
|
|
329
|
+
const validateSearchName = searchContractInfo.validateSearchPath
|
|
330
|
+
? await getImportNameForSearchContract(
|
|
331
|
+
searchContractInfo.validateSearchPath,
|
|
332
|
+
'validateSearch',
|
|
333
|
+
)
|
|
334
|
+
: null;
|
|
335
|
+
const loaderDepsName = searchContractInfo.loaderDepsPath
|
|
336
|
+
? await getImportNameForSearchContract(
|
|
337
|
+
searchContractInfo.loaderDepsPath,
|
|
338
|
+
'loaderDeps',
|
|
339
|
+
)
|
|
340
|
+
: null;
|
|
281
341
|
|
|
282
342
|
const rawPath = (route as any).path as string | undefined;
|
|
283
343
|
const hasSplat = typeof rawPath === 'string' && rawPath.includes('*');
|
|
@@ -297,6 +357,12 @@ export async function generateTanstackRouterTypesSourceForEntry(opts: {
|
|
|
297
357
|
`loader: modernLoaderToTanstack({ hasSplat: ${hasSplat} }, ${loaderName}),`,
|
|
298
358
|
);
|
|
299
359
|
}
|
|
360
|
+
if (validateSearchName) {
|
|
361
|
+
routeOpts.push(`validateSearch: ${validateSearchName},`);
|
|
362
|
+
}
|
|
363
|
+
if (loaderDepsName) {
|
|
364
|
+
routeOpts.push(`loaderDeps: ${loaderDepsName},`);
|
|
365
|
+
}
|
|
300
366
|
|
|
301
367
|
const staticDataSnippet = createRouteStaticDataSnippet({
|
|
302
368
|
modernRouteId: (route as any).id as string | undefined,
|
|
@@ -346,6 +412,21 @@ export async function generateTanstackRouterTypesSourceForEntry(opts: {
|
|
|
346
412
|
: null;
|
|
347
413
|
const rootLoaderName = rootLoaderImports?.loaderName || null;
|
|
348
414
|
const rootActionName = rootLoaderImports?.actionName || null;
|
|
415
|
+
const rootSearchContractInfo = rootModern
|
|
416
|
+
? pickRouteSearchContractModules(rootModern)
|
|
417
|
+
: null;
|
|
418
|
+
const rootValidateSearchName = rootSearchContractInfo?.validateSearchPath
|
|
419
|
+
? await getImportNameForSearchContract(
|
|
420
|
+
rootSearchContractInfo.validateSearchPath,
|
|
421
|
+
'validateSearch',
|
|
422
|
+
)
|
|
423
|
+
: null;
|
|
424
|
+
const rootLoaderDepsName = rootSearchContractInfo?.loaderDepsPath
|
|
425
|
+
? await getImportNameForSearchContract(
|
|
426
|
+
rootSearchContractInfo.loaderDepsPath,
|
|
427
|
+
'loaderDeps',
|
|
428
|
+
)
|
|
429
|
+
: null;
|
|
349
430
|
|
|
350
431
|
const topLevelVars = await Promise.all(
|
|
351
432
|
topLevel.map(route => buildRoute({ parentVar: 'rootRoute', route })),
|
|
@@ -357,12 +438,19 @@ export async function generateTanstackRouterTypesSourceForEntry(opts: {
|
|
|
357
438
|
`loader: modernLoaderToTanstack({ hasSplat: false }, ${rootLoaderName}),`,
|
|
358
439
|
);
|
|
359
440
|
}
|
|
441
|
+
if (rootValidateSearchName) {
|
|
442
|
+
rootOpts.push(`validateSearch: ${rootValidateSearchName},`);
|
|
443
|
+
}
|
|
444
|
+
if (rootLoaderDepsName) {
|
|
445
|
+
rootOpts.push(`loaderDeps: ${rootLoaderDepsName},`);
|
|
446
|
+
}
|
|
360
447
|
|
|
361
448
|
const routerGenTs = `/* eslint-disable */
|
|
362
449
|
// This file is auto-generated by Modern.js. Do not edit manually.
|
|
363
450
|
|
|
364
451
|
import {
|
|
365
452
|
createMemoryHistory,
|
|
453
|
+
modernTanstackRouterFastDefaults,
|
|
366
454
|
createRootRouteWithContext,
|
|
367
455
|
createRoute,
|
|
368
456
|
createRouter,
|
|
@@ -552,6 +640,7 @@ ${statements.join('\n\n')}
|
|
|
552
640
|
export const routeTree = rootRoute.addChildren([${topLevelVars.join(', ')}]);
|
|
553
641
|
|
|
554
642
|
export const router = createRouter({
|
|
643
|
+
...modernTanstackRouterFastDefaults,
|
|
555
644
|
routeTree,
|
|
556
645
|
history: createMemoryHistory({
|
|
557
646
|
initialEntries: ['/'],
|
package/src/runtime/index.tsx
CHANGED
|
@@ -35,3 +35,8 @@ export type {
|
|
|
35
35
|
CompositeComponentProps,
|
|
36
36
|
} from './rsc/client';
|
|
37
37
|
export { CompositeComponent } from './rsc/client';
|
|
38
|
+
export type { RouterConfig } from './types';
|
|
39
|
+
export {
|
|
40
|
+
getModernTanstackRouterFastDefaults,
|
|
41
|
+
modernTanstackRouterFastDefaults,
|
|
42
|
+
} from './types';
|
|
@@ -52,7 +52,11 @@ import {
|
|
|
52
52
|
createTanstackRscServerPayload,
|
|
53
53
|
handleTanstackRscRedirect,
|
|
54
54
|
} from './rsc/payloadRouter';
|
|
55
|
-
import
|
|
55
|
+
import {
|
|
56
|
+
getModernTanstackRouterFastDefaults,
|
|
57
|
+
type InternalRouterServerSnapshot,
|
|
58
|
+
type RouterConfig,
|
|
59
|
+
} from './types';
|
|
56
60
|
import { createRouteObjectsFromConfig, urlJoin } from './utils';
|
|
57
61
|
|
|
58
62
|
type ModernTanstackRouterContext = {
|
|
@@ -439,6 +443,7 @@ export const tanstackRouterPlugin = (
|
|
|
439
443
|
hooks.onBeforeCreateRouter.call(routerLifecycleContext);
|
|
440
444
|
|
|
441
445
|
const tanstackRouter = createRouter({
|
|
446
|
+
...getModernTanstackRouterFastDefaults(mergedConfig),
|
|
442
447
|
routeTree,
|
|
443
448
|
history,
|
|
444
449
|
basepath: '/',
|
package/src/runtime/plugin.tsx
CHANGED
|
@@ -43,7 +43,10 @@ import {
|
|
|
43
43
|
import { Link } from './prefetchLink';
|
|
44
44
|
import { createRouteTreeFromRouteObjects } from './routeTree';
|
|
45
45
|
import { getTanstackRscSerializationAdapters } from './rsc/client';
|
|
46
|
-
import
|
|
46
|
+
import {
|
|
47
|
+
getModernTanstackRouterFastDefaults,
|
|
48
|
+
type RouterConfig,
|
|
49
|
+
} from './types';
|
|
47
50
|
import { createRouteObjectsFromConfig, urlJoin } from './utils';
|
|
48
51
|
|
|
49
52
|
const BLOCKING_SUBSCRIBE_SYMBOL = Symbol.for(
|
|
@@ -322,6 +325,7 @@ export const tanstackRouterPlugin = (
|
|
|
322
325
|
: undefined;
|
|
323
326
|
|
|
324
327
|
cachedRouter = createRouter({
|
|
328
|
+
...getModernTanstackRouterFastDefaults(mergedConfig),
|
|
325
329
|
routeTree,
|
|
326
330
|
basepath: '/',
|
|
327
331
|
rewrite,
|
package/src/runtime/routeTree.ts
CHANGED
|
@@ -76,8 +76,10 @@ type ModernRouteObject = RouteObject & {
|
|
|
76
76
|
isClientComponent?: boolean;
|
|
77
77
|
lazyImport?: () => unknown;
|
|
78
78
|
loader?: ModernLoader;
|
|
79
|
+
loaderDeps?: unknown;
|
|
79
80
|
pendingComponent?: unknown;
|
|
80
81
|
shouldRevalidate?: ModernShouldRevalidate;
|
|
82
|
+
validateSearch?: unknown;
|
|
81
83
|
};
|
|
82
84
|
|
|
83
85
|
type ModernGeneratedRoute = (NestedRoute | PageRoute) & {
|
|
@@ -102,10 +104,12 @@ type ModernGeneratedRoute = (NestedRoute | PageRoute) & {
|
|
|
102
104
|
isRoot?: boolean;
|
|
103
105
|
lazyImport?: () => unknown;
|
|
104
106
|
loader?: ModernLoader;
|
|
107
|
+
loaderDeps?: unknown;
|
|
105
108
|
loading?: unknown;
|
|
106
109
|
pendingComponent?: unknown;
|
|
107
110
|
path?: string;
|
|
108
111
|
shouldRevalidate?: ModernShouldRevalidate;
|
|
112
|
+
validateSearch?: unknown;
|
|
109
113
|
};
|
|
110
114
|
|
|
111
115
|
type MutableTanstackRoute = AnyRoute & {
|
|
@@ -735,6 +739,8 @@ function createRouteFromRouteObject(opts: {
|
|
|
735
739
|
component: toRouteComponent(routeObject),
|
|
736
740
|
pendingComponent: toPendingComponent(routeObject),
|
|
737
741
|
errorComponent: toErrorComponent(routeObject),
|
|
742
|
+
validateSearch: modernRouteObject.validateSearch,
|
|
743
|
+
loaderDeps: modernRouteObject.loaderDeps,
|
|
738
744
|
wrapInSuspense: true,
|
|
739
745
|
staticData: createRouteStaticData({
|
|
740
746
|
modernRouteId: routeObject.id,
|
|
@@ -827,6 +833,8 @@ function createRouteFromModernRoute(opts: {
|
|
|
827
833
|
component: component || undefined,
|
|
828
834
|
pendingComponent: pendingComponent || undefined,
|
|
829
835
|
errorComponent: errorComponent || undefined,
|
|
836
|
+
validateSearch: route.validateSearch,
|
|
837
|
+
loaderDeps: route.loaderDeps,
|
|
830
838
|
wrapInSuspense: true,
|
|
831
839
|
staticData: createRouteStaticData({
|
|
832
840
|
modernRouteId: modernId,
|
|
@@ -910,6 +918,8 @@ export function createRouteTreeFromModernRoutes(
|
|
|
910
918
|
component: rootComponent || undefined,
|
|
911
919
|
pendingComponent: pendingComponent || undefined,
|
|
912
920
|
errorComponent: errorComponent || undefined,
|
|
921
|
+
validateSearch: rootModern?.validateSearch,
|
|
922
|
+
loaderDeps: rootModern?.loaderDeps,
|
|
913
923
|
wrapInSuspense: true,
|
|
914
924
|
notFoundComponent: DefaultNotFound,
|
|
915
925
|
staticData: createRouteStaticData({
|
|
@@ -981,6 +991,8 @@ export function createRouteTreeFromRouteObjects(
|
|
|
981
991
|
? toPendingComponent(rootLikeRoute)
|
|
982
992
|
: undefined,
|
|
983
993
|
errorComponent: rootLikeRoute ? toErrorComponent(rootLikeRoute) : undefined,
|
|
994
|
+
validateSearch: rootLikeRoute?.validateSearch,
|
|
995
|
+
loaderDeps: rootLikeRoute?.loaderDeps,
|
|
984
996
|
wrapInSuspense: true,
|
|
985
997
|
notFoundComponent: DefaultNotFound,
|
|
986
998
|
staticData: createRouteStaticData({
|
package/src/runtime/types.ts
CHANGED
|
@@ -20,9 +20,22 @@ export type RouterConfig = {
|
|
|
20
20
|
future?: Partial<{
|
|
21
21
|
v7_startTransition: boolean;
|
|
22
22
|
}>;
|
|
23
|
+
defaultStructuralSharing?: boolean;
|
|
23
24
|
unstable_reloadOnURLMismatch?: boolean;
|
|
24
25
|
};
|
|
25
26
|
|
|
27
|
+
export const modernTanstackRouterFastDefaults = {
|
|
28
|
+
defaultStructuralSharing: true,
|
|
29
|
+
} as const;
|
|
30
|
+
|
|
31
|
+
export const getModernTanstackRouterFastDefaults = (
|
|
32
|
+
config: Partial<Pick<RouterConfig, 'defaultStructuralSharing'>> = {},
|
|
33
|
+
) => ({
|
|
34
|
+
defaultStructuralSharing:
|
|
35
|
+
config.defaultStructuralSharing ??
|
|
36
|
+
modernTanstackRouterFastDefaults.defaultStructuralSharing,
|
|
37
|
+
});
|
|
38
|
+
|
|
26
39
|
export interface RouterRouteMatchSnapshot {
|
|
27
40
|
routeId: string;
|
|
28
41
|
assetRouteId?: string;
|
package/tests/router/cli.test.ts
CHANGED
|
@@ -1,9 +1,12 @@
|
|
|
1
1
|
import { mkdir, mkdtemp, readFile, rm } from 'node:fs/promises';
|
|
2
2
|
import { tmpdir } from 'node:os';
|
|
3
3
|
import path from 'node:path';
|
|
4
|
+
import { mergeConfig } from '@modern-js/plugin/cli';
|
|
4
5
|
import type { Entrypoint } from '@modern-js/types';
|
|
5
6
|
import { fs, NESTED_ROUTE_SPEC_FILE } from '@modern-js/utils';
|
|
6
7
|
import {
|
|
8
|
+
createTanstackRsbuildRouteSplittingProfile,
|
|
9
|
+
isTanstackStartRouteModuleSource,
|
|
7
10
|
tanstackRouterPlugin,
|
|
8
11
|
writeTanstackRegisterFile,
|
|
9
12
|
writeTanstackRouterTypesForEntries,
|
|
@@ -193,6 +196,12 @@ describe('tanstack router cli plugin', () => {
|
|
|
193
196
|
},
|
|
194
197
|
]);
|
|
195
198
|
|
|
199
|
+
expect(taps.config()).toMatchObject({
|
|
200
|
+
output: {
|
|
201
|
+
splitRouteChunks: true,
|
|
202
|
+
},
|
|
203
|
+
});
|
|
204
|
+
|
|
196
205
|
const specPath = path.join(distDirectory, NESTED_ROUTE_SPEC_FILE);
|
|
197
206
|
await fs.outputJSON(specPath, {
|
|
198
207
|
existing: [{ id: 'keep-me' }],
|
|
@@ -383,4 +392,234 @@ describe('tanstack router cli plugin', () => {
|
|
|
383
392
|
}),
|
|
384
393
|
);
|
|
385
394
|
});
|
|
395
|
+
|
|
396
|
+
test('can opt out of Modern-owned route code splitting', async () => {
|
|
397
|
+
const taps: Record<string, any> = {};
|
|
398
|
+
const api = {
|
|
399
|
+
getAppContext: () => ({
|
|
400
|
+
srcDirectory: '/tmp/app/src',
|
|
401
|
+
serverRoutes: [],
|
|
402
|
+
}),
|
|
403
|
+
_internalRuntimePlugins: () => {},
|
|
404
|
+
checkEntryPoint: () => {},
|
|
405
|
+
config: (tap: any) => {
|
|
406
|
+
taps.config = tap;
|
|
407
|
+
},
|
|
408
|
+
modifyEntrypoints: () => {},
|
|
409
|
+
generateEntryCode: () => {},
|
|
410
|
+
onFileChanged: () => {},
|
|
411
|
+
modifyFileSystemRoutes: () => {},
|
|
412
|
+
onBeforeGenerateRoutes: () => {},
|
|
413
|
+
};
|
|
414
|
+
|
|
415
|
+
tanstackRouterPlugin({ routeCodeSplitting: false }).setup!(api as any);
|
|
416
|
+
|
|
417
|
+
expect(taps.config()).toMatchObject({
|
|
418
|
+
output: {
|
|
419
|
+
splitRouteChunks: false,
|
|
420
|
+
},
|
|
421
|
+
});
|
|
422
|
+
});
|
|
423
|
+
|
|
424
|
+
test('documents why TanStack Start Rspack splitter is not registered for Modern routes', () => {
|
|
425
|
+
const profile = createTanstackRsbuildRouteSplittingProfile({});
|
|
426
|
+
|
|
427
|
+
expect(profile).toMatchObject({
|
|
428
|
+
defaultConfig: {
|
|
429
|
+
output: {
|
|
430
|
+
splitRouteChunks: true,
|
|
431
|
+
},
|
|
432
|
+
},
|
|
433
|
+
modernRouteChunks: {
|
|
434
|
+
enabled: true,
|
|
435
|
+
owner: 'modern',
|
|
436
|
+
},
|
|
437
|
+
builderChunkSplit: {
|
|
438
|
+
owner: 'modern-rsbuild',
|
|
439
|
+
preserved: true,
|
|
440
|
+
},
|
|
441
|
+
tanstackStartRspackSplitter: {
|
|
442
|
+
compatible: false,
|
|
443
|
+
clientDeleteNodes: ['ssr', 'server', 'headers'],
|
|
444
|
+
},
|
|
445
|
+
});
|
|
446
|
+
expect(
|
|
447
|
+
isTanstackStartRouteModuleSource(
|
|
448
|
+
"export const Route = createFileRoute('/dashboard')({ component })",
|
|
449
|
+
),
|
|
450
|
+
).toBe(true);
|
|
451
|
+
expect(
|
|
452
|
+
isTanstackStartRouteModuleSource(
|
|
453
|
+
'export const route = createRoute({ getParentRoute, path })',
|
|
454
|
+
),
|
|
455
|
+
).toBe(false);
|
|
456
|
+
});
|
|
457
|
+
|
|
458
|
+
test('preserves user-selected route and builder chunk splitting modes', () => {
|
|
459
|
+
const pluginDefaults = createTanstackRsbuildRouteSplittingProfile(
|
|
460
|
+
{},
|
|
461
|
+
).defaultConfig;
|
|
462
|
+
const chunkSplits = [
|
|
463
|
+
{ strategy: 'split-by-module' },
|
|
464
|
+
{ strategy: 'split-by-experience' },
|
|
465
|
+
{ strategy: 'all-in-one' },
|
|
466
|
+
{ strategy: 'single-vendor' },
|
|
467
|
+
{ strategy: 'split-by-size', minSize: 10_000, maxSize: 60_000 },
|
|
468
|
+
{
|
|
469
|
+
strategy: 'custom',
|
|
470
|
+
splitChunks: {
|
|
471
|
+
chunks: 'all',
|
|
472
|
+
cacheGroups: {
|
|
473
|
+
tractors: {
|
|
474
|
+
name: 'tractors',
|
|
475
|
+
test: /tractors/u,
|
|
476
|
+
},
|
|
477
|
+
},
|
|
478
|
+
},
|
|
479
|
+
},
|
|
480
|
+
];
|
|
481
|
+
|
|
482
|
+
for (const chunkSplit of chunkSplits) {
|
|
483
|
+
expect(
|
|
484
|
+
mergeConfig([
|
|
485
|
+
pluginDefaults,
|
|
486
|
+
{
|
|
487
|
+
output: {
|
|
488
|
+
splitRouteChunks: false,
|
|
489
|
+
},
|
|
490
|
+
performance: {
|
|
491
|
+
chunkSplit,
|
|
492
|
+
},
|
|
493
|
+
splitChunks: false,
|
|
494
|
+
},
|
|
495
|
+
]),
|
|
496
|
+
).toMatchObject({
|
|
497
|
+
output: {
|
|
498
|
+
splitRouteChunks: false,
|
|
499
|
+
},
|
|
500
|
+
performance: {
|
|
501
|
+
chunkSplit,
|
|
502
|
+
},
|
|
503
|
+
splitChunks: false,
|
|
504
|
+
});
|
|
505
|
+
}
|
|
506
|
+
|
|
507
|
+
const pageSplitWithManualAsyncChunks = mergeConfig([
|
|
508
|
+
pluginDefaults,
|
|
509
|
+
{
|
|
510
|
+
performance: {
|
|
511
|
+
chunkSplit: {
|
|
512
|
+
strategy: 'custom',
|
|
513
|
+
splitChunks: {
|
|
514
|
+
chunks: 'async',
|
|
515
|
+
},
|
|
516
|
+
},
|
|
517
|
+
},
|
|
518
|
+
},
|
|
519
|
+
]);
|
|
520
|
+
|
|
521
|
+
expect(pageSplitWithManualAsyncChunks).toMatchObject({
|
|
522
|
+
output: {
|
|
523
|
+
splitRouteChunks: true,
|
|
524
|
+
},
|
|
525
|
+
performance: {
|
|
526
|
+
chunkSplit: {
|
|
527
|
+
strategy: 'custom',
|
|
528
|
+
splitChunks: {
|
|
529
|
+
chunks: 'async',
|
|
530
|
+
},
|
|
531
|
+
},
|
|
532
|
+
},
|
|
533
|
+
});
|
|
534
|
+
});
|
|
535
|
+
|
|
536
|
+
test('keeps custom cache group details intact', () => {
|
|
537
|
+
const pluginDefaults = createTanstackRsbuildRouteSplittingProfile(
|
|
538
|
+
{},
|
|
539
|
+
).defaultConfig;
|
|
540
|
+
|
|
541
|
+
const mergedConfig = mergeConfig([
|
|
542
|
+
pluginDefaults,
|
|
543
|
+
{
|
|
544
|
+
performance: {
|
|
545
|
+
chunkSplit: {
|
|
546
|
+
strategy: 'custom',
|
|
547
|
+
splitChunks: {
|
|
548
|
+
chunks: 'all',
|
|
549
|
+
cacheGroups: {
|
|
550
|
+
tractors: {
|
|
551
|
+
name: 'tractors',
|
|
552
|
+
test: /tractors/u,
|
|
553
|
+
},
|
|
554
|
+
},
|
|
555
|
+
},
|
|
556
|
+
},
|
|
557
|
+
},
|
|
558
|
+
},
|
|
559
|
+
]);
|
|
560
|
+
|
|
561
|
+
expect(
|
|
562
|
+
(
|
|
563
|
+
mergedConfig as {
|
|
564
|
+
performance?: {
|
|
565
|
+
chunkSplit?: {
|
|
566
|
+
splitChunks?: {
|
|
567
|
+
cacheGroups?: {
|
|
568
|
+
tractors?: {
|
|
569
|
+
test?: RegExp;
|
|
570
|
+
};
|
|
571
|
+
};
|
|
572
|
+
};
|
|
573
|
+
};
|
|
574
|
+
};
|
|
575
|
+
}
|
|
576
|
+
).performance?.chunkSplit?.splitChunks?.cacheGroups?.tractors?.test,
|
|
577
|
+
).toEqual(/tractors/u);
|
|
578
|
+
expect(mergedConfig).toMatchObject({
|
|
579
|
+
output: {
|
|
580
|
+
splitRouteChunks: true,
|
|
581
|
+
},
|
|
582
|
+
performance: {
|
|
583
|
+
chunkSplit: {
|
|
584
|
+
strategy: 'custom',
|
|
585
|
+
splitChunks: {
|
|
586
|
+
chunks: 'all',
|
|
587
|
+
cacheGroups: {
|
|
588
|
+
tractors: {
|
|
589
|
+
name: 'tractors',
|
|
590
|
+
},
|
|
591
|
+
},
|
|
592
|
+
},
|
|
593
|
+
},
|
|
594
|
+
},
|
|
595
|
+
});
|
|
596
|
+
});
|
|
597
|
+
|
|
598
|
+
test('plugin opt-out can still combine with manual builder chunking', () => {
|
|
599
|
+
const pluginDefaults = createTanstackRsbuildRouteSplittingProfile({
|
|
600
|
+
routeCodeSplitting: false,
|
|
601
|
+
}).defaultConfig;
|
|
602
|
+
|
|
603
|
+
expect(
|
|
604
|
+
mergeConfig([
|
|
605
|
+
pluginDefaults,
|
|
606
|
+
{
|
|
607
|
+
performance: {
|
|
608
|
+
chunkSplit: {
|
|
609
|
+
strategy: 'single-vendor',
|
|
610
|
+
},
|
|
611
|
+
},
|
|
612
|
+
},
|
|
613
|
+
]),
|
|
614
|
+
).toMatchObject({
|
|
615
|
+
output: {
|
|
616
|
+
splitRouteChunks: false,
|
|
617
|
+
},
|
|
618
|
+
performance: {
|
|
619
|
+
chunkSplit: {
|
|
620
|
+
strategy: 'single-vendor',
|
|
621
|
+
},
|
|
622
|
+
},
|
|
623
|
+
});
|
|
624
|
+
});
|
|
386
625
|
});
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
import {
|
|
2
|
+
getModernTanstackRouterFastDefaults,
|
|
3
|
+
modernTanstackRouterFastDefaults,
|
|
4
|
+
} from '../../src/runtime/types';
|
|
5
|
+
|
|
6
|
+
describe('tanstack router fast defaults', () => {
|
|
7
|
+
test('enables structural sharing by default', () => {
|
|
8
|
+
expect(modernTanstackRouterFastDefaults).toEqual({
|
|
9
|
+
defaultStructuralSharing: true,
|
|
10
|
+
});
|
|
11
|
+
expect(getModernTanstackRouterFastDefaults()).toEqual({
|
|
12
|
+
defaultStructuralSharing: true,
|
|
13
|
+
});
|
|
14
|
+
});
|
|
15
|
+
|
|
16
|
+
test('allows explicit structural sharing override', () => {
|
|
17
|
+
expect(
|
|
18
|
+
getModernTanstackRouterFastDefaults({
|
|
19
|
+
defaultStructuralSharing: false,
|
|
20
|
+
}),
|
|
21
|
+
).toEqual({
|
|
22
|
+
defaultStructuralSharing: false,
|
|
23
|
+
});
|
|
24
|
+
});
|
|
25
|
+
});
|