@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
|
@@ -1,6 +1,8 @@
|
|
|
1
1
|
import "node:module";
|
|
2
|
-
import { createRootRoute, createRoute, notFound, redirect } from "@tanstack/react-router";
|
|
2
|
+
import { createRootRoute, createRoute, notFound, redirect, rootRouteId } from "@tanstack/react-router";
|
|
3
|
+
import { createElement } from "react";
|
|
3
4
|
import { DefaultNotFound } from "./DefaultNotFound.mjs";
|
|
5
|
+
import { withModernRouteMatchContext } from "./outlet.mjs";
|
|
4
6
|
import { isTanstackRscPayloadNavigationEnabled, loadTanstackRscRouteData } from "./rsc/payloadRouter.mjs";
|
|
5
7
|
function createTanstackRoute(options) {
|
|
6
8
|
return createRoute(options);
|
|
@@ -8,6 +10,10 @@ function createTanstackRoute(options) {
|
|
|
8
10
|
function createTanstackRootRoute(options) {
|
|
9
11
|
return createRootRoute(options);
|
|
10
12
|
}
|
|
13
|
+
function wrapRouteComponentWithModernContext(route, component, routeId) {
|
|
14
|
+
const routeMatchId = routeId || route.id;
|
|
15
|
+
if (component && routeMatchId) route.options.component = withModernRouteMatchContext(component, routeMatchId);
|
|
16
|
+
}
|
|
11
17
|
function toTanstackPath(pathname) {
|
|
12
18
|
return pathname.split('/').map((segment)=>{
|
|
13
19
|
if (!segment) return segment;
|
|
@@ -55,6 +61,40 @@ function normalizeModernLoaderResponse(result) {
|
|
|
55
61
|
}
|
|
56
62
|
return normalizeModernLoaderResult(result);
|
|
57
63
|
}
|
|
64
|
+
function pickRouteModuleComponent(routeModule, seen = new Set()) {
|
|
65
|
+
if ('function' == typeof routeModule || routeModule && 'object' == typeof routeModule && '$$typeof' in routeModule) return routeModule;
|
|
66
|
+
if (!routeModule || 'object' != typeof routeModule) return;
|
|
67
|
+
if (seen.has(routeModule)) return;
|
|
68
|
+
seen.add(routeModule);
|
|
69
|
+
const module = routeModule;
|
|
70
|
+
for (const candidate of [
|
|
71
|
+
module.default,
|
|
72
|
+
module.Component
|
|
73
|
+
]){
|
|
74
|
+
const component = pickRouteModuleComponent(candidate, seen);
|
|
75
|
+
if (component) return component;
|
|
76
|
+
}
|
|
77
|
+
}
|
|
78
|
+
function createServerLazyImportComponent(lazyImport, fallbackComponent) {
|
|
79
|
+
if ("u" > typeof document) return fallbackComponent;
|
|
80
|
+
let resolvedComponent;
|
|
81
|
+
let pendingLoad;
|
|
82
|
+
const load = async ()=>{
|
|
83
|
+
if (resolvedComponent) return resolvedComponent;
|
|
84
|
+
const routeModule = await lazyImport();
|
|
85
|
+
const component = pickRouteModuleComponent(routeModule);
|
|
86
|
+
if (component) resolvedComponent = component;
|
|
87
|
+
return resolvedComponent;
|
|
88
|
+
};
|
|
89
|
+
const Component = (props)=>{
|
|
90
|
+
if (resolvedComponent) return createElement(resolvedComponent, props);
|
|
91
|
+
pendingLoad ||= load();
|
|
92
|
+
throw pendingLoad;
|
|
93
|
+
};
|
|
94
|
+
Component.load = load;
|
|
95
|
+
Component.preload = load;
|
|
96
|
+
return Component;
|
|
97
|
+
}
|
|
58
98
|
function isAbsoluteUrl(value) {
|
|
59
99
|
try {
|
|
60
100
|
new URL(value);
|
|
@@ -127,7 +167,7 @@ function wrapModernLoader(modernRoute, modernLoader, revalidationState, options
|
|
|
127
167
|
const signal = ctx?.abortController?.signal || ctx?.signal || new AbortController().signal;
|
|
128
168
|
const baseRequest = ctx?.context?.request instanceof Request ? ctx.context.request : void 0;
|
|
129
169
|
const href = 'string' == typeof ctx?.location ? ctx.location : ctx?.location?.publicHref || ctx?.location?.href || ctx?.location?.url?.href || '';
|
|
130
|
-
const request = baseRequest ? new Request(baseRequest, {
|
|
170
|
+
const request = void 0 !== baseRequest ? new Request(baseRequest, {
|
|
131
171
|
signal
|
|
132
172
|
}) : createModernRequest(href, signal);
|
|
133
173
|
const params = mapParamsForModernLoader({
|
|
@@ -192,7 +232,7 @@ function wrapRouteObjectLoader(route, revalidationState, options = {}) {
|
|
|
192
232
|
const signal = ctx?.abortController?.signal || ctx?.signal || new AbortController().signal;
|
|
193
233
|
const baseRequest = ctx?.context?.request instanceof Request ? ctx.context.request : void 0;
|
|
194
234
|
const href = 'string' == typeof ctx?.location ? ctx.location : ctx?.location?.publicHref || ctx?.location?.href || ctx?.location?.url?.href || '';
|
|
195
|
-
const request = baseRequest ? new Request(baseRequest, {
|
|
235
|
+
const request = void 0 !== baseRequest ? new Request(baseRequest, {
|
|
196
236
|
signal
|
|
197
237
|
}) : createModernRequest(href, signal);
|
|
198
238
|
const params = mapParamsForRouteObjectLoader({
|
|
@@ -229,10 +269,18 @@ function wrapRouteObjectLoader(route, revalidationState, options = {}) {
|
|
|
229
269
|
}
|
|
230
270
|
function toRouteComponent(routeObject) {
|
|
231
271
|
const route = routeObject;
|
|
272
|
+
const lazyImport = 'function' == typeof route.lazyImport ? route.lazyImport : void 0;
|
|
273
|
+
const fallbackComponent = route.Component ? route.Component : route.element ? ()=>route.element : void 0;
|
|
274
|
+
if (lazyImport && fallbackComponent) return createServerLazyImportComponent(lazyImport, fallbackComponent);
|
|
232
275
|
if (route.Component) return route.Component;
|
|
233
276
|
const element = route.element;
|
|
234
277
|
if (element) return ()=>element;
|
|
235
278
|
}
|
|
279
|
+
function toModernRouteComponent(route) {
|
|
280
|
+
const component = route.component || void 0;
|
|
281
|
+
if ('function' == typeof route.lazyImport && component) return createServerLazyImportComponent(route.lazyImport, component);
|
|
282
|
+
return component;
|
|
283
|
+
}
|
|
236
284
|
function toErrorComponent(routeObject) {
|
|
237
285
|
const route = routeObject;
|
|
238
286
|
if (route.ErrorBoundary) return route.ErrorBoundary;
|
|
@@ -270,12 +318,14 @@ function createRouteFromRouteObject(opts) {
|
|
|
270
318
|
const shouldRevalidate = modernRouteObject.shouldRevalidate;
|
|
271
319
|
const shouldReload = createModernShouldReload(shouldRevalidate, revalidationState);
|
|
272
320
|
const stableFallbackId = routeObject.id || modernRouteObject.file || routeObject.path || 'pathless';
|
|
321
|
+
const component = toRouteComponent(routeObject);
|
|
273
322
|
const base = {
|
|
274
323
|
getParentRoute: ()=>parent,
|
|
275
|
-
component
|
|
324
|
+
component,
|
|
276
325
|
pendingComponent: toPendingComponent(routeObject),
|
|
277
326
|
errorComponent: toErrorComponent(routeObject),
|
|
278
|
-
|
|
327
|
+
validateSearch: modernRouteObject.validateSearch,
|
|
328
|
+
loaderDeps: modernRouteObject.loaderDeps,
|
|
279
329
|
staticData: createRouteStaticData({
|
|
280
330
|
modernRouteId: routeObject.id,
|
|
281
331
|
modernRouteAction: modernRouteObject.action,
|
|
@@ -294,6 +344,7 @@ function createRouteFromRouteObject(opts) {
|
|
|
294
344
|
if (isRouteObjectPathlessLayout(routeObject)) base.id = stableFallbackId;
|
|
295
345
|
else base.path = routeObject.index ? '/' : toTanstackPath(routeObject.path || '');
|
|
296
346
|
const route = createTanstackRoute(base);
|
|
347
|
+
wrapRouteComponentWithModernContext(route, component, routeObject.id);
|
|
297
348
|
const children = routeObject.children;
|
|
298
349
|
if (children && children.length > 0) {
|
|
299
350
|
const childRoutes = children.map((child)=>createRouteFromRouteObject({
|
|
@@ -313,7 +364,7 @@ function createRouteFromModernRoute(opts) {
|
|
|
313
364
|
const stableFallbackId = modernId || route._component || route.filename || route.data || ('function' == typeof route.loader ? route.id : void 0);
|
|
314
365
|
const pendingComponent = route.loading || route.pendingComponent;
|
|
315
366
|
const errorComponent = route.error || route.errorComponent;
|
|
316
|
-
const component = route
|
|
367
|
+
const component = toModernRouteComponent(route);
|
|
317
368
|
const modernLoader = route.loader;
|
|
318
369
|
const modernAction = route.action;
|
|
319
370
|
const modernShouldRevalidate = route.shouldRevalidate;
|
|
@@ -325,7 +376,8 @@ function createRouteFromModernRoute(opts) {
|
|
|
325
376
|
component: component || void 0,
|
|
326
377
|
pendingComponent: pendingComponent || void 0,
|
|
327
378
|
errorComponent: errorComponent || void 0,
|
|
328
|
-
|
|
379
|
+
validateSearch: route.validateSearch,
|
|
380
|
+
loaderDeps: route.loaderDeps,
|
|
329
381
|
staticData: createRouteStaticData({
|
|
330
382
|
modernRouteId: modernId,
|
|
331
383
|
modernRouteAction: modernAction,
|
|
@@ -347,6 +399,7 @@ function createRouteFromModernRoute(opts) {
|
|
|
347
399
|
base.path = isIndexRoute ? '/' : toTanstackPath(rawPath || '');
|
|
348
400
|
}
|
|
349
401
|
const tanstackRoute = createTanstackRoute(base);
|
|
402
|
+
wrapRouteComponentWithModernContext(tanstackRoute, component, modernId);
|
|
350
403
|
const children = route.children;
|
|
351
404
|
if (children && children.length > 0) {
|
|
352
405
|
const childRoutes = children.map((child)=>createRouteFromModernRoute({
|
|
@@ -360,7 +413,7 @@ function createRouteFromModernRoute(opts) {
|
|
|
360
413
|
}
|
|
361
414
|
function createRouteTreeFromModernRoutes(routes, options = {}) {
|
|
362
415
|
const rootModern = routes.find((r)=>r && 'nested' === r.type && r.isRoot);
|
|
363
|
-
const rootComponent = rootModern
|
|
416
|
+
const rootComponent = rootModern ? toModernRouteComponent(rootModern) : void 0;
|
|
364
417
|
const pendingComponent = rootModern?.loading;
|
|
365
418
|
const errorComponent = rootModern?.error;
|
|
366
419
|
const rootLoader = rootModern?.loader;
|
|
@@ -373,7 +426,8 @@ function createRouteTreeFromModernRoutes(routes, options = {}) {
|
|
|
373
426
|
component: rootComponent || void 0,
|
|
374
427
|
pendingComponent: pendingComponent || void 0,
|
|
375
428
|
errorComponent: errorComponent || void 0,
|
|
376
|
-
|
|
429
|
+
validateSearch: rootModern?.validateSearch,
|
|
430
|
+
loaderDeps: rootModern?.loaderDeps,
|
|
377
431
|
notFoundComponent: DefaultNotFound,
|
|
378
432
|
staticData: createRouteStaticData({
|
|
379
433
|
modernRouteId: rootModernId,
|
|
@@ -391,6 +445,7 @@ function createRouteTreeFromModernRoutes(routes, options = {}) {
|
|
|
391
445
|
if (rootShouldReload) rootRouteOptions.shouldReload = rootShouldReload;
|
|
392
446
|
if (rootModern?.inValidSSRRoute) rootRouteOptions.ssr = false;
|
|
393
447
|
const rootRoute = createTanstackRootRoute(rootRouteOptions);
|
|
448
|
+
if (rootComponent) rootRoute.options.component = withModernRouteMatchContext(rootComponent, rootRouteId);
|
|
394
449
|
const topLevel = rootModern ? rootModern.children || [] : routes;
|
|
395
450
|
const childRoutes = topLevel.map((child)=>createRouteFromModernRoute({
|
|
396
451
|
options,
|
|
@@ -408,11 +463,13 @@ function createRouteTreeFromRouteObjects(routes, options = {}) {
|
|
|
408
463
|
const rootRevalidationState = {};
|
|
409
464
|
const rootShouldRevalidate = rootLikeRoute?.shouldRevalidate;
|
|
410
465
|
const rootShouldReload = createModernShouldReload(rootShouldRevalidate, rootRevalidationState);
|
|
466
|
+
const rootComponent = rootLikeRoute ? toRouteComponent(rootLikeRoute) : void 0;
|
|
411
467
|
const rootRouteOptions = {
|
|
412
|
-
component:
|
|
468
|
+
component: rootComponent,
|
|
413
469
|
pendingComponent: rootLikeRoute ? toPendingComponent(rootLikeRoute) : void 0,
|
|
414
470
|
errorComponent: rootLikeRoute ? toErrorComponent(rootLikeRoute) : void 0,
|
|
415
|
-
|
|
471
|
+
validateSearch: rootLikeRoute?.validateSearch,
|
|
472
|
+
loaderDeps: rootLikeRoute?.loaderDeps,
|
|
416
473
|
notFoundComponent: DefaultNotFound,
|
|
417
474
|
staticData: createRouteStaticData({
|
|
418
475
|
modernRouteId: rootLikeRoute?.id,
|
|
@@ -430,6 +487,7 @@ function createRouteTreeFromRouteObjects(routes, options = {}) {
|
|
|
430
487
|
if (rootShouldReload) rootRouteOptions.shouldReload = rootShouldReload;
|
|
431
488
|
if (rootLikeRoute?.inValidSSRRoute) rootRouteOptions.ssr = false;
|
|
432
489
|
const rootRoute = createTanstackRootRoute(rootRouteOptions);
|
|
490
|
+
if (rootComponent) rootRoute.options.component = withModernRouteMatchContext(rootComponent, rootRouteId);
|
|
433
491
|
const topLevel = rootLikeRoute ? [
|
|
434
492
|
...rootLikeRoute.children || [],
|
|
435
493
|
...routes.filter((route)=>route !== rootLikeRoute)
|
|
@@ -444,9 +502,11 @@ function createRouteTreeFromRouteObjects(routes, options = {}) {
|
|
|
444
502
|
}
|
|
445
503
|
function getModernRouteIdsFromMatches(router) {
|
|
446
504
|
const matches = router.state.matches || [];
|
|
505
|
+
const routesById = router.routesById;
|
|
447
506
|
const ids = matches.map((match)=>{
|
|
448
|
-
const
|
|
449
|
-
|
|
507
|
+
const normalizedMatch = match;
|
|
508
|
+
const routeId = 'string' == typeof normalizedMatch.routeId ? normalizedMatch.routeId : void 0;
|
|
509
|
+
return normalizedMatch.route?.options?.staticData?.modernRouteId ?? (routeId ? routesById?.[routeId]?.options?.staticData?.modernRouteId : void 0);
|
|
450
510
|
}).filter((id)=>'string' == typeof id);
|
|
451
511
|
return Array.from(new Set(ids));
|
|
452
512
|
}
|
|
@@ -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,15 +1,21 @@
|
|
|
1
1
|
import type { AppTools, AppToolsContext, CliPlugin } from '@modern-js/app-tools';
|
|
2
2
|
import type { NestedRouteForCli, PageRoute } from '@modern-js/types';
|
|
3
|
-
|
|
3
|
+
import { type TanstackRouteCodeSplittingOption } from './routeSplitting';
|
|
4
|
+
export type { TanstackRouteCodeSplittingOption, TanstackRsbuildRouteSplittingProfile, } from './routeSplitting';
|
|
5
|
+
export { createTanstackRsbuildRouteSplittingProfile, isTanstackStartRouteModuleSource, resolveTanstackRouteCodeSplittingEnabled, } from './routeSplitting';
|
|
6
|
+
export { collectCanonicalRoutesForEntry, 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[];
|
|
10
14
|
generatedDirName?: string;
|
|
11
15
|
runtimeModule?: string;
|
|
12
16
|
srcDirectory: string;
|
|
17
|
+
canonicalRoutes?: Record<string, string> | null;
|
|
18
|
+
i18nRuntimeModule?: string;
|
|
13
19
|
}): Promise<void>;
|
|
14
20
|
export declare function writeTanstackRouterTypesForEntries(opts: {
|
|
15
21
|
appContext: AppToolsContext;
|
|
@@ -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;
|
|
@@ -1,5 +1,14 @@
|
|
|
1
1
|
import type { AppToolsContext } from '@modern-js/app-tools';
|
|
2
2
|
import type { NestedRouteForCli, PageRoute } from '@modern-js/types';
|
|
3
|
+
/**
|
|
4
|
+
* Derive the canonical (language-agnostic) route map for an entry: the
|
|
5
|
+
* leading locale param is stripped and localized physical variants (routes
|
|
6
|
+
* carrying `modernCanonicalPath` metadata from `@modern-js/plugin-i18n`)
|
|
7
|
+
* collapse to their canonical pattern. Returns `null` when the entry has no
|
|
8
|
+
* i18n routing surface (no locale param and no localized variants), so plain
|
|
9
|
+
* TanStack apps never get a `@modern-js/plugin-i18n` module augmentation.
|
|
10
|
+
*/
|
|
11
|
+
export declare function collectCanonicalRoutesForEntry(routes: (NestedRouteForCli | PageRoute)[]): Record<string, string> | null;
|
|
3
12
|
export declare function isTanstackRouterFrameworkEnabled(appContext: AppToolsContext): Promise<boolean>;
|
|
4
13
|
export declare function generateTanstackRouterTypesSourceForEntry(opts: {
|
|
5
14
|
appContext: AppToolsContext;
|
|
@@ -1,27 +1,12 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
declare const onBeforeCreateRoutes:
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
declare const
|
|
10
|
-
tap: (cb: any) => void;
|
|
11
|
-
call: (...params: any[]) => any;
|
|
12
|
-
};
|
|
13
|
-
declare const onAfterCreateRouter: {
|
|
14
|
-
tap: (cb: any) => void;
|
|
15
|
-
call: (...params: any[]) => any;
|
|
16
|
-
};
|
|
17
|
-
declare const onBeforeHydrateRouter: {
|
|
18
|
-
tap: (cb: any) => void;
|
|
19
|
-
call: (...params: any[]) => any;
|
|
20
|
-
};
|
|
21
|
-
declare const onAfterHydrateRouter: {
|
|
22
|
-
tap: (cb: any) => void;
|
|
23
|
-
call: (...params: any[]) => any;
|
|
24
|
-
};
|
|
1
|
+
import type { TRuntimeContext } from '@modern-js/runtime/context';
|
|
2
|
+
import type { RouteObject } from '@modern-js/runtime-utils/router';
|
|
3
|
+
import type { RouterLifecycleContext } from './lifecycle';
|
|
4
|
+
declare const modifyRoutes: import("@modern-js/plugin").SyncHook<(routes: RouteObject[]) => RouteObject[]>;
|
|
5
|
+
declare const onBeforeCreateRoutes: import("@modern-js/plugin").SyncHook<(context: TRuntimeContext) => void>;
|
|
6
|
+
declare const onBeforeCreateRouter: import("@modern-js/plugin").SyncHook<(context: RouterLifecycleContext) => void>;
|
|
7
|
+
declare const onAfterCreateRouter: import("@modern-js/plugin").SyncHook<(context: RouterLifecycleContext) => void>;
|
|
8
|
+
declare const onBeforeHydrateRouter: import("@modern-js/plugin").SyncHook<(context: RouterLifecycleContext) => void>;
|
|
9
|
+
declare const onAfterHydrateRouter: import("@modern-js/plugin").SyncHook<(context: RouterLifecycleContext) => void>;
|
|
25
10
|
export { modifyRoutes, onAfterCreateRouter, onAfterHydrateRouter, onBeforeCreateRouter, onBeforeCreateRoutes, onBeforeHydrateRouter, };
|
|
26
11
|
export type RouterExtendsHooks = {
|
|
27
12
|
modifyRoutes: typeof modifyRoutes;
|
|
@@ -1,9 +1,12 @@
|
|
|
1
|
-
export * from '@tanstack/react-router';
|
|
2
|
-
export { useMatch } from '@tanstack/react-router';
|
|
1
|
+
export type * from '@tanstack/react-router';
|
|
2
|
+
export { Asset, Await, Block, CatchBoundary, CatchNotFound, ClientOnly, cleanPath, composeRewrites, createBrowserHistory, createControlledPromise, createFileRoute, createHashHistory, createHistory, createLazyFileRoute, createLazyRoute, createLink, createMemoryHistory, createRootRoute, createRootRouteWithContext, createRoute, createRouteMask, createRouter, createRouterConfig, createSerializationAdapter, DEFAULT_PROTOCOL_ALLOWLIST, DefaultGlobalNotFound, deepEqual, defaultParseSearch, defaultStringifySearch, defer, ErrorComponent, FileRoute, FileRouteLoader, functionalUpdate, getRouteApi, HeadContent, interpolatePath, isMatch, isNotFound, isPlainArray, isPlainObject, isRedirect, joinPaths, LazyRoute, lazyFn, lazyRouteComponent, linkOptions, Match, Matches, MatchRoute, Navigate, NotFoundRoute, notFound, parseSearchWith, RootRoute, Route, RouteApi, Router, RouterContextProvider, RouterProvider, reactUse, redirect, replaceEqualDeep, resolvePath, retainSearchParams, rootRouteId, rootRouteWithContext, ScriptOnce, Scripts, ScrollRestoration, SearchParamError, stringifySearchWith, stripSearchParams, trimPath, trimPathLeft, trimPathRight, useAwaited, useBlocker, useCanGoBack, useChildMatches, useElementScrollRestoration, useHydrated, useLayoutEffect, useLinkProps, useLoaderData, useLoaderDeps, useLocation, useMatch, useMatches, useMatchRoute, useNavigate, useParams, useParentMatches, useRouteContext, useRouter, useRouterState, useSearch, useTags, } from '@tanstack/react-router';
|
|
3
3
|
export type { Fetcher, FetcherState, FetcherSubmitOptions, FormProps, SubmitOptions, } from './dataMutation';
|
|
4
4
|
export { Form, RouteActionResponseError, useFetcher, } from './dataMutation';
|
|
5
|
+
export { Outlet } from './outlet';
|
|
5
6
|
export { tanstackRouterPlugin, tanstackRouterPlugin as default, } from './plugin';
|
|
6
7
|
export type { LinkProps, NavLinkProps, PrefetchBehavior, } from './prefetchLink';
|
|
7
8
|
export { Link, NavLink } from './prefetchLink';
|
|
8
9
|
export type { AnyCompositeComponent, AnyRenderableServerComponent, CompositeComponentProps, } from './rsc/client';
|
|
9
10
|
export { CompositeComponent } from './rsc/client';
|
|
11
|
+
export type { RouterConfig } from './types';
|
|
12
|
+
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>;
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export { default, tanstackRouterPlugin, } from './plugin.node';
|
|
@@ -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.120",
|
|
22
22
|
"engines": {
|
|
23
23
|
"node": ">=20"
|
|
24
24
|
},
|
|
@@ -85,33 +85,33 @@
|
|
|
85
85
|
}
|
|
86
86
|
},
|
|
87
87
|
"dependencies": {
|
|
88
|
-
"@swc/helpers": "^0.5.
|
|
89
|
-
"@tanstack/react-router": "1.170.
|
|
90
|
-
"@tanstack/router-core": "1.
|
|
91
|
-
"@modern-js/plugin": "npm:@bleedingdev/modern-js-plugin@3.2.0-ultramodern.
|
|
92
|
-
"@modern-js/
|
|
93
|
-
"@modern-js/
|
|
94
|
-
"@modern-js/utils": "npm:@bleedingdev/modern-js-utils@3.2.0-ultramodern.
|
|
88
|
+
"@swc/helpers": "^0.5.23",
|
|
89
|
+
"@tanstack/react-router": "1.170.15",
|
|
90
|
+
"@tanstack/router-core": "1.171.13",
|
|
91
|
+
"@modern-js/plugin": "npm:@bleedingdev/modern-js-plugin@3.2.0-ultramodern.120",
|
|
92
|
+
"@modern-js/runtime-utils": "npm:@bleedingdev/modern-js-runtime-utils@3.2.0-ultramodern.120",
|
|
93
|
+
"@modern-js/types": "npm:@bleedingdev/modern-js-types@3.2.0-ultramodern.120",
|
|
94
|
+
"@modern-js/utils": "npm:@bleedingdev/modern-js-utils@3.2.0-ultramodern.120"
|
|
95
95
|
},
|
|
96
96
|
"peerDependencies": {
|
|
97
|
-
"@modern-js/runtime": "3.2.0-ultramodern.
|
|
98
|
-
"react": "^19.2.
|
|
99
|
-
"react-dom": "^19.2.
|
|
97
|
+
"@modern-js/runtime": "3.2.0-ultramodern.120",
|
|
98
|
+
"react": "^19.2.7",
|
|
99
|
+
"react-dom": "^19.2.7"
|
|
100
100
|
},
|
|
101
101
|
"devDependencies": {
|
|
102
|
-
"@rslib/core": "0.
|
|
102
|
+
"@rslib/core": "0.22.0",
|
|
103
103
|
"@tanstack/history": "1.162.0",
|
|
104
104
|
"@testing-library/dom": "^10.4.1",
|
|
105
105
|
"@testing-library/react": "^16.3.2",
|
|
106
|
-
"@types/node": "^25.
|
|
107
|
-
"@types/react": "^19.2.
|
|
106
|
+
"@types/node": "^25.9.3",
|
|
107
|
+
"@types/react": "^19.2.17",
|
|
108
108
|
"@types/react-dom": "^19.2.3",
|
|
109
|
-
"@typescript/native-preview": "7.0.0-dev.
|
|
110
|
-
"react": "^19.2.
|
|
111
|
-
"react-dom": "^19.2.
|
|
112
|
-
"@modern-js/app-tools": "npm:@bleedingdev/modern-js-app-tools@3.2.0-ultramodern.
|
|
113
|
-
"@
|
|
114
|
-
"@
|
|
109
|
+
"@typescript/native-preview": "7.0.0-dev.20260610.1",
|
|
110
|
+
"react": "^19.2.7",
|
|
111
|
+
"react-dom": "^19.2.7",
|
|
112
|
+
"@modern-js/app-tools": "npm:@bleedingdev/modern-js-app-tools@3.2.0-ultramodern.120",
|
|
113
|
+
"@modern-js/runtime": "npm:@bleedingdev/modern-js-runtime@3.2.0-ultramodern.120",
|
|
114
|
+
"@scripts/rstest-config": "2.66.0"
|
|
115
115
|
},
|
|
116
116
|
"sideEffects": false,
|
|
117
117
|
"publishConfig": {
|
package/src/cli/index.ts
CHANGED
|
@@ -19,11 +19,26 @@ import {
|
|
|
19
19
|
NESTED_ROUTE_SPEC_FILE,
|
|
20
20
|
} from '@modern-js/utils';
|
|
21
21
|
import {
|
|
22
|
+
createTanstackRsbuildRouteSplittingProfile,
|
|
23
|
+
type TanstackRouteCodeSplittingOption,
|
|
24
|
+
} from './routeSplitting';
|
|
25
|
+
import {
|
|
26
|
+
collectCanonicalRoutesForEntry,
|
|
22
27
|
generateTanstackRouterTypesSourceForEntry,
|
|
23
28
|
isTanstackRouterFrameworkEnabled,
|
|
24
29
|
} from './tanstackTypes';
|
|
25
30
|
|
|
31
|
+
export type {
|
|
32
|
+
TanstackRouteCodeSplittingOption,
|
|
33
|
+
TanstackRsbuildRouteSplittingProfile,
|
|
34
|
+
} from './routeSplitting';
|
|
35
|
+
export {
|
|
36
|
+
createTanstackRsbuildRouteSplittingProfile,
|
|
37
|
+
isTanstackStartRouteModuleSource,
|
|
38
|
+
resolveTanstackRouteCodeSplittingEnabled,
|
|
39
|
+
} from './routeSplitting';
|
|
26
40
|
export {
|
|
41
|
+
collectCanonicalRoutesForEntry,
|
|
27
42
|
generateTanstackRouterTypesSourceForEntry,
|
|
28
43
|
isTanstackRouterFrameworkEnabled,
|
|
29
44
|
} from './tanstackTypes';
|
|
@@ -35,6 +50,7 @@ const ENTRYPOINTS_KEY = '@modern-js/plugin-tanstack';
|
|
|
35
50
|
export type TanstackRouterPluginOptions = {
|
|
36
51
|
routesDir?: string;
|
|
37
52
|
generatedDirName?: string;
|
|
53
|
+
routeCodeSplitting?: TanstackRouteCodeSplittingOption;
|
|
38
54
|
};
|
|
39
55
|
|
|
40
56
|
type RuntimeRouterCliHelpers = {
|
|
@@ -110,6 +126,8 @@ async function writeFileIfChanged(filePath: string, content: string) {
|
|
|
110
126
|
function createRegisterDtsContent(opts: {
|
|
111
127
|
entries: string[];
|
|
112
128
|
runtimeModule: string;
|
|
129
|
+
canonicalRoutes?: Record<string, string> | null;
|
|
130
|
+
i18nRuntimeModule?: string;
|
|
113
131
|
}) {
|
|
114
132
|
const importStatements = opts.entries
|
|
115
133
|
.map(
|
|
@@ -121,6 +139,20 @@ function createRegisterDtsContent(opts: {
|
|
|
121
139
|
.map((_, index) => `typeof router${index}`)
|
|
122
140
|
.join(' | ');
|
|
123
141
|
|
|
142
|
+
const canonicalEntries = Object.entries(opts.canonicalRoutes ?? {});
|
|
143
|
+
const canonicalRoutesAugmentation =
|
|
144
|
+
canonicalEntries.length > 0
|
|
145
|
+
? `
|
|
146
|
+
declare module '${opts.i18nRuntimeModule || '@modern-js/plugin-i18n/runtime'}' {
|
|
147
|
+
interface UltramodernCanonicalRoutes {
|
|
148
|
+
${canonicalEntries
|
|
149
|
+
.map(([routePath, paramsType]) => ` '${routePath}': ${paramsType};`)
|
|
150
|
+
.join('\n')}
|
|
151
|
+
}
|
|
152
|
+
}
|
|
153
|
+
`
|
|
154
|
+
: '';
|
|
155
|
+
|
|
124
156
|
return `// This file is auto-generated by Modern.js. Do not edit manually.
|
|
125
157
|
|
|
126
158
|
${importStatements}
|
|
@@ -130,7 +162,7 @@ declare module '${opts.runtimeModule}' {
|
|
|
130
162
|
router: ${routerUnionType};
|
|
131
163
|
}
|
|
132
164
|
}
|
|
133
|
-
`;
|
|
165
|
+
${canonicalRoutesAugmentation}`;
|
|
134
166
|
}
|
|
135
167
|
|
|
136
168
|
export async function writeTanstackRegisterFile(opts: {
|
|
@@ -138,12 +170,16 @@ export async function writeTanstackRegisterFile(opts: {
|
|
|
138
170
|
generatedDirName?: string;
|
|
139
171
|
runtimeModule?: string;
|
|
140
172
|
srcDirectory: string;
|
|
173
|
+
canonicalRoutes?: Record<string, string> | null;
|
|
174
|
+
i18nRuntimeModule?: string;
|
|
141
175
|
}) {
|
|
142
176
|
const {
|
|
143
177
|
entries,
|
|
144
178
|
generatedDirName = DEFAULT_GENERATED_DIR_NAME,
|
|
145
179
|
runtimeModule = '@modern-js/plugin-tanstack/runtime',
|
|
146
180
|
srcDirectory,
|
|
181
|
+
canonicalRoutes,
|
|
182
|
+
i18nRuntimeModule,
|
|
147
183
|
} = opts;
|
|
148
184
|
|
|
149
185
|
if (entries.length === 0) {
|
|
@@ -158,7 +194,12 @@ export async function writeTanstackRegisterFile(opts: {
|
|
|
158
194
|
|
|
159
195
|
await writeFileIfChanged(
|
|
160
196
|
registerDtsPath,
|
|
161
|
-
createRegisterDtsContent({
|
|
197
|
+
createRegisterDtsContent({
|
|
198
|
+
entries,
|
|
199
|
+
runtimeModule,
|
|
200
|
+
canonicalRoutes,
|
|
201
|
+
i18nRuntimeModule,
|
|
202
|
+
}),
|
|
162
203
|
);
|
|
163
204
|
}
|
|
164
205
|
|
|
@@ -211,10 +252,23 @@ export async function writeTanstackRouterTypesForEntries(opts: {
|
|
|
211
252
|
return a.localeCompare(b);
|
|
212
253
|
});
|
|
213
254
|
|
|
255
|
+
// Merge the canonical (language-agnostic) route maps of every entry so the
|
|
256
|
+
// typed i18n Link covers all routes the app can navigate to.
|
|
257
|
+
let canonicalRoutes: Record<string, string> | null = null;
|
|
258
|
+
for (const entryName of registerEntries) {
|
|
259
|
+
const entryCanonicalRoutes = collectCanonicalRoutesForEntry(
|
|
260
|
+
routesByEntry[entryName],
|
|
261
|
+
);
|
|
262
|
+
if (entryCanonicalRoutes) {
|
|
263
|
+
canonicalRoutes = { ...entryCanonicalRoutes, ...(canonicalRoutes ?? {}) };
|
|
264
|
+
}
|
|
265
|
+
}
|
|
266
|
+
|
|
214
267
|
await writeTanstackRegisterFile({
|
|
215
268
|
entries: registerEntries,
|
|
216
269
|
generatedDirName,
|
|
217
270
|
srcDirectory: appContext.srcDirectory,
|
|
271
|
+
canonicalRoutes,
|
|
218
272
|
});
|
|
219
273
|
}
|
|
220
274
|
|
|
@@ -224,6 +278,8 @@ export function tanstackRouterPlugin(
|
|
|
224
278
|
const routesDir = options.routesDir || DEFAULT_ROUTES_DIR;
|
|
225
279
|
const generatedDirName =
|
|
226
280
|
options.generatedDirName || DEFAULT_GENERATED_DIR_NAME;
|
|
281
|
+
const routeSplittingProfile =
|
|
282
|
+
createTanstackRsbuildRouteSplittingProfile(options);
|
|
227
283
|
|
|
228
284
|
return {
|
|
229
285
|
name: '@modern-js/plugin-tanstack',
|
|
@@ -265,6 +321,7 @@ export function tanstackRouterPlugin(
|
|
|
265
321
|
}));
|
|
266
322
|
|
|
267
323
|
api.config(() => ({
|
|
324
|
+
...routeSplittingProfile.defaultConfig,
|
|
268
325
|
source: {
|
|
269
326
|
include: [
|
|
270
327
|
/[\\/]node_modules[\\/]@tanstack[\\/]react-router[\\/]/,
|