@bleedingdev/modern-js-plugin-tanstack 3.2.0-ultramodern.0

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 (183) hide show
  1. package/LICENSE +21 -0
  2. package/dist/cjs/cli/index.js +268 -0
  3. package/dist/cjs/cli/tanstackTypes.js +388 -0
  4. package/dist/cjs/cli.js +65 -0
  5. package/dist/cjs/runtime/DefaultNotFound.js +47 -0
  6. package/dist/cjs/runtime/basepathRewrite.js +62 -0
  7. package/dist/cjs/runtime/dataMutation.js +345 -0
  8. package/dist/cjs/runtime/hooks.js +57 -0
  9. package/dist/cjs/runtime/index.js +114 -0
  10. package/dist/cjs/runtime/lifecycle.js +125 -0
  11. package/dist/cjs/runtime/plugin.js +250 -0
  12. package/dist/cjs/runtime/plugin.node.js +304 -0
  13. package/dist/cjs/runtime/prefetchLink.js +55 -0
  14. package/dist/cjs/runtime/routeTree.js +492 -0
  15. package/dist/cjs/runtime/rsc/ClientSlot.js +53 -0
  16. package/dist/cjs/runtime/rsc/CompositeComponent.js +75 -0
  17. package/dist/cjs/runtime/rsc/ReplayableStream.js +141 -0
  18. package/dist/cjs/runtime/rsc/RscNodeRenderer.js +65 -0
  19. package/dist/cjs/runtime/rsc/SlotContext.js +54 -0
  20. package/dist/cjs/runtime/rsc/client.js +93 -0
  21. package/dist/cjs/runtime/rsc/createRscProxy.js +141 -0
  22. package/dist/cjs/runtime/rsc/index.js +42 -0
  23. package/dist/cjs/runtime/rsc/payloadRouter.js +211 -0
  24. package/dist/cjs/runtime/rsc/server.js +246 -0
  25. package/dist/cjs/runtime/rsc/slotUsageSanitizer.js +65 -0
  26. package/dist/cjs/runtime/rsc/symbols.js +72 -0
  27. package/dist/cjs/runtime/types.js +18 -0
  28. package/dist/cjs/runtime/utils.js +142 -0
  29. package/dist/cjs/runtime.js +58 -0
  30. package/dist/esm/cli/index.mjs +201 -0
  31. package/dist/esm/cli/tanstackTypes.mjs +341 -0
  32. package/dist/esm/cli.mjs +2 -0
  33. package/dist/esm/rslib-runtime.mjs +18 -0
  34. package/dist/esm/runtime/DefaultNotFound.mjs +13 -0
  35. package/dist/esm/runtime/basepathRewrite.mjs +28 -0
  36. package/dist/esm/runtime/dataMutation.mjs +305 -0
  37. package/dist/esm/runtime/hooks.mjs +8 -0
  38. package/dist/esm/runtime/index.mjs +6 -0
  39. package/dist/esm/runtime/lifecycle.mjs +82 -0
  40. package/dist/esm/runtime/plugin.mjs +214 -0
  41. package/dist/esm/runtime/plugin.node.mjs +268 -0
  42. package/dist/esm/runtime/prefetchLink.mjs +18 -0
  43. package/dist/esm/runtime/routeTree.mjs +452 -0
  44. package/dist/esm/runtime/rsc/ClientSlot.mjs +19 -0
  45. package/dist/esm/runtime/rsc/CompositeComponent.mjs +41 -0
  46. package/dist/esm/runtime/rsc/ReplayableStream.mjs +104 -0
  47. package/dist/esm/runtime/rsc/RscNodeRenderer.mjs +31 -0
  48. package/dist/esm/runtime/rsc/SlotContext.mjs +17 -0
  49. package/dist/esm/runtime/rsc/client.mjs +53 -0
  50. package/dist/esm/runtime/rsc/createRscProxy.mjs +107 -0
  51. package/dist/esm/runtime/rsc/index.mjs +1 -0
  52. package/dist/esm/runtime/rsc/payloadRouter.mjs +162 -0
  53. package/dist/esm/runtime/rsc/server.mjs +200 -0
  54. package/dist/esm/runtime/rsc/slotUsageSanitizer.mjs +31 -0
  55. package/dist/esm/runtime/rsc/symbols.mjs +17 -0
  56. package/dist/esm/runtime/types.mjs +0 -0
  57. package/dist/esm/runtime/utils.mjs +89 -0
  58. package/dist/esm/runtime.mjs +1 -0
  59. package/dist/esm-node/cli/index.mjs +205 -0
  60. package/dist/esm-node/cli/tanstackTypes.mjs +342 -0
  61. package/dist/esm-node/cli.mjs +3 -0
  62. package/dist/esm-node/rslib-runtime.mjs +19 -0
  63. package/dist/esm-node/runtime/DefaultNotFound.mjs +14 -0
  64. package/dist/esm-node/runtime/basepathRewrite.mjs +29 -0
  65. package/dist/esm-node/runtime/dataMutation.mjs +306 -0
  66. package/dist/esm-node/runtime/hooks.mjs +9 -0
  67. package/dist/esm-node/runtime/index.mjs +7 -0
  68. package/dist/esm-node/runtime/lifecycle.mjs +83 -0
  69. package/dist/esm-node/runtime/plugin.mjs +215 -0
  70. package/dist/esm-node/runtime/plugin.node.mjs +269 -0
  71. package/dist/esm-node/runtime/prefetchLink.mjs +19 -0
  72. package/dist/esm-node/runtime/routeTree.mjs +453 -0
  73. package/dist/esm-node/runtime/rsc/ClientSlot.mjs +20 -0
  74. package/dist/esm-node/runtime/rsc/CompositeComponent.mjs +42 -0
  75. package/dist/esm-node/runtime/rsc/ReplayableStream.mjs +105 -0
  76. package/dist/esm-node/runtime/rsc/RscNodeRenderer.mjs +32 -0
  77. package/dist/esm-node/runtime/rsc/SlotContext.mjs +18 -0
  78. package/dist/esm-node/runtime/rsc/client.mjs +54 -0
  79. package/dist/esm-node/runtime/rsc/createRscProxy.mjs +108 -0
  80. package/dist/esm-node/runtime/rsc/index.mjs +2 -0
  81. package/dist/esm-node/runtime/rsc/payloadRouter.mjs +163 -0
  82. package/dist/esm-node/runtime/rsc/server.mjs +201 -0
  83. package/dist/esm-node/runtime/rsc/slotUsageSanitizer.mjs +32 -0
  84. package/dist/esm-node/runtime/rsc/symbols.mjs +18 -0
  85. package/dist/esm-node/runtime/types.mjs +1 -0
  86. package/dist/esm-node/runtime/utils.mjs +90 -0
  87. package/dist/esm-node/runtime.mjs +2 -0
  88. package/dist/types/cli/index.d.ts +20 -0
  89. package/dist/types/cli/tanstackTypes.d.ts +11 -0
  90. package/dist/types/cli.d.ts +2 -0
  91. package/dist/types/runtime/DefaultNotFound.d.ts +2 -0
  92. package/dist/types/runtime/basepathRewrite.d.ts +8 -0
  93. package/dist/types/runtime/dataMutation.d.ts +29 -0
  94. package/dist/types/runtime/hooks.d.ts +18 -0
  95. package/dist/types/runtime/index.d.ts +9 -0
  96. package/dist/types/runtime/lifecycle.d.ts +22 -0
  97. package/dist/types/runtime/plugin.d.ts +17 -0
  98. package/dist/types/runtime/plugin.node.d.ts +17 -0
  99. package/dist/types/runtime/prefetchLink.d.ts +11 -0
  100. package/dist/types/runtime/routeTree.d.ts +11 -0
  101. package/dist/types/runtime/rsc/ClientSlot.d.ts +5 -0
  102. package/dist/types/runtime/rsc/CompositeComponent.d.ts +3 -0
  103. package/dist/types/runtime/rsc/ReplayableStream.d.ts +24 -0
  104. package/dist/types/runtime/rsc/RscNodeRenderer.d.ts +5 -0
  105. package/dist/types/runtime/rsc/SlotContext.d.ts +11 -0
  106. package/dist/types/runtime/rsc/client.d.ts +11 -0
  107. package/dist/types/runtime/rsc/createRscProxy.d.ts +7 -0
  108. package/dist/types/runtime/rsc/index.d.ts +2 -0
  109. package/dist/types/runtime/rsc/payloadRouter.d.ts +24 -0
  110. package/dist/types/runtime/rsc/server.d.ts +14 -0
  111. package/dist/types/runtime/rsc/slotUsageSanitizer.d.ts +2 -0
  112. package/dist/types/runtime/rsc/symbols.d.ts +46 -0
  113. package/dist/types/runtime/types.d.ts +68 -0
  114. package/dist/types/runtime/utils.d.ts +36 -0
  115. package/dist/types/runtime.d.ts +1 -0
  116. package/dist/types-direct/cli/index.d.ts +20 -0
  117. package/dist/types-direct/cli/tanstackTypes.d.ts +11 -0
  118. package/dist/types-direct/cli.d.ts +2 -0
  119. package/dist/types-direct/runtime/DefaultNotFound.d.ts +2 -0
  120. package/dist/types-direct/runtime/basepathRewrite.d.ts +8 -0
  121. package/dist/types-direct/runtime/dataMutation.d.ts +29 -0
  122. package/dist/types-direct/runtime/hooks.d.ts +18 -0
  123. package/dist/types-direct/runtime/index.d.ts +9 -0
  124. package/dist/types-direct/runtime/lifecycle.d.ts +22 -0
  125. package/dist/types-direct/runtime/plugin.d.ts +17 -0
  126. package/dist/types-direct/runtime/plugin.node.d.ts +17 -0
  127. package/dist/types-direct/runtime/prefetchLink.d.ts +11 -0
  128. package/dist/types-direct/runtime/routeTree.d.ts +11 -0
  129. package/dist/types-direct/runtime/rsc/ClientSlot.d.ts +5 -0
  130. package/dist/types-direct/runtime/rsc/CompositeComponent.d.ts +3 -0
  131. package/dist/types-direct/runtime/rsc/ReplayableStream.d.ts +24 -0
  132. package/dist/types-direct/runtime/rsc/RscNodeRenderer.d.ts +5 -0
  133. package/dist/types-direct/runtime/rsc/SlotContext.d.ts +11 -0
  134. package/dist/types-direct/runtime/rsc/client.d.ts +11 -0
  135. package/dist/types-direct/runtime/rsc/createRscProxy.d.ts +7 -0
  136. package/dist/types-direct/runtime/rsc/index.d.ts +2 -0
  137. package/dist/types-direct/runtime/rsc/payloadRouter.d.ts +24 -0
  138. package/dist/types-direct/runtime/rsc/server.d.ts +14 -0
  139. package/dist/types-direct/runtime/rsc/slotUsageSanitizer.d.ts +2 -0
  140. package/dist/types-direct/runtime/rsc/symbols.d.ts +46 -0
  141. package/dist/types-direct/runtime/types.d.ts +68 -0
  142. package/dist/types-direct/runtime/utils.d.ts +36 -0
  143. package/dist/types-direct/runtime.d.ts +1 -0
  144. package/package.json +126 -0
  145. package/rslib.config.mts +4 -0
  146. package/rstest.config.mts +43 -0
  147. package/src/cli/index.ts +388 -0
  148. package/src/cli/tanstackTypes.ts +503 -0
  149. package/src/cli.ts +2 -0
  150. package/src/runtime/DefaultNotFound.tsx +15 -0
  151. package/src/runtime/basepathRewrite.ts +59 -0
  152. package/src/runtime/dataMutation.tsx +517 -0
  153. package/src/runtime/hooks.ts +34 -0
  154. package/src/runtime/index.tsx +30 -0
  155. package/src/runtime/lifecycle.ts +150 -0
  156. package/src/runtime/plugin.node.tsx +534 -0
  157. package/src/runtime/plugin.tsx +395 -0
  158. package/src/runtime/prefetchLink.tsx +87 -0
  159. package/src/runtime/routeTree.ts +942 -0
  160. package/src/runtime/rsc/ClientSlot.tsx +25 -0
  161. package/src/runtime/rsc/CompositeComponent.tsx +65 -0
  162. package/src/runtime/rsc/ReplayableStream.ts +155 -0
  163. package/src/runtime/rsc/RscNodeRenderer.tsx +45 -0
  164. package/src/runtime/rsc/SlotContext.tsx +31 -0
  165. package/src/runtime/rsc/client.tsx +90 -0
  166. package/src/runtime/rsc/createRscProxy.tsx +189 -0
  167. package/src/runtime/rsc/index.ts +10 -0
  168. package/src/runtime/rsc/payloadRouter.ts +318 -0
  169. package/src/runtime/rsc/server.tsx +303 -0
  170. package/src/runtime/rsc/slotUsageSanitizer.ts +76 -0
  171. package/src/runtime/rsc/symbols.ts +106 -0
  172. package/src/runtime/ssr-shim.d.ts +12 -0
  173. package/src/runtime/types.ts +83 -0
  174. package/src/runtime/utils.tsx +161 -0
  175. package/src/runtime.ts +1 -0
  176. package/tests/router/cli.test.ts +386 -0
  177. package/tests/router/dataMutation.test.tsx +396 -0
  178. package/tests/router/prefetchLink.test.tsx +43 -0
  179. package/tests/router/routeTree.test.ts +502 -0
  180. package/tests/router/rsc.test.tsx +256 -0
  181. package/tests/router/tanstackTypes.test.ts +62 -0
  182. package/tsconfig.json +12 -0
  183. package/tsconfig.tsgo.json +6 -0
@@ -0,0 +1,395 @@
1
+ /// <reference path="./ssr-shim.d.ts" />
2
+
3
+ import type { Plugin, RuntimePluginExtends } from '@modern-js/plugin';
4
+ import type { RuntimePluginAPI } from '@modern-js/plugin/runtime';
5
+ import {
6
+ getGlobalEnableRsc,
7
+ getGlobalLayoutApp,
8
+ getGlobalRoutes,
9
+ InternalRuntimeContext,
10
+ type TInternalRuntimeContext,
11
+ } from '@modern-js/runtime/context';
12
+ import { merge } from '@modern-js/runtime-utils/merge';
13
+ import type { RouteObject } from '@modern-js/runtime-utils/router';
14
+ import { normalizePathname } from '@modern-js/runtime-utils/url';
15
+ import {
16
+ type AnyRouter,
17
+ createBrowserHistory,
18
+ createHashHistory,
19
+ createRouter,
20
+ RouterProvider,
21
+ useLocation,
22
+ useMatches,
23
+ useNavigate,
24
+ useRouter,
25
+ } from '@tanstack/react-router';
26
+ import { RouterClient } from '@tanstack/react-router/ssr/client';
27
+ import * as React from 'react';
28
+ import { useContext, useMemo } from 'react';
29
+ import { createModernBasepathRewrite } from './basepathRewrite';
30
+ import {
31
+ modifyRoutes as modifyRoutesHook,
32
+ onAfterCreateRouter as onAfterCreateRouterHook,
33
+ onAfterHydrateRouter as onAfterHydrateRouterHook,
34
+ onBeforeCreateRouter as onBeforeCreateRouterHook,
35
+ onBeforeCreateRoutes as onBeforeCreateRoutesHook,
36
+ onBeforeHydrateRouter as onBeforeHydrateRouterHook,
37
+ type RouterExtendsHooks,
38
+ } from './hooks';
39
+ import {
40
+ applyRouterRuntimeState,
41
+ type RouterLifecycleContext,
42
+ } from './lifecycle';
43
+ import { createRouteTreeFromRouteObjects } from './routeTree';
44
+ import { getTanstackRscSerializationAdapters } from './rsc/client';
45
+ import type { RouterConfig } from './types';
46
+ import { createRouteObjectsFromConfig, urlJoin } from './utils';
47
+
48
+ const BLOCKING_SUBSCRIBE_SYMBOL = Symbol.for(
49
+ '@modern-js/plugin-tanstack:blocking-subscribe',
50
+ );
51
+ const BLOCKING_STATE_SYMBOL = Symbol.for(
52
+ '@modern-js/plugin-tanstack:blocking-state',
53
+ );
54
+
55
+ type TanstackRouterWithSubscribe = {
56
+ [BLOCKING_STATE_SYMBOL]?: () => boolean;
57
+ [BLOCKING_SUBSCRIBE_SYMBOL]?: boolean;
58
+ subscribe?: (
59
+ eventType: string,
60
+ listener: (...args: unknown[]) => void,
61
+ ) => () => void;
62
+ };
63
+
64
+ type WindowWithTanstackSsr = Window & {
65
+ $_TSR?: unknown;
66
+ };
67
+
68
+ type TanstackRouterRuntimeConfig = {
69
+ plugins?: TanstackRouterRuntimePlugin[];
70
+ router?: Partial<RouterConfig>;
71
+ [key: string]: unknown;
72
+ };
73
+
74
+ type TanstackRouterRuntimeExtends = Required<
75
+ RuntimePluginExtends<TanstackRouterRuntimeConfig, TInternalRuntimeContext>
76
+ > & {
77
+ extendHooks: RouterExtendsHooks;
78
+ };
79
+
80
+ type TanstackRouterPluginAPI = RuntimePluginAPI<TanstackRouterRuntimeExtends>;
81
+
82
+ type TanstackRouterRuntimePlugin = Plugin<
83
+ TanstackRouterPluginAPI,
84
+ TInternalRuntimeContext
85
+ >;
86
+
87
+ function normalizeBase(b: string) {
88
+ if (b.length > 1 && b.endsWith('/')) {
89
+ return b.slice(0, -1);
90
+ }
91
+ return b || '/';
92
+ }
93
+
94
+ function isSegmentPrefix(pathname: string, base: string) {
95
+ const b = normalizeBase(base);
96
+ const p = pathname || '/';
97
+ return p === b || p.startsWith(`${b}/`);
98
+ }
99
+
100
+ function wrapRouterSubscribeWithBlockState(
101
+ router: unknown,
102
+ getBlockNavState?: () => boolean,
103
+ ) {
104
+ if (!router || typeof router !== 'object') {
105
+ return;
106
+ }
107
+
108
+ const target = router as TanstackRouterWithSubscribe;
109
+ target[BLOCKING_STATE_SYMBOL] = getBlockNavState;
110
+ if (
111
+ target[BLOCKING_SUBSCRIBE_SYMBOL] ||
112
+ typeof target.subscribe !== 'function'
113
+ ) {
114
+ return;
115
+ }
116
+
117
+ const originSubscribe = target.subscribe.bind(target);
118
+ target.subscribe = (eventType, listener) => {
119
+ const wrappedListener = (...args: unknown[]) => {
120
+ const blockRoute = target[BLOCKING_STATE_SYMBOL]?.() || false;
121
+ if (blockRoute) {
122
+ return;
123
+ }
124
+ return listener(...args);
125
+ };
126
+ return originSubscribe(eventType, wrappedListener);
127
+ };
128
+ target[BLOCKING_SUBSCRIBE_SYMBOL] = true;
129
+ }
130
+
131
+ function stripSyntheticNotFoundRoute(routes: RouteObject[]): RouteObject[] {
132
+ return routes
133
+ .filter(route => !(route.path === '*' && !route.id && !route.loader))
134
+ .map(route => {
135
+ if (!route.children?.length) {
136
+ return route;
137
+ }
138
+ return {
139
+ ...route,
140
+ children: stripSyntheticNotFoundRoute(route.children),
141
+ };
142
+ });
143
+ }
144
+
145
+ export const tanstackRouterPlugin = (
146
+ userConfig: Partial<RouterConfig> = {},
147
+ ): TanstackRouterRuntimePlugin => {
148
+ const plugin: TanstackRouterRuntimePlugin = {
149
+ name: '@modern-js/plugin-router-tanstack',
150
+ registryHooks: {
151
+ modifyRoutes: modifyRoutesHook,
152
+ onAfterCreateRouter: onAfterCreateRouterHook,
153
+ onAfterHydrateRouter: onAfterHydrateRouterHook,
154
+ onBeforeCreateRouter: onBeforeCreateRouterHook,
155
+ onBeforeCreateRoutes: onBeforeCreateRoutesHook,
156
+ onBeforeHydrateRouter: onBeforeHydrateRouterHook,
157
+ },
158
+ setup: (api: TanstackRouterPluginAPI) => {
159
+ api.onBeforeRender(context => {
160
+ const pluginConfig = api.getRuntimeConfig() as {
161
+ router?: Partial<RouterConfig>;
162
+ };
163
+ const mergedConfig = merge(
164
+ pluginConfig.router || {},
165
+ userConfig,
166
+ ) as RouterConfig;
167
+ if (
168
+ typeof window !== 'undefined' &&
169
+ (window as { _SSR_DATA?: unknown })._SSR_DATA &&
170
+ mergedConfig.unstable_reloadOnURLMismatch
171
+ ) {
172
+ const { ssrContext } = context;
173
+ const currentPathname = normalizePathname(window.location.pathname);
174
+ const initialPathname =
175
+ ssrContext?.request?.pathname &&
176
+ normalizePathname(ssrContext.request.pathname);
177
+
178
+ if (initialPathname && initialPathname !== currentPathname) {
179
+ const errorMsg = `The initial URL ${initialPathname} and the URL ${currentPathname} to be hydrated do not match, reload.`;
180
+ console.error(errorMsg);
181
+ window.location.reload();
182
+ }
183
+ }
184
+
185
+ context.router = {
186
+ useMatches,
187
+ useLocation,
188
+ useNavigate,
189
+ useRouter,
190
+ };
191
+ });
192
+
193
+ api.wrapRoot(App => {
194
+ const mergedConfig = merge(
195
+ api.getRuntimeConfig().router || {},
196
+ userConfig,
197
+ ) as RouterConfig;
198
+
199
+ const {
200
+ serverBase = [],
201
+ supportHtml5History = true,
202
+ basename = '',
203
+ routesConfig,
204
+ createRoutes,
205
+ } = mergedConfig;
206
+
207
+ const finalRouteConfig = {
208
+ routes: getGlobalRoutes(),
209
+ globalApp: getGlobalLayoutApp(),
210
+ ...routesConfig,
211
+ };
212
+
213
+ if (!finalRouteConfig.routes && !createRoutes) {
214
+ return App;
215
+ }
216
+
217
+ const hooks = api.getHooks();
218
+
219
+ let cachedRouteObjects: RouteObject[] | undefined;
220
+
221
+ const getRouteObjects = () => {
222
+ if (typeof cachedRouteObjects !== 'undefined') {
223
+ return cachedRouteObjects;
224
+ }
225
+
226
+ const routeObjects = createRoutes
227
+ ? createRoutes()
228
+ : createRouteObjectsFromConfig({
229
+ routesConfig: finalRouteConfig,
230
+ }) || [];
231
+
232
+ const normalizedRouteObjects = createRoutes
233
+ ? routeObjects
234
+ : stripSyntheticNotFoundRoute(routeObjects);
235
+
236
+ cachedRouteObjects = hooks.modifyRoutes.call(
237
+ normalizedRouteObjects,
238
+ ) as RouteObject[];
239
+ return cachedRouteObjects;
240
+ };
241
+
242
+ const selectBasePath = (pathname: string) => {
243
+ const match = serverBase.find(baseUrl =>
244
+ isSegmentPrefix(pathname, baseUrl),
245
+ );
246
+ return match || '/';
247
+ };
248
+
249
+ let cachedRouteTree: ReturnType<
250
+ typeof createRouteTreeFromRouteObjects
251
+ > | null = null;
252
+ let cachedRouter: AnyRouter | null = null;
253
+ let cachedRouterBasepath: string | null = null;
254
+
255
+ const RouterWrapper = () => {
256
+ const runtimeContext = useContext(
257
+ InternalRuntimeContext,
258
+ ) as TInternalRuntimeContext;
259
+
260
+ const baseUrl = selectBasePath(location.pathname).replace(
261
+ /^\/*/,
262
+ '/',
263
+ );
264
+ const _basename =
265
+ baseUrl === '/'
266
+ ? urlJoin(
267
+ baseUrl,
268
+ runtimeContext._internalRouterBaseName || basename || '',
269
+ )
270
+ : baseUrl;
271
+
272
+ const routeTree = useMemo(() => {
273
+ if (cachedRouteTree) {
274
+ return cachedRouteTree;
275
+ }
276
+ const routeObjects = getRouteObjects();
277
+ if (!routeObjects.length) {
278
+ return null;
279
+ }
280
+ cachedRouteTree = createRouteTreeFromRouteObjects(routeObjects, {
281
+ rscPayloadRouter: getGlobalEnableRsc(),
282
+ });
283
+ return cachedRouteTree;
284
+ }, []);
285
+
286
+ if (!routeTree) {
287
+ return App ? <App /> : null;
288
+ }
289
+
290
+ const router = useMemo(() => {
291
+ const lifecycleContext: RouterLifecycleContext = {
292
+ framework: 'tanstack',
293
+ phase: 'client-create',
294
+ routes: getRouteObjects(),
295
+ runtimeContext,
296
+ basename: _basename,
297
+ };
298
+ hooks.onBeforeCreateRouter.call(lifecycleContext);
299
+
300
+ if (cachedRouter && cachedRouterBasepath === _basename) {
301
+ wrapRouterSubscribeWithBlockState(
302
+ cachedRouter,
303
+ runtimeContext.unstable_getBlockNavState,
304
+ );
305
+ hooks.onAfterCreateRouter.call({
306
+ ...lifecycleContext,
307
+ router: cachedRouter,
308
+ runtimeContext,
309
+ });
310
+ return cachedRouter;
311
+ }
312
+
313
+ const history = supportHtml5History
314
+ ? createBrowserHistory()
315
+ : createHashHistory();
316
+
317
+ const rewrite = createModernBasepathRewrite(_basename);
318
+ const serializationAdapters = getGlobalEnableRsc()
319
+ ? getTanstackRscSerializationAdapters()
320
+ : undefined;
321
+
322
+ cachedRouter = createRouter({
323
+ routeTree,
324
+ basepath: '/',
325
+ rewrite,
326
+ history,
327
+ context: {},
328
+ ...(serializationAdapters ? { serializationAdapters } : {}),
329
+ });
330
+ cachedRouterBasepath = _basename;
331
+ wrapRouterSubscribeWithBlockState(
332
+ cachedRouter,
333
+ runtimeContext.unstable_getBlockNavState,
334
+ );
335
+ hooks.onAfterCreateRouter.call({
336
+ ...lifecycleContext,
337
+ router: cachedRouter,
338
+ runtimeContext,
339
+ });
340
+
341
+ return cachedRouter;
342
+ }, [_basename, routeTree, supportHtml5History, runtimeContext]);
343
+ const runtimeState = applyRouterRuntimeState(runtimeContext, {
344
+ framework: 'tanstack',
345
+ basename: _basename,
346
+ instance: router,
347
+ });
348
+ const lifecycleContext: RouterLifecycleContext = {
349
+ framework: 'tanstack',
350
+ phase: 'client-create',
351
+ routes: getRouteObjects(),
352
+ runtimeContext: runtimeState,
353
+ basename: _basename,
354
+ router,
355
+ };
356
+
357
+ const hasSSRBootstrap =
358
+ typeof window !== 'undefined' &&
359
+ Boolean((window as WindowWithTanstackSsr).$_TSR);
360
+ if (hasSSRBootstrap) {
361
+ hooks.onBeforeHydrateRouter.call({
362
+ ...lifecycleContext,
363
+ phase: 'hydrate',
364
+ router,
365
+ runtimeContext: runtimeState,
366
+ });
367
+ }
368
+
369
+ const RouterContent = hasSSRBootstrap ? (
370
+ <React.Suspense fallback={null}>
371
+ <RouterClient router={router} />
372
+ </React.Suspense>
373
+ ) : (
374
+ <RouterProvider router={router} />
375
+ );
376
+ if (hasSSRBootstrap) {
377
+ hooks.onAfterHydrateRouter.call({
378
+ ...lifecycleContext,
379
+ phase: 'hydrate',
380
+ router,
381
+ runtimeContext: runtimeState,
382
+ });
383
+ }
384
+
385
+ return App ? <App>{RouterContent}</App> : RouterContent;
386
+ };
387
+
388
+ return RouterWrapper;
389
+ });
390
+ },
391
+ };
392
+ return plugin;
393
+ };
394
+
395
+ export default tanstackRouterPlugin;
@@ -0,0 +1,87 @@
1
+ import {
2
+ type AnyRouter,
3
+ type LinkComponentProps,
4
+ type RegisteredRouter,
5
+ Link as TanStackLink,
6
+ } from '@tanstack/react-router';
7
+ import type { ReactElement } from 'react';
8
+
9
+ export type PrefetchBehavior = 'intent' | 'render' | 'viewport' | 'none';
10
+
11
+ function resolvePreloadFromPrefetch(
12
+ prefetch: PrefetchBehavior | undefined,
13
+ preload: unknown,
14
+ ) {
15
+ if (typeof preload !== 'undefined') {
16
+ return preload;
17
+ }
18
+
19
+ if (prefetch === 'none') {
20
+ return false;
21
+ }
22
+
23
+ if (
24
+ prefetch === 'intent' ||
25
+ prefetch === 'render' ||
26
+ prefetch === 'viewport'
27
+ ) {
28
+ return prefetch;
29
+ }
30
+
31
+ return preload;
32
+ }
33
+
34
+ export type LinkProps<
35
+ TRouter extends AnyRouter = RegisteredRouter,
36
+ TFrom extends string = string,
37
+ TTo extends string | undefined = '.',
38
+ TMaskFrom extends string = TFrom,
39
+ TMaskTo extends string = '.',
40
+ > = LinkComponentProps<'a', TRouter, TFrom, TTo, TMaskFrom, TMaskTo> & {
41
+ prefetch?: PrefetchBehavior;
42
+ };
43
+
44
+ export type NavLinkProps<
45
+ TRouter extends AnyRouter = RegisteredRouter,
46
+ TFrom extends string = string,
47
+ TTo extends string | undefined = '.',
48
+ TMaskFrom extends string = TFrom,
49
+ TMaskTo extends string = '.',
50
+ > = LinkProps<TRouter, TFrom, TTo, TMaskFrom, TMaskTo>;
51
+
52
+ type LinkComponent = <
53
+ TRouter extends AnyRouter = RegisteredRouter,
54
+ const TFrom extends string = string,
55
+ const TTo extends string | undefined = undefined,
56
+ const TMaskFrom extends string = TFrom,
57
+ const TMaskTo extends string = '',
58
+ >(
59
+ props: LinkProps<TRouter, TFrom, TTo, TMaskFrom, TMaskTo>,
60
+ ) => ReactElement;
61
+
62
+ type LinkComponentImplProps = LinkProps<
63
+ AnyRouter,
64
+ string,
65
+ string | undefined,
66
+ string,
67
+ string
68
+ >;
69
+
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
+ );
83
+ };
84
+
85
+ export const Link = LinkComponentImpl as LinkComponent;
86
+
87
+ export const NavLink = LinkComponentImpl as LinkComponent;