@bleedingdev/modern-js-plugin-tanstack 3.2.0-ultramodern.120 → 3.2.0-ultramodern.122

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.
Files changed (94) hide show
  1. package/dist/cjs/cli/index.js +47 -27
  2. package/dist/cjs/cli/routeSplitting.js +0 -32
  3. package/dist/cjs/cli/tanstackTypes.js +34 -199
  4. package/dist/cjs/runtime/hooks.js +11 -14
  5. package/dist/cjs/runtime/index.js +107 -319
  6. package/dist/cjs/runtime/lifecycle.js +12 -86
  7. package/dist/cjs/runtime/loaderBridge.js +173 -0
  8. package/dist/cjs/runtime/plugin.js +6 -30
  9. package/dist/cjs/runtime/plugin.node.js +7 -29
  10. package/dist/cjs/runtime/pluginCore.js +55 -0
  11. package/dist/cjs/runtime/register.js +56 -0
  12. package/dist/cjs/runtime/routeTree.js +10 -207
  13. package/dist/cjs/runtime/{DefaultNotFound.js → router.js} +5 -15
  14. package/dist/cjs/runtime/rsc/payloadRouter.js +35 -1
  15. package/dist/cjs/runtime/state.js +45 -0
  16. package/dist/cjs/runtime/utils.js +0 -5
  17. package/dist/esm/cli/index.mjs +52 -26
  18. package/dist/esm/cli/routeSplitting.mjs +1 -30
  19. package/dist/esm/cli/tanstackTypes.mjs +32 -194
  20. package/dist/esm/runtime/hooks.mjs +1 -8
  21. package/dist/esm/runtime/index.mjs +4 -2
  22. package/dist/esm/runtime/lifecycle.mjs +1 -82
  23. package/dist/esm/runtime/loaderBridge.mjs +114 -0
  24. package/dist/esm/runtime/plugin.mjs +8 -32
  25. package/dist/esm/runtime/plugin.node.mjs +10 -32
  26. package/dist/esm/runtime/pluginCore.mjs +14 -0
  27. package/dist/esm/runtime/register.mjs +18 -0
  28. package/dist/esm/runtime/routeTree.mjs +4 -198
  29. package/dist/esm/runtime/router.mjs +2 -0
  30. package/dist/esm/runtime/rsc/payloadRouter.mjs +35 -1
  31. package/dist/esm/runtime/state.mjs +7 -0
  32. package/dist/esm/runtime/utils.mjs +0 -5
  33. package/dist/esm-node/cli/index.mjs +52 -26
  34. package/dist/esm-node/cli/routeSplitting.mjs +1 -30
  35. package/dist/esm-node/cli/tanstackTypes.mjs +32 -194
  36. package/dist/esm-node/runtime/hooks.mjs +1 -8
  37. package/dist/esm-node/runtime/index.mjs +4 -2
  38. package/dist/esm-node/runtime/lifecycle.mjs +1 -82
  39. package/dist/esm-node/runtime/loaderBridge.mjs +115 -0
  40. package/dist/esm-node/runtime/plugin.mjs +8 -32
  41. package/dist/esm-node/runtime/plugin.node.mjs +10 -32
  42. package/dist/esm-node/runtime/pluginCore.mjs +15 -0
  43. package/dist/esm-node/runtime/register.mjs +19 -0
  44. package/dist/esm-node/runtime/routeTree.mjs +4 -198
  45. package/dist/esm-node/runtime/router.mjs +3 -0
  46. package/dist/esm-node/runtime/rsc/payloadRouter.mjs +35 -1
  47. package/dist/esm-node/runtime/state.mjs +8 -0
  48. package/dist/esm-node/runtime/utils.mjs +0 -5
  49. package/dist/types/cli/index.d.ts +9 -2
  50. package/dist/types/cli/routeSplitting.d.ts +6 -15
  51. package/dist/types/cli/tanstackTypes.d.ts +13 -2
  52. package/dist/types/runtime/hooks.d.ts +8 -18
  53. package/dist/types/runtime/index.d.ts +6 -4
  54. package/dist/types/runtime/lifecycle.d.ts +7 -22
  55. package/dist/types/runtime/loaderBridge.d.ts +48 -0
  56. package/dist/types/runtime/plugin.d.ts +1 -14
  57. package/dist/types/runtime/plugin.node.d.ts +1 -14
  58. package/dist/types/runtime/pluginCore.d.ts +21 -0
  59. package/dist/types/runtime/register.d.ts +9 -0
  60. package/dist/types/runtime/routeTree.d.ts +0 -2
  61. package/dist/types/runtime/router.d.ts +14 -0
  62. package/dist/types/runtime/state.d.ts +16 -0
  63. package/dist/types/runtime/types.d.ts +7 -53
  64. package/package.json +31 -29
  65. package/rstest.config.mts +6 -0
  66. package/src/cli/index.ts +111 -29
  67. package/src/cli/routeSplitting.ts +6 -44
  68. package/src/cli/tanstackTypes.ts +78 -214
  69. package/src/runtime/hooks.ts +10 -27
  70. package/src/runtime/index.tsx +12 -107
  71. package/src/runtime/lifecycle.ts +16 -151
  72. package/src/runtime/loaderBridge.ts +257 -0
  73. package/src/runtime/plugin.node.tsx +14 -77
  74. package/src/runtime/plugin.tsx +12 -72
  75. package/src/runtime/pluginCore.ts +48 -0
  76. package/src/runtime/register.ts +58 -0
  77. package/src/runtime/routeTree.ts +8 -370
  78. package/src/runtime/router.ts +15 -0
  79. package/src/runtime/rsc/payloadRouter.ts +45 -2
  80. package/src/runtime/state.ts +29 -0
  81. package/src/runtime/types.ts +20 -67
  82. package/src/runtime/utils.tsx +3 -6
  83. package/tests/router/cli.test.ts +297 -31
  84. package/tests/router/hooks.test.ts +26 -0
  85. package/tests/router/loaderBridge.test.ts +211 -0
  86. package/tests/router/packageSurface.test.ts +24 -0
  87. package/tests/router/register.test.ts +46 -0
  88. package/tests/router/routeTree.test.ts +65 -180
  89. package/tests/router/rsc.test.tsx +70 -0
  90. package/tests/router/tanstackTypes.test.ts +164 -6
  91. package/dist/esm/runtime/DefaultNotFound.mjs +0 -13
  92. package/dist/esm-node/runtime/DefaultNotFound.mjs +0 -14
  93. package/dist/types/runtime/DefaultNotFound.d.ts +0 -2
  94. package/src/runtime/DefaultNotFound.tsx +0 -15
@@ -1,17 +1,6 @@
1
- import { findExists, formatImportPath, fs, slash } from "@modern-js/utils";
1
+ import { getPathWithoutExt, makeLegalIdentifier } from "@modern-js/runtime/cli";
2
+ import { findExists, formatImportPath, slash } from "@modern-js/utils";
2
3
  import path from "path";
3
- const reservedWords = 'break case class catch const continue debugger default delete do else export extends finally for function if import in instanceof let new return super switch this throw try typeof var void while with yield enum await implements package protected static interface private public';
4
- const builtins = 'arguments Infinity NaN undefined null true false eval uneval isFinite isNaN parseFloat parseInt decodeURI decodeURIComponent encodeURI encodeURIComponent escape unescape Object Function Boolean Symbol Error EvalError InternalError RangeError ReferenceError SyntaxError TypeError URIError Number Math Date String RegExp Array Int8Array Uint8Array Uint8ClampedArray Int16Array Uint16Array Int32Array Float32Array Float64Array Map Set WeakMap WeakSet SIMD ArrayBuffer DataView JSON Promise Generator GeneratorFunction Reflect Proxy Intl';
5
- const forbidList = new Set(`${reservedWords} ${builtins}`.split(' '));
6
- function makeLegalIdentifier(str) {
7
- const identifier = str.replace(/-(\w)/g, (_, letter)=>letter.toUpperCase()).replace(/[^$_a-zA-Z0-9]/g, '_');
8
- if (/\d/.test(identifier[0]) || forbidList.has(identifier)) return `_${identifier}`;
9
- return identifier || '_';
10
- }
11
- function getPathWithoutExt(filename) {
12
- const extname = path.extname(filename);
13
- return extname ? filename.slice(0, -extname.length) : filename;
14
- }
15
4
  const JS_OR_TS_EXTS = [
16
5
  '.js',
17
6
  '.jsx',
@@ -108,7 +97,8 @@ function paramsTypeForCanonicalPath(canonicalPath) {
108
97
  }
109
98
  return fields.length > 0 ? `{ ${fields.join('; ')} }` : 'Record<string, never>';
110
99
  }
111
- function collectCanonicalRoutesForEntry(routes) {
100
+ function collectCanonicalRoutesForEntry(routes, options = {}) {
101
+ const { localeParamHeuristic = true } = options;
112
102
  const canonicalParams = new Map();
113
103
  let hasI18nSurface = false;
114
104
  const normalizeJoined = (joined)=>{
@@ -128,7 +118,7 @@ function collectCanonicalRoutesForEntry(routes) {
128
118
  currentPath = normalizeJoined(route.modernCanonicalPath);
129
119
  } else if ('string' == typeof route.path && route.path.length > 0) {
130
120
  const segments = route.path.replace(/\[(.+?)\]/g, ':$1').split('/').filter(Boolean);
131
- if ('' === parentPath && LOCALE_PARAM_SEGMENTS.has(segments[0])) {
121
+ if (localeParamHeuristic && '' === parentPath && LOCALE_PARAM_SEGMENTS.has(segments[0])) {
132
122
  hasI18nSurface = true;
133
123
  segments.shift();
134
124
  }
@@ -149,17 +139,6 @@ function collectCanonicalRoutesForEntry(routes) {
149
139
  ...canonicalParams.entries()
150
140
  ].sort(([a], [b])=>a.localeCompare(b)));
151
141
  }
152
- async function isTanstackRouterFrameworkEnabled(appContext) {
153
- const runtimeConfigBase = path.join(appContext.srcDirectory, appContext.runtimeConfigFile);
154
- const runtimeConfigFile = findExists(JS_OR_TS_EXTS.map((ext)=>`${runtimeConfigBase}${ext}`));
155
- if (!runtimeConfigFile) return false;
156
- try {
157
- const content = await fs.readFile(runtimeConfigFile, 'utf-8');
158
- return /framework\s*:\s*['"]tanstack['"]/.test(content);
159
- } catch {
160
- return false;
161
- }
162
- }
163
142
  async function generateTanstackRouterTypesSourceForEntry(opts) {
164
143
  const { appContext, entryName, generatedDirName = 'modern-tanstack', routes } = opts;
165
144
  const outDir = path.join(appContext.srcDirectory, generatedDirName, entryName);
@@ -168,12 +147,30 @@ async function generateTanstackRouterTypesSourceForEntry(opts) {
168
147
  const imports = [];
169
148
  const statements = [];
170
149
  const loaderImportMap = new Map();
150
+ const componentImportMap = new Map();
171
151
  const searchContractImportMap = new Map();
172
152
  const usedRouteVarNames = new Set();
173
153
  let loaderIndex = 0;
154
+ let componentIndex = 0;
174
155
  let validateSearchIndex = 0;
175
156
  let loaderDepsIndex = 0;
176
157
  let routeIndex = 0;
158
+ const getImportNameForComponent = (componentPath)=>{
159
+ if ('string' != typeof componentPath || 0 === componentPath.length) return Promise.resolve(null);
160
+ let pendingImportName = componentImportMap.get(componentPath);
161
+ if (!pendingImportName) {
162
+ pendingImportName = (async ()=>{
163
+ const resolvedNoExt = await resolveRouteModuleNoExt(componentPath);
164
+ if (!resolvedNoExt) return null;
165
+ const relImport = normalizeRelativeImport(path.relative(outDir, resolvedNoExt));
166
+ const componentName = `component_${componentIndex++}`;
167
+ imports.push(`import ${componentName} from ${quote(relImport)};`);
168
+ return componentName;
169
+ })();
170
+ componentImportMap.set(componentPath, pendingImportName);
171
+ }
172
+ return pendingImportName;
173
+ };
177
174
  const resolveRouteModuleNoExt = async (aliasedNoExtPath)=>{
178
175
  const prefix = `${appContext.internalSrcAlias}/`;
179
176
  let absNoExt;
@@ -248,6 +245,8 @@ async function generateTanstackRouterTypesSourceForEntry(opts) {
248
245
  const routeOpts = [
249
246
  `getParentRoute: () => ${parentVar},`
250
247
  ];
248
+ const componentName = await getImportNameForComponent(route._component);
249
+ if (componentName) routeOpts.push(`component: ${componentName},`);
251
250
  if (isPathlessLayout(route)) {
252
251
  const id = route.id;
253
252
  routeOpts.push(`id: ${quote(id || 'pathless')},`);
@@ -290,6 +289,8 @@ async function generateTanstackRouterTypesSourceForEntry(opts) {
290
289
  route
291
290
  })));
292
291
  const rootOpts = [];
292
+ const rootComponentName = await getImportNameForComponent(rootModern?._component);
293
+ if (rootComponentName) rootOpts.push(`component: ${rootComponentName},`);
293
294
  if (rootLoaderName) rootOpts.push(`loader: modernLoaderToTanstack({ hasSplat: false }, ${rootLoaderName}),`);
294
295
  if (rootValidateSearchName) rootOpts.push(`validateSearch: ${rootValidateSearchName},`);
295
296
  if (rootLoaderDepsName) rootOpts.push(`loaderDeps: ${rootLoaderDepsName},`);
@@ -298,178 +299,15 @@ async function generateTanstackRouterTypesSourceForEntry(opts) {
298
299
 
299
300
  import {
300
301
  createMemoryHistory,
301
- modernTanstackRouterFastDefaults,
302
302
  createRootRouteWithContext,
303
303
  createRoute,
304
304
  createRouter,
305
- notFound,
306
- redirect,
305
+ createRouteStaticData,
306
+ type ModernRouterContext,
307
+ modernLoaderToTanstack,
308
+ modernTanstackRouterFastDefaults,
307
309
  } from '@modern-js/plugin-tanstack/runtime';
308
310
 
309
- type ModernRouterContext = {
310
- request?: Request;
311
- requestContext?: unknown;
312
- };
313
-
314
- function isResponse(value: unknown): value is Response {
315
- return (
316
- value != null &&
317
- typeof value === 'object' &&
318
- typeof (value as any).status === 'number' &&
319
- typeof (value as any).headers === 'object'
320
- );
321
- }
322
-
323
- const redirectStatusCodes = new Set([301, 302, 303, 307, 308]);
324
- function isRedirectResponse(res: Response) {
325
- return redirectStatusCodes.has(res.status);
326
- }
327
-
328
- function throwTanstackRedirect(location: string) {
329
- const target = location.length > 0 ? location : '/';
330
- try {
331
- void new URL(target);
332
- throw redirect({ href: target });
333
- } catch {
334
- throw redirect({ to: target });
335
- }
336
- }
337
-
338
- function mapParamsForModernLoader(params: Record<string, string>, hasSplat: boolean) {
339
- if (!hasSplat) {
340
- return params;
341
- }
342
-
343
- const { _splat, ...rest } = params as any;
344
- if (typeof _splat !== 'undefined') {
345
- return { ...rest, '*': _splat };
346
- }
347
- return rest;
348
- }
349
-
350
- function createRouteStaticData(opts: {
351
- modernRouteId?: string;
352
- modernRouteAction?: unknown;
353
- modernRouteLoader?: unknown;
354
- }) {
355
- const staticData: {
356
- modernRouteId?: string;
357
- modernRouteAction?: unknown;
358
- modernRouteLoader?: unknown;
359
- } = {};
360
-
361
- if (typeof opts.modernRouteId === 'string' && opts.modernRouteId.length > 0) {
362
- staticData.modernRouteId = opts.modernRouteId;
363
- }
364
-
365
- if (typeof opts.modernRouteLoader !== 'undefined') {
366
- staticData.modernRouteLoader = opts.modernRouteLoader;
367
- }
368
-
369
- if (typeof opts.modernRouteAction !== 'undefined') {
370
- staticData.modernRouteAction = opts.modernRouteAction;
371
- }
372
-
373
- return staticData;
374
- }
375
-
376
- function getLoaderSignal(ctx: any): AbortSignal {
377
- const abortSignal = ctx?.abortController?.signal;
378
- if (abortSignal instanceof AbortSignal) {
379
- return abortSignal;
380
- }
381
- if (ctx?.signal instanceof AbortSignal) {
382
- return ctx.signal;
383
- }
384
- return new AbortController().signal;
385
- }
386
-
387
- function getLoaderHref(ctx: any): string {
388
- if (typeof ctx?.location === 'string') {
389
- return ctx.location;
390
- }
391
-
392
- const publicHref = ctx?.location?.publicHref;
393
- if (typeof publicHref === 'string') {
394
- return publicHref;
395
- }
396
-
397
- const href = ctx?.location?.href;
398
- if (typeof href === 'string') {
399
- return href;
400
- }
401
-
402
- const urlHref = ctx?.location?.url?.href;
403
- return typeof urlHref === 'string' ? urlHref : '';
404
- }
405
-
406
- function getLoaderParams(ctx: any): Record<string, string> {
407
- return typeof ctx?.params === 'object' && ctx.params !== null ? ctx.params : {};
408
- }
409
-
410
- function handleModernLoaderResult<LoaderResult>(result: LoaderResult): LoaderResult {
411
- if (isResponse(result)) {
412
- if (isRedirectResponse(result)) {
413
- const location = result.headers.get('Location') ?? '/';
414
- throwTanstackRedirect(location);
415
- }
416
- if (result.status === 404) {
417
- throw notFound();
418
- }
419
- }
420
-
421
- return result;
422
- }
423
-
424
- function handleModernLoaderError(err: unknown): never {
425
- if (isResponse(err)) {
426
- if (isRedirectResponse(err)) {
427
- const location = err.headers.get('Location') ?? '/';
428
- throwTanstackRedirect(location);
429
- }
430
- if (err.status === 404) {
431
- throw notFound();
432
- }
433
- }
434
-
435
- throw err;
436
- }
437
-
438
- function modernLoaderToTanstack<TLoader extends (args: any) => any>(
439
- opts: { hasSplat: boolean },
440
- modernLoader: TLoader,
441
- ) {
442
- type LoaderResult = Awaited<ReturnType<TLoader>>;
443
-
444
- return (ctx: any): Promise<LoaderResult> => {
445
- try {
446
- const signal = getLoaderSignal(ctx);
447
- const baseRequest: Request | undefined =
448
- ctx?.context?.request instanceof Request ? ctx.context.request : undefined;
449
-
450
- const href = getLoaderHref(ctx);
451
-
452
- const request = baseRequest !== undefined
453
- ? new Request(baseRequest, { signal })
454
- : new Request(href, { signal });
455
-
456
- const params = mapParamsForModernLoader(getLoaderParams(ctx), opts.hasSplat);
457
-
458
- return Promise.resolve(
459
- (modernLoader as any)({
460
- request,
461
- params,
462
- context: ctx?.context?.requestContext,
463
- }),
464
- )
465
- .then((result: LoaderResult) => handleModernLoaderResult(result))
466
- .catch(handleModernLoaderError);
467
- } catch (err) {
468
- handleModernLoaderError(err);
469
- }
470
- };
471
- }
472
-
473
311
  ${imports.join('\n')}
474
312
 
475
313
  export const rootRoute = createRootRouteWithContext<ModernRouterContext>()({
@@ -498,4 +336,4 @@ export const router = createRouter({
498
336
  routerGenTs
499
337
  };
500
338
  }
501
- export { collectCanonicalRoutesForEntry, generateTanstackRouterTypesSourceForEntry, isTanstackRouterFrameworkEnabled };
339
+ export { collectCanonicalRoutesForEntry, generateTanstackRouterTypesSourceForEntry };
@@ -1,8 +1 @@
1
- import { createSyncHook } from "@modern-js/plugin";
2
- const modifyRoutes = createSyncHook();
3
- const onBeforeCreateRoutes = createSyncHook();
4
- const onBeforeCreateRouter = createSyncHook();
5
- const onAfterCreateRouter = createSyncHook();
6
- const onBeforeHydrateRouter = createSyncHook();
7
- const onAfterHydrateRouter = createSyncHook();
8
- export { modifyRoutes, onAfterCreateRouter, onAfterHydrateRouter, onBeforeCreateRouter, onBeforeCreateRoutes, onBeforeHydrateRouter };
1
+ export { modifyRoutes, onAfterCreateRouter, onAfterHydrateRouter, onBeforeCreateRouter, onBeforeCreateRoutes, onBeforeHydrateRouter, routerProviderRegistryHooks } from "@modern-js/runtime/context";
@@ -1,7 +1,9 @@
1
- export { Asset, Await, Block, CatchBoundary, CatchNotFound, ClientOnly, DEFAULT_PROTOCOL_ALLOWLIST, DefaultGlobalNotFound, ErrorComponent, FileRoute, FileRouteLoader, HeadContent, LazyRoute, Match, MatchRoute, Matches, Navigate, NotFoundRoute, RootRoute, Route, RouteApi, Router, RouterContextProvider, RouterProvider, ScriptOnce, Scripts, ScrollRestoration, SearchParamError, cleanPath, composeRewrites, createBrowserHistory, createControlledPromise, createFileRoute, createHashHistory, createHistory, createLazyFileRoute, createLazyRoute, createLink, createMemoryHistory, createRootRoute, createRootRouteWithContext, createRoute, createRouteMask, createRouter, createRouterConfig, createSerializationAdapter, deepEqual, defaultParseSearch, defaultStringifySearch, defer, functionalUpdate, getRouteApi, interpolatePath, isMatch, isNotFound, isPlainArray, isPlainObject, isRedirect, joinPaths, lazyFn, lazyRouteComponent, linkOptions, notFound, parseSearchWith, reactUse, redirect, replaceEqualDeep, resolvePath, retainSearchParams, rootRouteId, rootRouteWithContext, stringifySearchWith, stripSearchParams, trimPath, trimPathLeft, trimPathRight, useAwaited, useBlocker, useCanGoBack, useChildMatches, useElementScrollRestoration, useHydrated, useLayoutEffect, useLinkProps, useLoaderData, useLoaderDeps, useLocation, useMatch, useMatchRoute, useMatches, useNavigate, useParams, useParentMatches, useRouteContext, useRouter, useRouterState, useSearch, useTags } from "@tanstack/react-router";
1
+ import "./register.mjs";
2
+ export * from "@tanstack/react-router";
2
3
  export { Form, RouteActionResponseError, useFetcher } from "./dataMutation.mjs";
4
+ export { createRouteStaticData, isAbsoluteUrl, modernLoaderToTanstack, throwTanstackRedirect } from "./loaderBridge.mjs";
3
5
  export { Outlet } from "./outlet.mjs";
4
6
  export { tanstackRouterPlugin as default, tanstackRouterPlugin } from "./plugin.mjs";
5
7
  export { Link, NavLink } from "./prefetchLink.mjs";
6
- export { CompositeComponent } from "./rsc/client.mjs";
8
+ export { getTanstackRouterState } from "./state.mjs";
7
9
  export { getModernTanstackRouterFastDefaults, modernTanstackRouterFastDefaults } from "./types.mjs";
@@ -1,82 +1 @@
1
- function toHydrationScripts(state) {
2
- if (state.hydrationScripts?.length) return state.hydrationScripts;
3
- return state.hydrationScript ? [
4
- state.hydrationScript
5
- ] : void 0;
6
- }
7
- function getMatchedRouteIdsFromMatches(matches) {
8
- const routeIds = matches?.map((match)=>match.assetRouteId ?? match.routeId).filter((routeId)=>'string' == typeof routeId);
9
- return routeIds?.length ? routeIds : void 0;
10
- }
11
- function createRouterServerSnapshot(state) {
12
- const hydrationScripts = toHydrationScripts(state);
13
- const matchedRouteIds = state.matchedRouteIds ?? getMatchedRouteIdsFromMatches(state.matches);
14
- return {
15
- ...state,
16
- ...hydrationScripts?.length ? {
17
- hydrationScript: state.hydrationScript ?? hydrationScripts[0],
18
- hydrationScripts
19
- } : {},
20
- ...matchedRouteIds ? {
21
- matchedRouteIds
22
- } : {}
23
- };
24
- }
25
- function createRouterRuntimeState(state) {
26
- const hasSnapshotState = Boolean(state.serverSnapshot) || Boolean(state.hydrationScript) || Boolean(state.hydrationScripts?.length) || Boolean(state.matchedRouteIds?.length) || Boolean(state.matches?.length);
27
- const serverSnapshot = state.serverSnapshot ? createRouterServerSnapshot({
28
- ...state.serverSnapshot,
29
- framework: state.serverSnapshot.framework ?? state.framework,
30
- basename: state.serverSnapshot.basename ?? state.basename,
31
- hydrationScript: state.serverSnapshot.hydrationScript ?? state.hydrationScript,
32
- hydrationScripts: state.serverSnapshot.hydrationScripts ?? state.hydrationScripts,
33
- matchedRouteIds: state.serverSnapshot.matchedRouteIds ?? state.matchedRouteIds,
34
- matches: state.serverSnapshot.matches ?? state.matches
35
- }) : hasSnapshotState ? createRouterServerSnapshot({
36
- framework: state.framework,
37
- basename: state.basename,
38
- hydrationScript: state.hydrationScript,
39
- hydrationScripts: state.hydrationScripts,
40
- matchedRouteIds: state.matchedRouteIds,
41
- matches: state.matches
42
- }) : void 0;
43
- const hydrationScripts = toHydrationScripts({
44
- hydrationScript: state.hydrationScript ?? serverSnapshot?.hydrationScript,
45
- hydrationScripts: state.hydrationScripts ?? serverSnapshot?.hydrationScripts
46
- });
47
- const matchedRouteIds = state.matchedRouteIds ?? serverSnapshot?.matchedRouteIds ?? getMatchedRouteIdsFromMatches(state.matches);
48
- return {
49
- ...state,
50
- ...hydrationScripts?.length ? {
51
- hydrationScript: state.hydrationScript ?? hydrationScripts[0],
52
- hydrationScripts
53
- } : {},
54
- ...matchedRouteIds ? {
55
- matchedRouteIds
56
- } : {},
57
- ...serverSnapshot ? {
58
- serverSnapshot
59
- } : {}
60
- };
61
- }
62
- function applyRouterRuntimeState(runtimeContext, state) {
63
- const normalized = createRouterRuntimeState(state);
64
- const mutableRuntimeContext = runtimeContext;
65
- mutableRuntimeContext.routerFramework = normalized.framework;
66
- mutableRuntimeContext.routerInstance = normalized.instance;
67
- mutableRuntimeContext.routerHydrationScript = normalized.hydrationScript;
68
- mutableRuntimeContext.routerMatchedRouteIds = normalized.matchedRouteIds;
69
- mutableRuntimeContext.routerRuntime = normalized;
70
- if (normalized.serverSnapshot) mutableRuntimeContext.routerServerSnapshot = normalized.serverSnapshot;
71
- return runtimeContext;
72
- }
73
- function applyRouterServerPrepareResult(runtimeContext, result) {
74
- const state = createRouterRuntimeState({
75
- ...result.state,
76
- cleanup: result.cleanup ?? result.state.cleanup,
77
- serverSnapshot: result.snapshot ?? result.state.serverSnapshot
78
- });
79
- applyRouterRuntimeState(runtimeContext, state);
80
- return runtimeContext;
81
- }
82
- export { applyRouterRuntimeState, applyRouterServerPrepareResult, createRouterRuntimeState, createRouterServerSnapshot };
1
+ export { applyRouterRuntimeState, applyRouterServerPrepareResult, createRouterRuntimeState, createRouterServerSnapshot, getRouterRuntimeState, getRouterServerSnapshot } from "@modern-js/runtime/context";
@@ -0,0 +1,114 @@
1
+ import { notFound, redirect } from "@tanstack/react-router";
2
+ function isResponse(value) {
3
+ const record = value;
4
+ return null != record && 'object' == typeof record && 'number' == typeof record.status && 'object' == typeof record.headers;
5
+ }
6
+ const redirectStatusCodes = new Set([
7
+ 301,
8
+ 302,
9
+ 303,
10
+ 307,
11
+ 308
12
+ ]);
13
+ function isRedirectResponse(res) {
14
+ return redirectStatusCodes.has(res.status);
15
+ }
16
+ function isTanstackRedirect(value) {
17
+ return isResponse(value) && 'object' == typeof value.options;
18
+ }
19
+ function isAbsoluteUrl(value) {
20
+ try {
21
+ new URL(value);
22
+ return true;
23
+ } catch {
24
+ return false;
25
+ }
26
+ }
27
+ function throwTanstackRedirect(location) {
28
+ const target = location || '/';
29
+ if (isAbsoluteUrl(target)) throw redirect({
30
+ href: target
31
+ });
32
+ throw redirect({
33
+ to: target
34
+ });
35
+ }
36
+ function mapSplatParamsForModernLoader(params, hasSplat) {
37
+ if (!hasSplat) return params;
38
+ const { _splat, ...rest } = params;
39
+ if (void 0 !== _splat) return {
40
+ ...rest,
41
+ '*': _splat
42
+ };
43
+ return rest;
44
+ }
45
+ function createRouteStaticData(opts) {
46
+ const staticData = {};
47
+ if ('string' == typeof opts.modernRouteId && opts.modernRouteId.length > 0) staticData.modernRouteId = opts.modernRouteId;
48
+ if (void 0 !== opts.modernRouteLoader) staticData.modernRouteLoader = opts.modernRouteLoader;
49
+ if (void 0 !== opts.modernRouteAction) staticData.modernRouteAction = opts.modernRouteAction;
50
+ return staticData;
51
+ }
52
+ function getLoaderSignal(ctx) {
53
+ const abortSignal = ctx?.abortController?.signal;
54
+ if (abortSignal instanceof AbortSignal) return abortSignal;
55
+ if (ctx?.signal instanceof AbortSignal) return ctx.signal;
56
+ return new AbortController().signal;
57
+ }
58
+ function getLoaderHref(ctx) {
59
+ if ('string' == typeof ctx?.location) return ctx.location;
60
+ const publicHref = ctx?.location?.publicHref;
61
+ if ('string' == typeof publicHref) return publicHref;
62
+ const href = ctx?.location?.href;
63
+ if ('string' == typeof href) return href;
64
+ const urlHref = ctx?.location?.url?.href;
65
+ return 'string' == typeof urlHref ? urlHref : '';
66
+ }
67
+ function getLoaderParams(ctx) {
68
+ return 'object' == typeof ctx?.params && null !== ctx.params ? ctx.params : {};
69
+ }
70
+ function handleModernLoaderResult(result) {
71
+ if (isResponse(result)) {
72
+ if (isRedirectResponse(result)) {
73
+ const location = result.headers.get('Location') ?? '/';
74
+ throwTanstackRedirect(location);
75
+ }
76
+ if (404 === result.status) throw notFound();
77
+ }
78
+ return result;
79
+ }
80
+ function handleModernLoaderError(err) {
81
+ if (isResponse(err)) {
82
+ if (isTanstackRedirect(err)) throw err;
83
+ if (isRedirectResponse(err)) {
84
+ const location = err.headers.get('Location') ?? '/';
85
+ throwTanstackRedirect(location);
86
+ }
87
+ if (404 === err.status) throw notFound();
88
+ }
89
+ throw err;
90
+ }
91
+ function modernLoaderToTanstack(opts, modernLoader) {
92
+ return (rawCtx)=>{
93
+ const ctx = rawCtx;
94
+ try {
95
+ const signal = getLoaderSignal(ctx);
96
+ const baseRequest = ctx?.context?.request instanceof Request ? ctx.context.request : void 0;
97
+ const href = getLoaderHref(ctx);
98
+ const request = void 0 !== baseRequest ? new Request(baseRequest, {
99
+ signal
100
+ }) : new Request(href, {
101
+ signal
102
+ });
103
+ const params = mapSplatParamsForModernLoader(getLoaderParams(ctx), opts.hasSplat);
104
+ return Promise.resolve(modernLoader({
105
+ request,
106
+ params,
107
+ context: ctx?.context?.requestContext
108
+ })).then((result)=>handleModernLoaderResult(result)).catch(handleModernLoaderError);
109
+ } catch (err) {
110
+ handleModernLoaderError(err);
111
+ }
112
+ };
113
+ }
114
+ export { createRouteStaticData, isAbsoluteUrl, isRedirectResponse, isResponse, isTanstackRedirect, mapSplatParamsForModernLoader, modernLoaderToTanstack, throwTanstackRedirect };
@@ -1,15 +1,15 @@
1
1
  import { jsx } from "react/jsx-runtime";
2
- import { InternalRuntimeContext, getGlobalEnableRsc, getGlobalLayoutApp, getGlobalRoutes } from "@modern-js/runtime/context";
3
- import { merge } from "@modern-js/runtime-utils/merge";
2
+ import { InternalRuntimeContext, getGlobalEnableRsc } from "@modern-js/runtime/context";
4
3
  import { normalizePathname } from "@modern-js/runtime-utils/url";
5
4
  import { RouterProvider, createBrowserHistory, createHashHistory, createRouter, useLocation, useMatches, useNavigate, useRouter } from "@tanstack/react-router";
6
5
  import { hydrate } from "@tanstack/react-router/ssr/client";
7
6
  import { useContext, useMemo } from "react";
8
7
  import { createModernBasepathRewrite } from "./basepathRewrite.mjs";
9
- import { modifyRoutes, onAfterCreateRouter, onAfterHydrateRouter, onBeforeCreateRouter, onBeforeCreateRoutes, onBeforeHydrateRouter } from "./hooks.mjs";
8
+ import { routerProviderRegistryHooks } from "./hooks.mjs";
10
9
  import { wrapTanstackSsrHydrationBoundary } from "./hydrationBoundary.mjs";
11
10
  import { applyRouterRuntimeState } from "./lifecycle.mjs";
12
11
  import { withModernRouteMatchContext } from "./outlet.mjs";
12
+ import { getFinalRouteConfig, getMergedRouterConfig } from "./pluginCore.mjs";
13
13
  import { Link } from "./prefetchLink.mjs";
14
14
  import { createRouteTreeFromRouteObjects } from "./routeTree.mjs";
15
15
  import { getTanstackRscSerializationAdapters } from "./rsc/client.mjs";
@@ -118,50 +118,26 @@ function ModernRouterClient({ router }) {
118
118
  router: router
119
119
  });
120
120
  }
121
- function stripSyntheticNotFoundRoute(routes) {
122
- return routes.filter((route)=>!('*' === route.path && !route.id && !route.loader)).map((route)=>{
123
- if (!route.children?.length) return route;
124
- return {
125
- ...route,
126
- children: stripSyntheticNotFoundRoute(route.children)
127
- };
128
- });
129
- }
130
121
  const tanstackRouterPlugin = (userConfig = {})=>{
131
122
  const plugin = {
132
123
  name: '@modern-js/plugin-router-tanstack',
133
- registryHooks: {
134
- modifyRoutes: modifyRoutes,
135
- onAfterCreateRouter: onAfterCreateRouter,
136
- onAfterHydrateRouter: onAfterHydrateRouter,
137
- onBeforeCreateRouter: onBeforeCreateRouter,
138
- onBeforeCreateRoutes: onBeforeCreateRoutes,
139
- onBeforeHydrateRouter: onBeforeHydrateRouter
140
- },
124
+ registryHooks: routerProviderRegistryHooks,
141
125
  setup: (api)=>{
142
126
  const hooks = api.getHooks();
143
127
  let cachedRouteObjects;
144
128
  let cachedRouteTree = null;
145
129
  let cachedRouter = null;
146
130
  let cachedRouterBasepath = null;
147
- const getMergedConfig = ()=>{
148
- const pluginConfig = api.getRuntimeConfig();
149
- return merge(pluginConfig.router || {}, userConfig);
150
- };
131
+ const getMergedConfig = ()=>getMergedRouterConfig(api, userConfig);
151
132
  const getRouteObjects = ()=>{
152
133
  if (void 0 !== cachedRouteObjects) return cachedRouteObjects;
153
134
  const mergedConfig = getMergedConfig();
154
- const { routesConfig, createRoutes } = mergedConfig;
155
- const finalRouteConfig = {
156
- routes: getGlobalRoutes(),
157
- globalApp: getGlobalLayoutApp(),
158
- ...routesConfig
159
- };
135
+ const { createRoutes } = mergedConfig;
136
+ const finalRouteConfig = getFinalRouteConfig(mergedConfig);
160
137
  const routeObjects = createRoutes ? createRoutes() : createRouteObjectsFromConfig({
161
138
  routesConfig: finalRouteConfig
162
139
  }) || [];
163
- const normalizedRouteObjects = createRoutes ? routeObjects : stripSyntheticNotFoundRoute(routeObjects);
164
- cachedRouteObjects = hooks.modifyRoutes.call(normalizedRouteObjects);
140
+ cachedRouteObjects = hooks.modifyRoutes.call(routeObjects);
165
141
  return cachedRouteObjects;
166
142
  };
167
143
  const getRouteTree = ()=>{
@@ -1,6 +1,5 @@
1
1
  import { jsx } from "react/jsx-runtime";
2
- import { InternalRuntimeContext, getGlobalEnableRsc, getGlobalLayoutApp, getGlobalRoutes } from "@modern-js/runtime/context";
3
- import { merge } from "@modern-js/runtime-utils/merge";
2
+ import { InternalRuntimeContext, getGlobalEnableRsc } from "@modern-js/runtime/context";
4
3
  import { createRequestContext, storage } from "@modern-js/runtime-utils/node";
5
4
  import { time } from "@modern-js/runtime-utils/time";
6
5
  import { LOADER_REPORTER_NAME } from "@modern-js/utils/universal/constants";
@@ -8,9 +7,10 @@ import { RouterProvider, createMemoryHistory, createRouter } from "@tanstack/rea
8
7
  import { attachRouterServerSsrUtils } from "@tanstack/router-core/ssr/server";
9
8
  import { useContext } from "react";
10
9
  import { createModernBasepathRewrite } from "./basepathRewrite.mjs";
11
- import { modifyRoutes, onAfterCreateRouter, onAfterHydrateRouter, onBeforeCreateRouter, onBeforeCreateRoutes, onBeforeHydrateRouter } from "./hooks.mjs";
10
+ import { routerProviderRegistryHooks } from "./hooks.mjs";
12
11
  import { wrapTanstackSsrHydrationBoundary } from "./hydrationBoundary.mjs";
13
- import { applyRouterServerPrepareResult, createRouterServerSnapshot } from "./lifecycle.mjs";
12
+ import { applyRouterServerPrepareResult, createRouterServerSnapshot, getRouterRuntimeState } from "./lifecycle.mjs";
13
+ import { getFinalRouteConfig, getMergedRouterConfig } from "./pluginCore.mjs";
14
14
  import { createRouteTreeFromRouteObjects, getModernRouteIdsFromMatches } from "./routeTree.mjs";
15
15
  import { createTanstackRscServerPayload, handleTanstackRscRedirect } from "./rsc/payloadRouter.mjs";
16
16
  import { getModernTanstackRouterFastDefaults } from "./types.mjs";
@@ -95,15 +95,6 @@ function createGetSsrHref(request) {
95
95
  const url = new URL(request.url);
96
96
  return `${url.pathname}${url.search}${url.hash}`;
97
97
  }
98
- function stripSyntheticNotFoundRoute(routes) {
99
- return routes.filter((route)=>!('*' === route.path && !route.id && !route.loader)).map((route)=>{
100
- if (!route.children?.length) return route;
101
- return {
102
- ...route,
103
- children: stripSyntheticNotFoundRoute(route.children)
104
- };
105
- });
106
- }
107
98
  function collectRouterErrors(tanstackRouter) {
108
99
  const state = tanstackRouter.state;
109
100
  const matches = Array.isArray(state.matches) ? state.matches : [];
@@ -118,26 +109,14 @@ function collectRouterErrors(tanstackRouter) {
118
109
  const tanstackRouterPlugin = (userConfig = {})=>{
119
110
  const plugin = {
120
111
  name: '@modern-js/plugin-router-tanstack',
121
- registryHooks: {
122
- modifyRoutes: modifyRoutes,
123
- onAfterCreateRouter: onAfterCreateRouter,
124
- onAfterHydrateRouter: onAfterHydrateRouter,
125
- onBeforeCreateRouter: onBeforeCreateRouter,
126
- onBeforeCreateRoutes: onBeforeCreateRoutes,
127
- onBeforeHydrateRouter: onBeforeHydrateRouter
128
- },
112
+ registryHooks: routerProviderRegistryHooks,
129
113
  setup: (api)=>{
130
114
  api.onBeforeRender(async (context, interrupt)=>{
131
- const pluginConfig = api.getRuntimeConfig();
132
- const mergedConfig = merge(pluginConfig.router || {}, userConfig);
115
+ const mergedConfig = getMergedRouterConfig(api, userConfig);
133
116
  const serializationAdapters = getGlobalEnableRsc() ? (await import("./rsc/server.mjs")).getTanstackRscSerializationAdapters() : void 0;
134
117
  const enableRsc = getGlobalEnableRsc();
135
- const { basename = '', routesConfig, createRoutes } = mergedConfig;
136
- const finalRouteConfig = {
137
- routes: getGlobalRoutes(),
138
- globalApp: getGlobalLayoutApp(),
139
- ...routesConfig
140
- };
118
+ const { basename = '', createRoutes } = mergedConfig;
119
+ const finalRouteConfig = getFinalRouteConfig(mergedConfig);
141
120
  if (!finalRouteConfig.routes && !createRoutes) return;
142
121
  const hooks = api.getHooks();
143
122
  await hooks.onBeforeCreateRoutes.call(context);
@@ -145,8 +124,7 @@ const tanstackRouterPlugin = (userConfig = {})=>{
145
124
  routesConfig: finalRouteConfig,
146
125
  ssrMode: context.ssrContext?.mode
147
126
  }) || [];
148
- const normalizedRouteObjects = createRoutes ? routeObjects : stripSyntheticNotFoundRoute(routeObjects);
149
- const modifiedRouteObjects = hooks.modifyRoutes.call(normalizedRouteObjects);
127
+ const modifiedRouteObjects = hooks.modifyRoutes.call(routeObjects);
150
128
  if (!modifiedRouteObjects.length) return;
151
129
  const { request, nonce, baseUrl, loaderFailureMode = 'errorBoundary' } = context.ssrContext;
152
130
  const _basename = '/' === baseUrl ? urlJoin(baseUrl, basename || '') : baseUrl;
@@ -264,7 +242,7 @@ const tanstackRouterPlugin = (userConfig = {})=>{
264
242
  api.wrapRoot((App)=>{
265
243
  const getRouteApp = ()=>(props)=>{
266
244
  const context = useContext(InternalRuntimeContext);
267
- const router = context.routerInstance ?? context.routerRuntime?.instance;
245
+ const router = getRouterRuntimeState(context)?.instance;
268
246
  if (!router) return App ? /*#__PURE__*/ jsx(App, {
269
247
  ...props
270
248
  }) : null;