@bleedingdev/modern-js-plugin-tanstack 3.5.0-ultramodern.9 → 3.5.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.
Files changed (270) hide show
  1. package/dist/cjs/cli/artifacts.js +157 -0
  2. package/dist/cjs/cli/index.js +8 -79
  3. package/dist/cjs/cli/tanstackTypes/canonicalRoutes.js +113 -0
  4. package/dist/cjs/cli/tanstackTypes/shared.js +123 -0
  5. package/dist/cjs/cli/tanstackTypes/source.js +255 -0
  6. package/dist/cjs/cli/tanstackTypes.js +4 -350
  7. package/dist/cjs/runtime/blockingSubscribe.js +57 -0
  8. package/dist/cjs/runtime/{pluginCore.js → clientBasepath.js} +12 -19
  9. package/dist/cjs/runtime/clientHydration.js +118 -0
  10. package/dist/cjs/runtime/dataMutation.js +11 -176
  11. package/dist/cjs/runtime/formData.js +116 -0
  12. package/dist/cjs/runtime/loaderBridge.js +7 -11
  13. package/dist/cjs/runtime/plugin.js +21 -125
  14. package/dist/cjs/runtime/plugin.node.js +45 -125
  15. package/dist/cjs/runtime/pluginShared.js +87 -0
  16. package/dist/cjs/runtime/prefetchLink.js +15 -2
  17. package/dist/cjs/runtime/register.js +3 -16
  18. package/dist/cjs/runtime/routeTree/components.js +102 -0
  19. package/dist/cjs/runtime/routeTree/construction.js +152 -0
  20. package/dist/cjs/runtime/routeTree/index.js +47 -0
  21. package/dist/cjs/runtime/routeTree/loaders.js +158 -0
  22. package/dist/cjs/runtime/routeTree/paths.js +57 -0
  23. package/dist/cjs/runtime/routeTree/staticData.js +63 -0
  24. package/dist/cjs/runtime/routeTree/tanstackRoutes.js +57 -0
  25. package/dist/cjs/runtime/routeTree/types.js +18 -0
  26. package/dist/cjs/runtime/routeTree.js +7 -320
  27. package/dist/cjs/runtime/router.js +15 -2
  28. package/dist/cjs/runtime/rsc/CompositeComponent.js +18 -13
  29. package/dist/cjs/runtime/rsc/ReplayableStream.js +0 -4
  30. package/dist/cjs/runtime/rsc/RscNodeRenderer.js +5 -16
  31. package/dist/cjs/runtime/rsc/client.js +8 -25
  32. package/dist/cjs/runtime/rsc/flightSerialization.js +132 -0
  33. package/dist/cjs/runtime/rsc/payloadErrors.js +99 -0
  34. package/dist/cjs/runtime/rsc/payloadFetch.js +105 -0
  35. package/dist/cjs/runtime/rsc/payloadRouter.js +21 -142
  36. package/dist/cjs/runtime/rsc/payloadRoutes.js +94 -0
  37. package/dist/cjs/runtime/rsc/payloadStorage.js +58 -0
  38. package/dist/cjs/runtime/rsc/server.js +14 -18
  39. package/dist/cjs/runtime/rsc/shared.js +68 -0
  40. package/dist/cjs/runtime/rsc/slotUsageSanitizer.js +1 -0
  41. package/dist/cjs/runtime/rsc/treeGetter.js +72 -0
  42. package/dist/cjs/runtime/shared/isAbsoluteUrl.js +47 -0
  43. package/dist/cjs/runtime/ssrManagedTags.js +103 -0
  44. package/dist/cjs/runtime/ssrPreload.js +89 -0
  45. package/dist/cjs/runtime/ssrTypes.js +18 -0
  46. package/dist/cjs/runtime/state.js +1 -1
  47. package/dist/cjs/runtime/submitAction.js +161 -0
  48. package/dist/cjs/runtime/utils.js +49 -86
  49. package/dist/esm/cli/artifacts.mjs +103 -0
  50. package/dist/esm/cli/index.mjs +8 -82
  51. package/dist/esm/cli/tanstackTypes/canonicalRoutes.mjs +75 -0
  52. package/dist/esm/cli/tanstackTypes/shared.mjs +61 -0
  53. package/dist/esm/cli/tanstackTypes/source.mjs +207 -0
  54. package/dist/esm/cli/tanstackTypes.mjs +2 -339
  55. package/dist/esm/runtime/blockingSubscribe.mjs +19 -0
  56. package/dist/esm/runtime/clientBasepath.mjs +10 -0
  57. package/dist/esm/runtime/clientHydration.mjs +71 -0
  58. package/dist/esm/runtime/dataMutation.mjs +2 -167
  59. package/dist/esm/runtime/formData.mjs +63 -0
  60. package/dist/esm/runtime/loaderBridge.mjs +5 -9
  61. package/dist/esm/runtime/plugin.mjs +14 -118
  62. package/dist/esm/runtime/plugin.node.mjs +41 -121
  63. package/dist/esm/runtime/pluginShared.mjs +40 -0
  64. package/dist/esm/runtime/prefetchLink.mjs +18 -5
  65. package/dist/esm/runtime/register.mjs +1 -14
  66. package/dist/esm/runtime/routeTree/components.mjs +55 -0
  67. package/dist/esm/runtime/routeTree/construction.mjs +111 -0
  68. package/dist/esm/runtime/routeTree/index.mjs +2 -0
  69. package/dist/esm/runtime/routeTree/loaders.mjs +117 -0
  70. package/dist/esm/runtime/routeTree/paths.mjs +16 -0
  71. package/dist/esm/runtime/routeTree/staticData.mjs +22 -0
  72. package/dist/esm/runtime/routeTree/tanstackRoutes.mjs +13 -0
  73. package/dist/esm/runtime/routeTree/types.mjs +0 -0
  74. package/dist/esm/runtime/routeTree.mjs +1 -318
  75. package/dist/esm/runtime/router.mjs +16 -2
  76. package/dist/esm/runtime/rsc/CompositeComponent.mjs +18 -13
  77. package/dist/esm/runtime/rsc/ReplayableStream.mjs +1 -1
  78. package/dist/esm/runtime/rsc/RscNodeRenderer.mjs +4 -15
  79. package/dist/esm/runtime/rsc/client.mjs +6 -26
  80. package/dist/esm/runtime/rsc/flightSerialization.mjs +88 -0
  81. package/dist/esm/runtime/rsc/payloadErrors.mjs +49 -0
  82. package/dist/esm/runtime/rsc/payloadFetch.mjs +55 -0
  83. package/dist/esm/runtime/rsc/payloadRouter.mjs +12 -133
  84. package/dist/esm/runtime/rsc/payloadRoutes.mjs +50 -0
  85. package/dist/esm/runtime/rsc/payloadStorage.mjs +14 -0
  86. package/dist/esm/runtime/rsc/server.mjs +17 -21
  87. package/dist/esm/runtime/rsc/shared.mjs +21 -0
  88. package/dist/esm/runtime/rsc/slotUsageSanitizer.mjs +1 -0
  89. package/dist/esm/runtime/rsc/treeGetter.mjs +34 -0
  90. package/dist/esm/runtime/shared/isAbsoluteUrl.mjs +9 -0
  91. package/dist/esm/runtime/ssrManagedTags.mjs +53 -0
  92. package/dist/esm/runtime/ssrPreload.mjs +51 -0
  93. package/dist/esm/runtime/ssrTypes.mjs +0 -0
  94. package/dist/esm/runtime/state.mjs +1 -1
  95. package/dist/esm/runtime/submitAction.mjs +120 -0
  96. package/dist/esm/runtime/utils.mjs +47 -75
  97. package/dist/esm-node/cli/artifacts.mjs +104 -0
  98. package/dist/esm-node/cli/index.mjs +8 -82
  99. package/dist/esm-node/cli/tanstackTypes/canonicalRoutes.mjs +76 -0
  100. package/dist/esm-node/cli/tanstackTypes/shared.mjs +62 -0
  101. package/dist/esm-node/cli/tanstackTypes/source.mjs +208 -0
  102. package/dist/esm-node/cli/tanstackTypes.mjs +2 -339
  103. package/dist/esm-node/runtime/blockingSubscribe.mjs +20 -0
  104. package/dist/esm-node/runtime/clientBasepath.mjs +11 -0
  105. package/dist/esm-node/runtime/clientHydration.mjs +72 -0
  106. package/dist/esm-node/runtime/dataMutation.mjs +2 -167
  107. package/dist/esm-node/runtime/formData.mjs +64 -0
  108. package/dist/esm-node/runtime/loaderBridge.mjs +5 -9
  109. package/dist/esm-node/runtime/plugin.mjs +14 -118
  110. package/dist/esm-node/runtime/plugin.node.mjs +41 -121
  111. package/dist/esm-node/runtime/pluginShared.mjs +41 -0
  112. package/dist/esm-node/runtime/prefetchLink.mjs +18 -5
  113. package/dist/esm-node/runtime/register.mjs +1 -14
  114. package/dist/esm-node/runtime/routeTree/components.mjs +56 -0
  115. package/dist/esm-node/runtime/routeTree/construction.mjs +112 -0
  116. package/dist/esm-node/runtime/routeTree/index.mjs +3 -0
  117. package/dist/esm-node/runtime/routeTree/loaders.mjs +118 -0
  118. package/dist/esm-node/runtime/routeTree/paths.mjs +17 -0
  119. package/dist/esm-node/runtime/routeTree/staticData.mjs +23 -0
  120. package/dist/esm-node/runtime/routeTree/tanstackRoutes.mjs +14 -0
  121. package/dist/esm-node/runtime/routeTree/types.mjs +1 -0
  122. package/dist/esm-node/runtime/routeTree.mjs +1 -318
  123. package/dist/esm-node/runtime/router.mjs +16 -2
  124. package/dist/esm-node/runtime/rsc/CompositeComponent.mjs +18 -13
  125. package/dist/esm-node/runtime/rsc/ReplayableStream.mjs +1 -1
  126. package/dist/esm-node/runtime/rsc/RscNodeRenderer.mjs +4 -15
  127. package/dist/esm-node/runtime/rsc/client.mjs +6 -26
  128. package/dist/esm-node/runtime/rsc/flightSerialization.mjs +89 -0
  129. package/dist/esm-node/runtime/rsc/payloadErrors.mjs +50 -0
  130. package/dist/esm-node/runtime/rsc/payloadFetch.mjs +56 -0
  131. package/dist/esm-node/runtime/rsc/payloadRouter.mjs +12 -133
  132. package/dist/esm-node/runtime/rsc/payloadRoutes.mjs +51 -0
  133. package/dist/esm-node/runtime/rsc/payloadStorage.mjs +15 -0
  134. package/dist/esm-node/runtime/rsc/server.mjs +17 -21
  135. package/dist/esm-node/runtime/rsc/shared.mjs +22 -0
  136. package/dist/esm-node/runtime/rsc/slotUsageSanitizer.mjs +1 -0
  137. package/dist/esm-node/runtime/rsc/treeGetter.mjs +35 -0
  138. package/dist/esm-node/runtime/shared/isAbsoluteUrl.mjs +10 -0
  139. package/dist/esm-node/runtime/ssrManagedTags.mjs +54 -0
  140. package/dist/esm-node/runtime/ssrPreload.mjs +52 -0
  141. package/dist/esm-node/runtime/ssrTypes.mjs +1 -0
  142. package/dist/esm-node/runtime/state.mjs +1 -1
  143. package/dist/esm-node/runtime/submitAction.mjs +121 -0
  144. package/dist/esm-node/runtime/utils.mjs +47 -75
  145. package/dist/types/cli/artifacts.d.ts +33 -0
  146. package/dist/types/cli/index.d.ts +2 -22
  147. package/dist/types/cli/tanstackTypes/canonicalRoutes.d.ts +22 -0
  148. package/dist/types/cli/tanstackTypes/shared.d.ts +20 -0
  149. package/dist/types/cli/tanstackTypes/source.d.ts +12 -0
  150. package/dist/types/cli/tanstackTypes.d.ts +3 -31
  151. package/dist/types/runtime/blockingSubscribe.d.ts +1 -0
  152. package/dist/types/runtime/clientBasepath.d.ts +1 -0
  153. package/dist/types/runtime/clientHydration.d.ts +10 -0
  154. package/dist/types/runtime/dataMutation.d.ts +3 -12
  155. package/dist/types/runtime/formData.d.ts +24 -0
  156. package/dist/types/runtime/loaderBridge.d.ts +2 -1
  157. package/dist/types/runtime/plugin.d.ts +1 -1
  158. package/dist/types/runtime/plugin.node.d.ts +1 -1
  159. package/dist/types/runtime/pluginShared.d.ts +38 -0
  160. package/dist/types/runtime/register.d.ts +10 -9
  161. package/dist/types/runtime/routeTree/components.d.ts +7 -0
  162. package/dist/types/runtime/routeTree/construction.d.ts +5 -0
  163. package/dist/types/runtime/routeTree/index.d.ts +2 -0
  164. package/dist/types/runtime/routeTree/loaders.d.ts +4 -0
  165. package/dist/types/runtime/routeTree/paths.d.ts +3 -0
  166. package/dist/types/runtime/routeTree/staticData.d.ts +19 -0
  167. package/dist/types/runtime/routeTree/tanstackRoutes.d.ts +4 -0
  168. package/dist/types/runtime/routeTree/types.d.ts +76 -0
  169. package/dist/types/runtime/routeTree.d.ts +1 -9
  170. package/dist/types/runtime/router.d.ts +6 -7
  171. package/dist/types/runtime/rsc/CompositeComponent.d.ts +1 -2
  172. package/dist/types/runtime/rsc/ReplayableStream.d.ts +3 -2
  173. package/dist/types/runtime/rsc/RscNodeRenderer.d.ts +2 -3
  174. package/dist/types/runtime/rsc/SlotContext.d.ts +2 -1
  175. package/dist/types/runtime/rsc/client.d.ts +2 -0
  176. package/dist/types/runtime/rsc/flightSerialization.d.ts +3 -0
  177. package/dist/types/runtime/rsc/payloadErrors.d.ts +6 -0
  178. package/dist/types/runtime/rsc/payloadFetch.d.ts +8 -0
  179. package/dist/types/runtime/rsc/payloadRouter.d.ts +2 -10
  180. package/dist/types/runtime/rsc/payloadRoutes.d.ts +40 -0
  181. package/dist/types/runtime/rsc/payloadStorage.d.ts +5 -0
  182. package/dist/types/runtime/rsc/shared.d.ts +18 -0
  183. package/dist/types/runtime/rsc/treeGetter.d.ts +1 -0
  184. package/dist/types/runtime/shared/isAbsoluteUrl.d.ts +1 -0
  185. package/dist/types/runtime/ssrManagedTags.d.ts +7 -0
  186. package/dist/types/runtime/ssrPreload.d.ts +2 -0
  187. package/dist/types/runtime/ssrTypes.d.ts +44 -0
  188. package/dist/types/runtime/state.d.ts +1 -1
  189. package/dist/types/runtime/submitAction.d.ts +14 -0
  190. package/dist/types/runtime/types.d.ts +4 -10
  191. package/dist/types/runtime/utils.d.ts +4 -24
  192. package/package.json +37 -17
  193. package/rstest.config.mts +23 -0
  194. package/src/cli/artifacts.ts +255 -0
  195. package/src/cli/index.ts +7 -185
  196. package/src/cli/tanstackTypes/canonicalRoutes.ts +157 -0
  197. package/src/cli/tanstackTypes/shared.ts +113 -0
  198. package/src/cli/tanstackTypes/source.ts +414 -0
  199. package/src/cli/tanstackTypes.ts +4 -647
  200. package/src/runtime/blockingSubscribe.ts +48 -0
  201. package/src/runtime/clientBasepath.ts +12 -0
  202. package/src/runtime/clientHydration.ts +149 -0
  203. package/src/runtime/dataMutation.tsx +9 -306
  204. package/src/runtime/formData.ts +153 -0
  205. package/src/runtime/loaderBridge.ts +11 -12
  206. package/src/runtime/plugin.node.tsx +76 -291
  207. package/src/runtime/plugin.tsx +21 -257
  208. package/src/runtime/pluginShared.ts +112 -0
  209. package/src/runtime/prefetchLink.tsx +78 -15
  210. package/src/runtime/register.ts +10 -42
  211. package/src/runtime/routeTree/components.ts +130 -0
  212. package/src/runtime/routeTree/construction.ts +238 -0
  213. package/src/runtime/routeTree/index.ts +7 -0
  214. package/src/runtime/routeTree/loaders.ts +232 -0
  215. package/src/runtime/routeTree/paths.ts +36 -0
  216. package/src/runtime/routeTree/staticData.ts +66 -0
  217. package/src/runtime/routeTree/tanstackRoutes.ts +36 -0
  218. package/src/runtime/routeTree/types.ts +87 -0
  219. package/src/runtime/routeTree.ts +5 -750
  220. package/src/runtime/router.ts +35 -7
  221. package/src/runtime/rsc/CompositeComponent.tsx +29 -20
  222. package/src/runtime/rsc/ReplayableStream.ts +2 -2
  223. package/src/runtime/rsc/RscNodeRenderer.tsx +9 -27
  224. package/src/runtime/rsc/SlotContext.tsx +1 -1
  225. package/src/runtime/rsc/client.tsx +12 -40
  226. package/src/runtime/rsc/flightSerialization.ts +158 -0
  227. package/src/runtime/rsc/payloadErrors.ts +73 -0
  228. package/src/runtime/rsc/payloadFetch.ts +92 -0
  229. package/src/runtime/rsc/payloadRouter.ts +29 -234
  230. package/src/runtime/rsc/payloadRoutes.ts +122 -0
  231. package/src/runtime/rsc/payloadStorage.ts +35 -0
  232. package/src/runtime/rsc/server.tsx +20 -29
  233. package/src/runtime/rsc/shared.ts +70 -0
  234. package/src/runtime/rsc/slotUsageSanitizer.ts +4 -0
  235. package/src/runtime/rsc/treeGetter.tsx +52 -0
  236. package/src/runtime/shared/isAbsoluteUrl.ts +8 -0
  237. package/src/runtime/ssrManagedTags.ts +107 -0
  238. package/src/runtime/ssrPreload.ts +125 -0
  239. package/src/runtime/ssrTypes.ts +51 -0
  240. package/src/runtime/state.ts +9 -3
  241. package/src/runtime/submitAction.ts +201 -0
  242. package/src/runtime/types.ts +4 -18
  243. package/src/runtime/utils.tsx +76 -110
  244. package/src/types/react-server-dom-rspack.d.ts +56 -0
  245. package/tests/castRatchet.test.ts +85 -0
  246. package/tests/realm-isolation.test.ts +114 -0
  247. package/tests/router/cli.test.ts +7 -0
  248. package/tests/router/clientHydration.test.tsx +61 -0
  249. package/tests/router/dataMutation.test.tsx +59 -0
  250. package/tests/router/fixtures/legacyRuntimeRouter.ts +10 -0
  251. package/tests/router/fixtures/router-gen.golden.txt +71 -0
  252. package/tests/router/fixtures/router-gen.oxlint.json +5 -0
  253. package/tests/router/flightSerialization.roundtrip.test.tsx +137 -0
  254. package/tests/router/generateRouteArtifacts.test.ts +106 -0
  255. package/tests/router/hooks.test.ts +14 -0
  256. package/tests/router/loaderBridge.test.ts +21 -0
  257. package/tests/router/prefetchLink.test.tsx +106 -59
  258. package/tests/router/prefetchLinkPreload.test.tsx +85 -0
  259. package/tests/router/register.test.ts +1 -39
  260. package/tests/router/routeTree.test.ts +51 -11
  261. package/tests/router/routerCompatibility.test.ts +245 -0
  262. package/tests/router/rsc.test.tsx +189 -0
  263. package/tests/router/rscPayloadRouterMatrix.test.ts +197 -0
  264. package/tests/router/slotUsageSanitizer.test.ts +23 -0
  265. package/tests/router/ssrPreload.test.ts +30 -0
  266. package/tests/router/tanstackTypes.test.ts +298 -1
  267. package/dist/esm/runtime/pluginCore.mjs +0 -14
  268. package/dist/esm-node/runtime/pluginCore.mjs +0 -15
  269. package/dist/types/runtime/pluginCore.d.ts +0 -21
  270. package/src/runtime/pluginCore.ts +0 -48
@@ -20,19 +20,28 @@ import {
20
20
  } from '@tanstack/react-router';
21
21
  import { useContext, useMemo } from 'react';
22
22
  import { createModernBasepathRewrite } from './basepathRewrite';
23
+ import { wrapRouterSubscribeWithBlockState } from './blockingSubscribe';
24
+ import { isSegmentPrefix } from './clientBasepath';
25
+ import {
26
+ getTanstackSsrHydrationPromise,
27
+ hasTanstackSsrHydrationRecord,
28
+ ModernRouterClient,
29
+ type WindowWithTanstackSsr,
30
+ } from './clientHydration';
23
31
  import { routerProviderRegistryHooks } from './hooks';
24
32
  import { wrapTanstackSsrHydrationBoundary } from './hydrationBoundary';
25
33
  import {
26
34
  applyRouterRuntimeState,
27
35
  type RouterLifecycleContext,
28
36
  } from './lifecycle';
29
- import { withModernRouteMatchContext } from './outlet';
30
37
  import {
31
- getFinalRouteConfig,
38
+ createTanstackRouteObjects,
32
39
  getMergedRouterConfig,
40
+ getTanstackRouteConfig,
41
+ joinBasename,
33
42
  type TanstackRouterPluginAPI,
34
43
  type TanstackRouterRuntimePlugin,
35
- } from './pluginCore';
44
+ } from './pluginShared';
36
45
  import { Link } from './prefetchLink';
37
46
  import { useMatches } from './routeHooks';
38
47
  import { createRouteTreeFromRouteObjects } from './routeTree';
@@ -41,245 +50,6 @@ import {
41
50
  getModernTanstackRouterFastDefaults,
42
51
  type RouterConfig,
43
52
  } from './types';
44
- import { createRouteObjectsFromConfig, urlJoin } from './utils';
45
-
46
- const BLOCKING_SUBSCRIBE_SYMBOL = Symbol.for(
47
- '@modern-js/plugin-tanstack:blocking-subscribe',
48
- );
49
- const BLOCKING_STATE_SYMBOL = Symbol.for(
50
- '@modern-js/plugin-tanstack:blocking-state',
51
- );
52
- type TanstackRouterWithSubscribe = {
53
- [BLOCKING_STATE_SYMBOL]?: () => boolean;
54
- [BLOCKING_SUBSCRIBE_SYMBOL]?: boolean;
55
- subscribe?: (
56
- eventType: string,
57
- listener: (...args: unknown[]) => void,
58
- ) => () => void;
59
- };
60
-
61
- type WindowWithTanstackSsr = Window & {
62
- $_TSR?: unknown;
63
- };
64
-
65
- type RouteComponentPreloadable = {
66
- load?: () => Promise<unknown>;
67
- preload?: () => Promise<unknown>;
68
- };
69
-
70
- type ModernRouteModule = {
71
- Component?: unknown;
72
- default?: unknown;
73
- };
74
-
75
- type RouterWithPreloadableRoutes = AnyRouter & {
76
- routesById?: Record<
77
- string,
78
- {
79
- options?: {
80
- component?: unknown;
81
- staticData?: {
82
- modernRouteId?: string;
83
- };
84
- };
85
- }
86
- >;
87
- };
88
-
89
- function normalizeBase(b: string) {
90
- if (b.length > 1 && b.endsWith('/')) {
91
- return b.slice(0, -1);
92
- }
93
- return b || '/';
94
- }
95
-
96
- function isSegmentPrefix(pathname: string, base: string) {
97
- const b = normalizeBase(base);
98
- const p = pathname || '/';
99
- return p === b || p.startsWith(`${b}/`);
100
- }
101
-
102
- function wrapRouterSubscribeWithBlockState(
103
- router: unknown,
104
- getBlockNavState?: () => boolean,
105
- ) {
106
- if (!router || typeof router !== 'object') {
107
- return;
108
- }
109
-
110
- const target = router as TanstackRouterWithSubscribe;
111
- target[BLOCKING_STATE_SYMBOL] = getBlockNavState;
112
- if (
113
- target[BLOCKING_SUBSCRIBE_SYMBOL] ||
114
- typeof target.subscribe !== 'function'
115
- ) {
116
- return;
117
- }
118
-
119
- const originSubscribe = target.subscribe.bind(target);
120
- target.subscribe = (eventType, listener) => {
121
- const wrappedListener = (...args: unknown[]) => {
122
- const blockRoute = target[BLOCKING_STATE_SYMBOL]?.() || false;
123
- if (blockRoute) {
124
- return;
125
- }
126
- return listener(...args);
127
- };
128
- return originSubscribe(eventType, wrappedListener);
129
- };
130
- target[BLOCKING_SUBSCRIBE_SYMBOL] = true;
131
- }
132
-
133
- type RouterHydrationRecord = {
134
- error?: unknown;
135
- promise: Promise<unknown>;
136
- status: 'pending' | 'fulfilled' | 'rejected';
137
- };
138
-
139
- const routerHydrationRecords = new WeakMap<AnyRouter, RouterHydrationRecord>();
140
- const routeModulesKey = '_routeModules';
141
-
142
- function pickRouteModuleComponent(
143
- routeModule: unknown,
144
- seen: Set<unknown> = new Set(),
145
- ): unknown {
146
- if (
147
- typeof routeModule === 'function' ||
148
- (routeModule &&
149
- typeof routeModule === 'object' &&
150
- '$$typeof' in routeModule)
151
- ) {
152
- return routeModule;
153
- }
154
-
155
- if (!routeModule || typeof routeModule !== 'object') {
156
- return undefined;
157
- }
158
- if (seen.has(routeModule)) {
159
- return undefined;
160
- }
161
- seen.add(routeModule);
162
-
163
- const module = routeModule as ModernRouteModule;
164
- for (const candidate of [module.default, module.Component]) {
165
- const component = pickRouteModuleComponent(candidate, seen);
166
- if (component) {
167
- return component;
168
- }
169
- }
170
-
171
- return undefined;
172
- }
173
-
174
- function getCachedRouteModule(routeId: string) {
175
- if (typeof window === 'undefined') {
176
- return undefined;
177
- }
178
-
179
- return (window as unknown as Record<string, Record<string, unknown>>)[
180
- routeModulesKey
181
- ]?.[routeId];
182
- }
183
-
184
- function preloadHydratedRouteComponents(router: AnyRouter): Promise<void> {
185
- const preloadableRouter = router as RouterWithPreloadableRoutes;
186
- const routesById = preloadableRouter.routesById || {};
187
- const matches = preloadableRouter.stores.matches.get() as Array<{
188
- routeId?: string;
189
- }>;
190
-
191
- return Promise.all(
192
- matches.map(match => {
193
- if (match.routeId === undefined || match.routeId === '') {
194
- return undefined;
195
- }
196
-
197
- const route = routesById[match.routeId];
198
- const component = route?.options?.component as RouteComponentPreloadable;
199
- const preload = component?.load || component?.preload;
200
- if (typeof preload !== 'function') {
201
- return undefined;
202
- }
203
-
204
- return Promise.resolve(preload.call(component)).then(routeModule => {
205
- const modernRouteId = route?.options?.staticData?.modernRouteId;
206
- const cachedRouteModule =
207
- typeof modernRouteId === 'string' && modernRouteId !== ''
208
- ? getCachedRouteModule(modernRouteId)
209
- : undefined;
210
- const resolvedComponent = pickRouteModuleComponent(
211
- cachedRouteModule ?? routeModule,
212
- );
213
- if (
214
- resolvedComponent !== undefined &&
215
- typeof modernRouteId === 'string' &&
216
- modernRouteId !== ''
217
- ) {
218
- route.options.component = withModernRouteMatchContext(
219
- resolvedComponent,
220
- modernRouteId,
221
- );
222
- }
223
- });
224
- }),
225
- ).then(() => undefined);
226
- }
227
-
228
- function hydrateTanstackRouter(router: AnyRouter) {
229
- return import('@tanstack/react-router/ssr/client').then(({ hydrate }) =>
230
- hydrate(router),
231
- );
232
- }
233
-
234
- function getTanstackSsrHydrationRecord(router: AnyRouter) {
235
- const existingHydrationRecord = routerHydrationRecords.get(router);
236
- if (existingHydrationRecord !== undefined) {
237
- return existingHydrationRecord;
238
- }
239
-
240
- const hydrationRecord: RouterHydrationRecord = {
241
- promise: Promise.resolve(),
242
- status: 'pending',
243
- };
244
- routerHydrationRecords.set(router, hydrationRecord);
245
- try {
246
- hydrationRecord.promise = hydrateTanstackRouter(router)
247
- .then(value => preloadHydratedRouteComponents(router).then(() => value))
248
- .then(
249
- value => {
250
- hydrationRecord.status = 'fulfilled';
251
- return value;
252
- },
253
- error => {
254
- hydrationRecord.status = 'rejected';
255
- hydrationRecord.error = error;
256
- throw error;
257
- },
258
- );
259
- } catch (error) {
260
- hydrationRecord.status = 'rejected';
261
- hydrationRecord.error = error;
262
- hydrationRecord.promise = Promise.reject(error);
263
- hydrationRecord.promise.catch(() => {});
264
- }
265
- return hydrationRecord;
266
- }
267
-
268
- function getTanstackSsrHydrationPromise(router: AnyRouter) {
269
- return getTanstackSsrHydrationRecord(router).promise;
270
- }
271
-
272
- function hasTanstackSsrHydrationRecord(router: AnyRouter) {
273
- return routerHydrationRecords.has(router);
274
- }
275
-
276
- function ModernRouterClient({ router }: { router: AnyRouter }) {
277
- const hydrationRecord = getTanstackSsrHydrationRecord(router);
278
- if (hydrationRecord.status === 'rejected') {
279
- throw hydrationRecord.error;
280
- }
281
- return <RouterProvider router={router} />;
282
- }
283
53
 
284
54
  export const tanstackRouterPlugin = (
285
55
  userConfig: Partial<RouterConfig> = {},
@@ -303,19 +73,10 @@ export const tanstackRouterPlugin = (
303
73
  return cachedRouteObjects;
304
74
  }
305
75
 
306
- const mergedConfig = getMergedConfig();
307
- const { createRoutes } = mergedConfig;
308
- const finalRouteConfig = getFinalRouteConfig(mergedConfig);
309
-
310
- const routeObjects = createRoutes
311
- ? createRoutes()
312
- : createRouteObjectsFromConfig({
313
- routesConfig: finalRouteConfig,
314
- }) || [];
315
-
316
- cachedRouteObjects = hooks.modifyRoutes.call(
317
- routeObjects,
318
- ) as RouteObject[];
76
+ cachedRouteObjects = createTanstackRouteObjects({
77
+ hooks,
78
+ routeConfig: getTanstackRouteConfig(api, userConfig),
79
+ });
319
80
  return cachedRouteObjects;
320
81
  };
321
82
 
@@ -347,7 +108,7 @@ export const tanstackRouterPlugin = (
347
108
  const { basename = '' } = getMergedConfig();
348
109
  const baseUrl = selectBasePath(location.pathname).replace(/^\/*/, '/');
349
110
  return baseUrl === '/'
350
- ? urlJoin(
111
+ ? joinBasename(
351
112
  baseUrl,
352
113
  runtimeContext._internalRouterBaseName || basename || '',
353
114
  )
@@ -394,9 +155,12 @@ export const tanstackRouterPlugin = (
394
155
  const serializationAdapters = getGlobalEnableRsc()
395
156
  ? getTanstackRscSerializationAdapters()
396
157
  : undefined;
158
+ const routerFastDefaults =
159
+ getModernTanstackRouterFastDefaults(mergedConfig);
397
160
 
398
161
  cachedRouter = createRouter({
399
- ...getModernTanstackRouterFastDefaults(mergedConfig),
162
+ ...routerFastDefaults,
163
+ ...(serializationAdapters ? { defaultStructuralSharing: false } : {}),
400
164
  routeTree,
401
165
  basepath: '/',
402
166
  rewrite,
@@ -0,0 +1,112 @@
1
+ import {
2
+ getGlobalLayoutApp,
3
+ getGlobalRoutes,
4
+ type TInternalRuntimeContext,
5
+ } from '@modern-js/runtime/context';
6
+ import { merge } from '@modern-js/runtime-utils/merge';
7
+ import type { RouteObject } from '@modern-js/runtime-utils/router';
8
+ import type { RouterExtendsHooks } from './hooks';
9
+ import type { RouterConfig } from './types';
10
+ import { createTanstackRouteObjectsFromConfig, type SSRMode } from './utils';
11
+
12
+ type TanstackRouterRuntimeConfig = {
13
+ plugins?: TanstackRouterRuntimePlugin[];
14
+ router?: Partial<RouterConfig>;
15
+ [key: string]: unknown;
16
+ };
17
+
18
+ type RuntimeInterrupt = (value?: unknown) => unknown;
19
+
20
+ export type TanstackRouterPluginAPI = {
21
+ getRuntimeConfig: () => TanstackRouterRuntimeConfig;
22
+ getHooks: () => RouterExtendsHooks;
23
+ onBeforeRender: (
24
+ listener: (
25
+ context: TInternalRuntimeContext,
26
+ interrupt: RuntimeInterrupt,
27
+ ) => unknown,
28
+ ) => void;
29
+ wrapRoot: (listener: (App: any) => any) => void;
30
+ [key: string]: any;
31
+ };
32
+
33
+ export type TanstackRouterRuntimePlugin = {
34
+ name?: string;
35
+ registryHooks?: RouterExtendsHooks;
36
+ setup?: (api: TanstackRouterPluginAPI) => unknown;
37
+ [key: string]: unknown;
38
+ };
39
+
40
+ type TanstackRouteConfig = {
41
+ mergedConfig: RouterConfig;
42
+ finalRouteConfig: RouterConfig['routesConfig'];
43
+ hasConfiguredRoutes: boolean;
44
+ };
45
+
46
+ export function getMergedRouterConfig(
47
+ api: TanstackRouterPluginAPI,
48
+ userConfig: Partial<RouterConfig>,
49
+ ): RouterConfig {
50
+ const pluginConfig = api.getRuntimeConfig() as {
51
+ router?: Partial<RouterConfig>;
52
+ };
53
+ return merge(pluginConfig.router || {}, userConfig) as RouterConfig;
54
+ }
55
+
56
+ function getFinalRouteConfig(
57
+ mergedConfig: RouterConfig,
58
+ ): RouterConfig['routesConfig'] {
59
+ return {
60
+ routes: getGlobalRoutes() as RouterConfig['routesConfig']['routes'],
61
+ globalApp: getGlobalLayoutApp(),
62
+ ...mergedConfig.routesConfig,
63
+ };
64
+ }
65
+
66
+ export function getTanstackRouteConfig(
67
+ api: TanstackRouterPluginAPI,
68
+ userConfig: Partial<RouterConfig>,
69
+ ): TanstackRouteConfig {
70
+ const mergedConfig = getMergedRouterConfig(api, userConfig);
71
+ const finalRouteConfig = getFinalRouteConfig(mergedConfig);
72
+ return {
73
+ mergedConfig,
74
+ finalRouteConfig,
75
+ hasConfiguredRoutes:
76
+ Boolean(finalRouteConfig.routes) || Boolean(mergedConfig.createRoutes),
77
+ };
78
+ }
79
+
80
+ export function createTanstackRouteObjects({
81
+ hooks,
82
+ routeConfig,
83
+ ssrMode,
84
+ }: {
85
+ hooks: RouterExtendsHooks;
86
+ routeConfig: TanstackRouteConfig;
87
+ ssrMode?: SSRMode;
88
+ }): RouteObject[] {
89
+ const { mergedConfig, finalRouteConfig } = routeConfig;
90
+ const routeObjects = mergedConfig.createRoutes
91
+ ? mergedConfig.createRoutes()
92
+ : createTanstackRouteObjectsFromConfig({
93
+ routesConfig: finalRouteConfig,
94
+ ssrMode,
95
+ }) || [];
96
+
97
+ return hooks.modifyRoutes.call(routeObjects) as RouteObject[];
98
+ }
99
+
100
+ export function joinBasename(baseUrl: string, basename: string): string {
101
+ const base = baseUrl || '/';
102
+ const normalizedBase = base.startsWith('/') ? base : `/${base}`;
103
+ const trimmedBase =
104
+ normalizedBase.length > 1
105
+ ? normalizedBase.replace(/\/+$/g, '')
106
+ : normalizedBase;
107
+ const trimmedBasename = basename.replace(/^\/+|\/+$/g, '');
108
+ if (!trimmedBasename) {
109
+ return trimmedBase || '/';
110
+ }
111
+ return `${trimmedBase}/${trimmedBasename}`.replace(/\/{2,}/g, '/');
112
+ }
@@ -2,9 +2,9 @@ import {
2
2
  type AnyRouter,
3
3
  type LinkComponentProps,
4
4
  type RegisteredRouter,
5
- Link as TanStackLink,
5
+ useLinkProps,
6
6
  } from '@tanstack/react-router';
7
- import type { ReactElement } from 'react';
7
+ import type { AnchorHTMLAttributes, ReactElement, ReactNode, Ref } from 'react';
8
8
 
9
9
  export type PrefetchBehavior = 'intent' | 'render' | 'viewport' | 'none';
10
10
 
@@ -65,21 +65,84 @@ type LinkComponentImplProps = LinkProps<
65
65
  string | undefined,
66
66
  string,
67
67
  string
68
- >;
68
+ > & { ref?: Ref<HTMLAnchorElement> };
69
69
 
70
70
  const LinkComponentImpl = (props: LinkComponentImplProps) => {
71
- const { prefetch, preload, ...rest } = props;
72
- return (
73
- <TanStackLink
74
- {...rest}
75
- preload={
76
- resolvePreloadFromPrefetch(
77
- prefetch,
78
- preload,
79
- ) as LinkComponentImplProps['preload']
80
- }
81
- />
82
- );
71
+ const {
72
+ prefetch,
73
+ preload,
74
+ 'aria-current': ariaCurrentProp,
75
+ ref,
76
+ children,
77
+ ...rest
78
+ } = props as LinkComponentImplProps & {
79
+ children?:
80
+ | ReactNode
81
+ | ((state: { isActive: boolean; isTransitioning: boolean }) => ReactNode);
82
+ };
83
+ const hasAriaCurrentOverride = 'aria-current' in props;
84
+
85
+ // Children are rendered by us, not by useLinkProps() — the hook filters
86
+ // unknown/function props out of its return value, so anything routed
87
+ // through it would be silently dropped.
88
+ const linkOptions = {
89
+ ...rest,
90
+ preload: resolvePreloadFromPrefetch(
91
+ prefetch,
92
+ preload,
93
+ ) as LinkComponentImplProps['preload'],
94
+ } as LinkComponentImplProps;
95
+
96
+ // TanStack Router's useLinkProps() unconditionally spreads
97
+ // STATIC_ACTIVE_PROPS = { "data-status": "active", "aria-current": "page" }
98
+ // as the LAST entry of the props object it returns for an active link
99
+ // (@tanstack/react-router dist/esm/link.js:369 `...isActive &&
100
+ // STATIC_ACTIVE_PROPS`, defined at line 379-382, spread after
101
+ // `...propsSafeToSpread`, `...resolvedActiveProps`, and
102
+ // `...resolvedInactiveProps`). That means any caller-supplied aria-current
103
+ // -- whether passed directly or via activeProps -- is always clobbered by
104
+ // the time <Link>/createLink render the anchor; there is no props-merge
105
+ // order that lets a caller win from inside <Link>. So instead of
106
+ // delegating rendering to <Link>, we call useLinkProps() ourselves and
107
+ // re-apply the caller's original aria-current (including `false`, meaning
108
+ // "suppress the attribute entirely") as the final word on the anchor we
109
+ // render.
110
+ const linkProps = useLinkProps(
111
+ linkOptions as Parameters<typeof useLinkProps>[0],
112
+ ref as Parameters<typeof useLinkProps>[1],
113
+ ) as AnchorHTMLAttributes<HTMLAnchorElement> & {
114
+ disabled?: boolean;
115
+ type?: string;
116
+ };
117
+
118
+ // TanStack's own Link strips `type` and `disabled` before rendering the
119
+ // anchor (link.js:449-452) — mirror that.
120
+ const { disabled: _disabled, type: _type, ...anchorProps } = linkProps;
121
+
122
+ if (hasAriaCurrentOverride) {
123
+ if (ariaCurrentProp === false || typeof ariaCurrentProp === 'undefined') {
124
+ delete anchorProps['aria-current'];
125
+ } else {
126
+ anchorProps['aria-current'] = ariaCurrentProp;
127
+ }
128
+ }
129
+
130
+ // TanStack's Link resolves render-prop children with the active state
131
+ // (link.js:450) — without this, function children reach React as an
132
+ // invalid child and crash the render.
133
+ const resolvedChildren =
134
+ typeof children === 'function'
135
+ ? children({
136
+ isActive:
137
+ (anchorProps as Record<string, unknown>)['data-status'] ===
138
+ 'active',
139
+ isTransitioning:
140
+ (anchorProps as Record<string, unknown>)['data-transitioning'] ===
141
+ 'transitioning',
142
+ })
143
+ : children;
144
+
145
+ return <a {...anchorProps}>{resolvedChildren}</a>;
83
146
  };
84
147
 
85
148
  export const Link = LinkComponentImpl as LinkComponent;
@@ -1,8 +1,7 @@
1
1
  /**
2
- * Registers the TanStack router provider with the @modern-js/runtime router
3
- * provider registry. Importing '@modern-js/plugin-tanstack/runtime' is enough
4
- * to make `runtime.router.framework: 'tanstack'` resolvable by the built-in
5
- * router runtime plugin.
2
+ * Registers TanStack in the @modern-js/runtime compatibility registry.
3
+ * Runtime entries bind the exported local factory into their own provider
4
+ * realm; registration remains for older runtime wrappers and mixed cohorts.
6
5
  *
7
6
  * This module is intentionally side-effectful (see `sideEffects` in
8
7
  * package.json).
@@ -12,47 +11,16 @@ import {
12
11
  type RouterProviderPlugin,
13
12
  registerRouterProvider,
14
13
  } from '@modern-js/runtime/context';
15
- import { Form, RouteActionResponseError, useFetcher } from './dataMutation';
16
- import { Outlet } from './outlet';
17
14
  import { tanstackRouterPlugin } from './plugin';
18
- import { Link, NavLink } from './prefetchLink';
19
15
 
20
- // The TanStack runtime plugin types its API against its own hook registry,
16
+ // TanStack runtime plugin types its API against its own hook registry,
21
17
  // while the provider contract is typed against the built-in router hook
22
- // registry of @modern-js/runtime. The two are runtime-compatible (the
18
+ // registry from @modern-js/runtime. The two are runtime-compatible (the
23
19
  // built-in router plugin registers the hooks and forwards its API to the
24
- // resolved provider), but nominally distinct — hence the explicit adapter
25
- // cast at this single boundary.
26
- const tanstackRouterProviderFactory: RouterProviderFactory = userConfig =>
27
- tanstackRouterPlugin(userConfig) as unknown as RouterProviderPlugin;
20
+ // resolved provider), but nominally distinct, so keep an explicit adapter
21
+ // cast as the single boundary.
22
+ export const tanstackRouterProviderFactory: RouterProviderFactory =
23
+ userConfig =>
24
+ tanstackRouterPlugin(userConfig) as unknown as RouterProviderPlugin;
28
25
 
29
26
  registerRouterProvider('tanstack', tanstackRouterProviderFactory);
30
-
31
- /**
32
- * Compatibility bindings for the deprecated `@modern-js/runtime/tanstack-router`
33
- * alias. `@modern-js/runtime` cannot depend on this package (the dependency
34
- * direction is plugin-tanstack -> runtime), so the alias resolves the
35
- * Modern.js specific bindings through this `Symbol.for` slot at use time.
36
- *
37
- * `??=` keeps the first copy: when Module Federation evaluates a second
38
- * bundled copy of this module, both copies are functionally identical and the
39
- * established registration wins (mirroring the router-provider registry).
40
- */
41
- const COMPAT_BINDINGS_SLOT: unique symbol = Symbol.for(
42
- '@modern-js/plugin-tanstack:runtime-compat-bindings',
43
- );
44
-
45
- export const tanstackRouterCompatBindings = {
46
- Form,
47
- Link,
48
- NavLink,
49
- Outlet,
50
- RouteActionResponseError,
51
- useFetcher,
52
- };
53
-
54
- (
55
- globalThis as {
56
- [COMPAT_BINDINGS_SLOT]?: typeof tanstackRouterCompatBindings;
57
- }
58
- )[COMPAT_BINDINGS_SLOT] ??= tanstackRouterCompatBindings;