@bleedingdev/modern-js-plugin-tanstack 3.2.0-ultramodern.95 → 3.2.0-ultramodern.97
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/cjs/runtime/hydrationBoundary.js +43 -0
- package/dist/cjs/runtime/plugin.js +4 -2
- package/dist/cjs/runtime/plugin.node.js +3 -2
- package/dist/cjs/runtime/routeTree.js +4 -2
- package/dist/esm/runtime/hydrationBoundary.mjs +9 -0
- package/dist/esm/runtime/plugin.mjs +4 -2
- package/dist/esm/runtime/plugin.node.mjs +3 -2
- package/dist/esm/runtime/routeTree.mjs +4 -2
- package/dist/esm-node/runtime/hydrationBoundary.mjs +10 -0
- package/dist/esm-node/runtime/plugin.mjs +4 -2
- package/dist/esm-node/runtime/plugin.node.mjs +3 -2
- package/dist/esm-node/runtime/routeTree.mjs +4 -2
- package/dist/types/runtime/hydrationBoundary.d.ts +2 -0
- package/package.json +8 -8
- package/src/runtime/hydrationBoundary.tsx +12 -0
- package/src/runtime/plugin.node.tsx +4 -2
- package/src/runtime/plugin.tsx +10 -1
- package/src/runtime/routeTree.ts +29 -9
- package/tests/router/hydrationBoundary.test.tsx +23 -0
- package/tests/router/routeTree.test.ts +53 -0
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __webpack_require__ = {};
|
|
3
|
+
(()=>{
|
|
4
|
+
__webpack_require__.d = (exports1, definition)=>{
|
|
5
|
+
for(var key in definition)if (__webpack_require__.o(definition, key) && !__webpack_require__.o(exports1, key)) Object.defineProperty(exports1, key, {
|
|
6
|
+
enumerable: true,
|
|
7
|
+
get: definition[key]
|
|
8
|
+
});
|
|
9
|
+
};
|
|
10
|
+
})();
|
|
11
|
+
(()=>{
|
|
12
|
+
__webpack_require__.o = (obj, prop)=>Object.prototype.hasOwnProperty.call(obj, prop);
|
|
13
|
+
})();
|
|
14
|
+
(()=>{
|
|
15
|
+
__webpack_require__.r = (exports1)=>{
|
|
16
|
+
if ("u" > typeof Symbol && Symbol.toStringTag) Object.defineProperty(exports1, Symbol.toStringTag, {
|
|
17
|
+
value: 'Module'
|
|
18
|
+
});
|
|
19
|
+
Object.defineProperty(exports1, '__esModule', {
|
|
20
|
+
value: true
|
|
21
|
+
});
|
|
22
|
+
};
|
|
23
|
+
})();
|
|
24
|
+
var __webpack_exports__ = {};
|
|
25
|
+
__webpack_require__.r(__webpack_exports__);
|
|
26
|
+
__webpack_require__.d(__webpack_exports__, {
|
|
27
|
+
wrapTanstackSsrHydrationBoundary: ()=>wrapTanstackSsrHydrationBoundary
|
|
28
|
+
});
|
|
29
|
+
const jsx_runtime_namespaceObject = require("react/jsx-runtime");
|
|
30
|
+
const external_react_namespaceObject = require("react");
|
|
31
|
+
function wrapTanstackSsrHydrationBoundary(routerContent, shouldWrap) {
|
|
32
|
+
return shouldWrap ? /*#__PURE__*/ (0, jsx_runtime_namespaceObject.jsx)(external_react_namespaceObject.Suspense, {
|
|
33
|
+
fallback: null,
|
|
34
|
+
children: routerContent
|
|
35
|
+
}) : routerContent;
|
|
36
|
+
}
|
|
37
|
+
exports.wrapTanstackSsrHydrationBoundary = __webpack_exports__.wrapTanstackSsrHydrationBoundary;
|
|
38
|
+
for(var __rspack_i in __webpack_exports__)if (-1 === [
|
|
39
|
+
"wrapTanstackSsrHydrationBoundary"
|
|
40
|
+
].indexOf(__rspack_i)) exports[__rspack_i] = __webpack_exports__[__rspack_i];
|
|
41
|
+
Object.defineProperty(exports, '__esModule', {
|
|
42
|
+
value: true
|
|
43
|
+
});
|
|
@@ -36,6 +36,7 @@ const client_namespaceObject = require("@tanstack/react-router/ssr/client");
|
|
|
36
36
|
const external_react_namespaceObject = require("react");
|
|
37
37
|
const external_basepathRewrite_js_namespaceObject = require("./basepathRewrite.js");
|
|
38
38
|
const external_hooks_js_namespaceObject = require("./hooks.js");
|
|
39
|
+
const external_hydrationBoundary_js_namespaceObject = require("./hydrationBoundary.js");
|
|
39
40
|
const external_lifecycle_js_namespaceObject = require("./lifecycle.js");
|
|
40
41
|
const external_prefetchLink_js_namespaceObject = require("./prefetchLink.js");
|
|
41
42
|
const external_routeTree_js_namespaceObject = require("./routeTree.js");
|
|
@@ -223,6 +224,7 @@ const tanstackRouterPlugin = (userConfig = {})=>{
|
|
|
223
224
|
}) : /*#__PURE__*/ (0, jsx_runtime_namespaceObject.jsx)(react_router_namespaceObject.RouterProvider, {
|
|
224
225
|
router: router
|
|
225
226
|
});
|
|
227
|
+
const HydratableRouterContent = (0, external_hydrationBoundary_js_namespaceObject.wrapTanstackSsrHydrationBoundary)(RouterContent, hasSSRBootstrap);
|
|
226
228
|
if (hasSSRBootstrap) hooks.onAfterHydrateRouter.call({
|
|
227
229
|
...lifecycleContext,
|
|
228
230
|
phase: 'hydrate',
|
|
@@ -230,8 +232,8 @@ const tanstackRouterPlugin = (userConfig = {})=>{
|
|
|
230
232
|
runtimeContext: runtimeState
|
|
231
233
|
});
|
|
232
234
|
return App ? /*#__PURE__*/ (0, jsx_runtime_namespaceObject.jsx)(App, {
|
|
233
|
-
children:
|
|
234
|
-
}) :
|
|
235
|
+
children: HydratableRouterContent
|
|
236
|
+
}) : HydratableRouterContent;
|
|
235
237
|
};
|
|
236
238
|
return RouterWrapper;
|
|
237
239
|
});
|
|
@@ -38,6 +38,7 @@ const server_namespaceObject = require("@tanstack/router-core/ssr/server");
|
|
|
38
38
|
const external_react_namespaceObject = require("react");
|
|
39
39
|
const external_basepathRewrite_js_namespaceObject = require("./basepathRewrite.js");
|
|
40
40
|
const external_hooks_js_namespaceObject = require("./hooks.js");
|
|
41
|
+
const external_hydrationBoundary_js_namespaceObject = require("./hydrationBoundary.js");
|
|
41
42
|
const external_lifecycle_js_namespaceObject = require("./lifecycle.js");
|
|
42
43
|
const external_routeTree_js_namespaceObject = require("./routeTree.js");
|
|
43
44
|
const payloadRouter_js_namespaceObject = require("./rsc/payloadRouter.js");
|
|
@@ -296,9 +297,9 @@ const tanstackRouterPlugin = (userConfig = {})=>{
|
|
|
296
297
|
if (!router) return App ? /*#__PURE__*/ (0, jsx_runtime_namespaceObject.jsx)(App, {
|
|
297
298
|
...props
|
|
298
299
|
}) : null;
|
|
299
|
-
const routerWrapper = /*#__PURE__*/ (0, jsx_runtime_namespaceObject.jsx)(react_router_namespaceObject.RouterProvider, {
|
|
300
|
+
const routerWrapper = (0, external_hydrationBoundary_js_namespaceObject.wrapTanstackSsrHydrationBoundary)(/*#__PURE__*/ (0, jsx_runtime_namespaceObject.jsx)(react_router_namespaceObject.RouterProvider, {
|
|
300
301
|
router: router
|
|
301
|
-
});
|
|
302
|
+
}), true);
|
|
302
303
|
return App ? /*#__PURE__*/ (0, jsx_runtime_namespaceObject.jsx)(App, {
|
|
303
304
|
children: routerWrapper
|
|
304
305
|
}) : routerWrapper;
|
|
@@ -520,9 +520,11 @@ function createRouteTreeFromRouteObjects(routes, options = {}) {
|
|
|
520
520
|
}
|
|
521
521
|
function getModernRouteIdsFromMatches(router) {
|
|
522
522
|
const matches = router.state.matches || [];
|
|
523
|
+
const routesById = router.routesById;
|
|
523
524
|
const ids = matches.map((match)=>{
|
|
524
|
-
const
|
|
525
|
-
|
|
525
|
+
const normalizedMatch = match;
|
|
526
|
+
const routeId = 'string' == typeof normalizedMatch.routeId ? normalizedMatch.routeId : void 0;
|
|
527
|
+
return normalizedMatch.route?.options?.staticData?.modernRouteId ?? (routeId ? routesById?.[routeId]?.options?.staticData?.modernRouteId : void 0);
|
|
526
528
|
}).filter((id)=>'string' == typeof id);
|
|
527
529
|
return Array.from(new Set(ids));
|
|
528
530
|
}
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
import { jsx } from "react/jsx-runtime";
|
|
2
|
+
import { Suspense } from "react";
|
|
3
|
+
function wrapTanstackSsrHydrationBoundary(routerContent, shouldWrap) {
|
|
4
|
+
return shouldWrap ? /*#__PURE__*/ jsx(Suspense, {
|
|
5
|
+
fallback: null,
|
|
6
|
+
children: routerContent
|
|
7
|
+
}) : routerContent;
|
|
8
|
+
}
|
|
9
|
+
export { wrapTanstackSsrHydrationBoundary };
|
|
@@ -7,6 +7,7 @@ import { RouterClient } from "@tanstack/react-router/ssr/client";
|
|
|
7
7
|
import { useContext, useMemo } from "react";
|
|
8
8
|
import { createModernBasepathRewrite } from "./basepathRewrite.mjs";
|
|
9
9
|
import { modifyRoutes, onAfterCreateRouter, onAfterHydrateRouter, onBeforeCreateRouter, onBeforeCreateRoutes, onBeforeHydrateRouter } from "./hooks.mjs";
|
|
10
|
+
import { wrapTanstackSsrHydrationBoundary } from "./hydrationBoundary.mjs";
|
|
10
11
|
import { applyRouterRuntimeState } from "./lifecycle.mjs";
|
|
11
12
|
import { Link } from "./prefetchLink.mjs";
|
|
12
13
|
import { createRouteTreeFromRouteObjects } from "./routeTree.mjs";
|
|
@@ -194,6 +195,7 @@ const tanstackRouterPlugin = (userConfig = {})=>{
|
|
|
194
195
|
}) : /*#__PURE__*/ jsx(RouterProvider, {
|
|
195
196
|
router: router
|
|
196
197
|
});
|
|
198
|
+
const HydratableRouterContent = wrapTanstackSsrHydrationBoundary(RouterContent, hasSSRBootstrap);
|
|
197
199
|
if (hasSSRBootstrap) hooks.onAfterHydrateRouter.call({
|
|
198
200
|
...lifecycleContext,
|
|
199
201
|
phase: 'hydrate',
|
|
@@ -201,8 +203,8 @@ const tanstackRouterPlugin = (userConfig = {})=>{
|
|
|
201
203
|
runtimeContext: runtimeState
|
|
202
204
|
});
|
|
203
205
|
return App ? /*#__PURE__*/ jsx(App, {
|
|
204
|
-
children:
|
|
205
|
-
}) :
|
|
206
|
+
children: HydratableRouterContent
|
|
207
|
+
}) : HydratableRouterContent;
|
|
206
208
|
};
|
|
207
209
|
return RouterWrapper;
|
|
208
210
|
});
|
|
@@ -9,6 +9,7 @@ import { attachRouterServerSsrUtils } from "@tanstack/router-core/ssr/server";
|
|
|
9
9
|
import { useContext } from "react";
|
|
10
10
|
import { createModernBasepathRewrite } from "./basepathRewrite.mjs";
|
|
11
11
|
import { modifyRoutes, onAfterCreateRouter, onAfterHydrateRouter, onBeforeCreateRouter, onBeforeCreateRoutes, onBeforeHydrateRouter } from "./hooks.mjs";
|
|
12
|
+
import { wrapTanstackSsrHydrationBoundary } from "./hydrationBoundary.mjs";
|
|
12
13
|
import { applyRouterServerPrepareResult, createRouterServerSnapshot } from "./lifecycle.mjs";
|
|
13
14
|
import { createRouteTreeFromRouteObjects, getModernRouteIdsFromMatches } from "./routeTree.mjs";
|
|
14
15
|
import { createTanstackRscServerPayload, handleTanstackRscRedirect } from "./rsc/payloadRouter.mjs";
|
|
@@ -267,9 +268,9 @@ const tanstackRouterPlugin = (userConfig = {})=>{
|
|
|
267
268
|
if (!router) return App ? /*#__PURE__*/ jsx(App, {
|
|
268
269
|
...props
|
|
269
270
|
}) : null;
|
|
270
|
-
const routerWrapper = /*#__PURE__*/ jsx(RouterProvider, {
|
|
271
|
+
const routerWrapper = wrapTanstackSsrHydrationBoundary(/*#__PURE__*/ jsx(RouterProvider, {
|
|
271
272
|
router: router
|
|
272
|
-
});
|
|
273
|
+
}), true);
|
|
273
274
|
return App ? /*#__PURE__*/ jsx(App, {
|
|
274
275
|
children: routerWrapper
|
|
275
276
|
}) : routerWrapper;
|
|
@@ -490,9 +490,11 @@ function createRouteTreeFromRouteObjects(routes, options = {}) {
|
|
|
490
490
|
}
|
|
491
491
|
function getModernRouteIdsFromMatches(router) {
|
|
492
492
|
const matches = router.state.matches || [];
|
|
493
|
+
const routesById = router.routesById;
|
|
493
494
|
const ids = matches.map((match)=>{
|
|
494
|
-
const
|
|
495
|
-
|
|
495
|
+
const normalizedMatch = match;
|
|
496
|
+
const routeId = 'string' == typeof normalizedMatch.routeId ? normalizedMatch.routeId : void 0;
|
|
497
|
+
return normalizedMatch.route?.options?.staticData?.modernRouteId ?? (routeId ? routesById?.[routeId]?.options?.staticData?.modernRouteId : void 0);
|
|
496
498
|
}).filter((id)=>'string' == typeof id);
|
|
497
499
|
return Array.from(new Set(ids));
|
|
498
500
|
}
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
import "node:module";
|
|
2
|
+
import { jsx } from "react/jsx-runtime";
|
|
3
|
+
import { Suspense } from "react";
|
|
4
|
+
function wrapTanstackSsrHydrationBoundary(routerContent, shouldWrap) {
|
|
5
|
+
return shouldWrap ? /*#__PURE__*/ jsx(Suspense, {
|
|
6
|
+
fallback: null,
|
|
7
|
+
children: routerContent
|
|
8
|
+
}) : routerContent;
|
|
9
|
+
}
|
|
10
|
+
export { wrapTanstackSsrHydrationBoundary };
|
|
@@ -8,6 +8,7 @@ import { RouterClient } from "@tanstack/react-router/ssr/client";
|
|
|
8
8
|
import { useContext, useMemo } from "react";
|
|
9
9
|
import { createModernBasepathRewrite } from "./basepathRewrite.mjs";
|
|
10
10
|
import { modifyRoutes, onAfterCreateRouter, onAfterHydrateRouter, onBeforeCreateRouter, onBeforeCreateRoutes, onBeforeHydrateRouter } from "./hooks.mjs";
|
|
11
|
+
import { wrapTanstackSsrHydrationBoundary } from "./hydrationBoundary.mjs";
|
|
11
12
|
import { applyRouterRuntimeState } from "./lifecycle.mjs";
|
|
12
13
|
import { Link } from "./prefetchLink.mjs";
|
|
13
14
|
import { createRouteTreeFromRouteObjects } from "./routeTree.mjs";
|
|
@@ -195,6 +196,7 @@ const tanstackRouterPlugin = (userConfig = {})=>{
|
|
|
195
196
|
}) : /*#__PURE__*/ jsx(RouterProvider, {
|
|
196
197
|
router: router
|
|
197
198
|
});
|
|
199
|
+
const HydratableRouterContent = wrapTanstackSsrHydrationBoundary(RouterContent, hasSSRBootstrap);
|
|
198
200
|
if (hasSSRBootstrap) hooks.onAfterHydrateRouter.call({
|
|
199
201
|
...lifecycleContext,
|
|
200
202
|
phase: 'hydrate',
|
|
@@ -202,8 +204,8 @@ const tanstackRouterPlugin = (userConfig = {})=>{
|
|
|
202
204
|
runtimeContext: runtimeState
|
|
203
205
|
});
|
|
204
206
|
return App ? /*#__PURE__*/ jsx(App, {
|
|
205
|
-
children:
|
|
206
|
-
}) :
|
|
207
|
+
children: HydratableRouterContent
|
|
208
|
+
}) : HydratableRouterContent;
|
|
207
209
|
};
|
|
208
210
|
return RouterWrapper;
|
|
209
211
|
});
|
|
@@ -10,6 +10,7 @@ import { attachRouterServerSsrUtils } from "@tanstack/router-core/ssr/server";
|
|
|
10
10
|
import { useContext } from "react";
|
|
11
11
|
import { createModernBasepathRewrite } from "./basepathRewrite.mjs";
|
|
12
12
|
import { modifyRoutes, onAfterCreateRouter, onAfterHydrateRouter, onBeforeCreateRouter, onBeforeCreateRoutes, onBeforeHydrateRouter } from "./hooks.mjs";
|
|
13
|
+
import { wrapTanstackSsrHydrationBoundary } from "./hydrationBoundary.mjs";
|
|
13
14
|
import { applyRouterServerPrepareResult, createRouterServerSnapshot } from "./lifecycle.mjs";
|
|
14
15
|
import { createRouteTreeFromRouteObjects, getModernRouteIdsFromMatches } from "./routeTree.mjs";
|
|
15
16
|
import { createTanstackRscServerPayload, handleTanstackRscRedirect } from "./rsc/payloadRouter.mjs";
|
|
@@ -268,9 +269,9 @@ const tanstackRouterPlugin = (userConfig = {})=>{
|
|
|
268
269
|
if (!router) return App ? /*#__PURE__*/ jsx(App, {
|
|
269
270
|
...props
|
|
270
271
|
}) : null;
|
|
271
|
-
const routerWrapper = /*#__PURE__*/ jsx(RouterProvider, {
|
|
272
|
+
const routerWrapper = wrapTanstackSsrHydrationBoundary(/*#__PURE__*/ jsx(RouterProvider, {
|
|
272
273
|
router: router
|
|
273
|
-
});
|
|
274
|
+
}), true);
|
|
274
275
|
return App ? /*#__PURE__*/ jsx(App, {
|
|
275
276
|
children: routerWrapper
|
|
276
277
|
}) : routerWrapper;
|
|
@@ -491,9 +491,11 @@ function createRouteTreeFromRouteObjects(routes, options = {}) {
|
|
|
491
491
|
}
|
|
492
492
|
function getModernRouteIdsFromMatches(router) {
|
|
493
493
|
const matches = router.state.matches || [];
|
|
494
|
+
const routesById = router.routesById;
|
|
494
495
|
const ids = matches.map((match)=>{
|
|
495
|
-
const
|
|
496
|
-
|
|
496
|
+
const normalizedMatch = match;
|
|
497
|
+
const routeId = 'string' == typeof normalizedMatch.routeId ? normalizedMatch.routeId : void 0;
|
|
498
|
+
return normalizedMatch.route?.options?.staticData?.modernRouteId ?? (routeId ? routesById?.[routeId]?.options?.staticData?.modernRouteId : void 0);
|
|
497
499
|
}).filter((id)=>'string' == typeof id);
|
|
498
500
|
return Array.from(new Set(ids));
|
|
499
501
|
}
|
package/package.json
CHANGED
|
@@ -18,7 +18,7 @@
|
|
|
18
18
|
"modern.js",
|
|
19
19
|
"tanstack-router"
|
|
20
20
|
],
|
|
21
|
-
"version": "3.2.0-ultramodern.
|
|
21
|
+
"version": "3.2.0-ultramodern.97",
|
|
22
22
|
"engines": {
|
|
23
23
|
"node": ">=20"
|
|
24
24
|
},
|
|
@@ -88,13 +88,13 @@
|
|
|
88
88
|
"@swc/helpers": "^0.5.23",
|
|
89
89
|
"@tanstack/react-router": "1.170.11",
|
|
90
90
|
"@tanstack/router-core": "1.171.9",
|
|
91
|
-
"@modern-js/plugin": "npm:@bleedingdev/modern-js-plugin@3.2.0-ultramodern.
|
|
92
|
-
"@modern-js/
|
|
93
|
-
"@modern-js/
|
|
94
|
-
"@modern-js/utils": "npm:@bleedingdev/modern-js-utils@3.2.0-ultramodern.
|
|
91
|
+
"@modern-js/plugin": "npm:@bleedingdev/modern-js-plugin@3.2.0-ultramodern.97",
|
|
92
|
+
"@modern-js/runtime-utils": "npm:@bleedingdev/modern-js-runtime-utils@3.2.0-ultramodern.97",
|
|
93
|
+
"@modern-js/types": "npm:@bleedingdev/modern-js-types@3.2.0-ultramodern.97",
|
|
94
|
+
"@modern-js/utils": "npm:@bleedingdev/modern-js-utils@3.2.0-ultramodern.97"
|
|
95
95
|
},
|
|
96
96
|
"peerDependencies": {
|
|
97
|
-
"@modern-js/runtime": "3.2.0-ultramodern.
|
|
97
|
+
"@modern-js/runtime": "3.2.0-ultramodern.97",
|
|
98
98
|
"react": "^19.2.6",
|
|
99
99
|
"react-dom": "^19.2.6"
|
|
100
100
|
},
|
|
@@ -109,8 +109,8 @@
|
|
|
109
109
|
"@typescript/native-preview": "7.0.0-dev.20260527.2",
|
|
110
110
|
"react": "^19.2.6",
|
|
111
111
|
"react-dom": "^19.2.6",
|
|
112
|
-
"@modern-js/app-tools": "npm:@bleedingdev/modern-js-app-tools@3.2.0-ultramodern.
|
|
113
|
-
"@modern-js/runtime": "npm:@bleedingdev/modern-js-runtime@3.2.0-ultramodern.
|
|
112
|
+
"@modern-js/app-tools": "npm:@bleedingdev/modern-js-app-tools@3.2.0-ultramodern.97",
|
|
113
|
+
"@modern-js/runtime": "npm:@bleedingdev/modern-js-runtime@3.2.0-ultramodern.97",
|
|
114
114
|
"@scripts/rstest-config": "2.66.0"
|
|
115
115
|
},
|
|
116
116
|
"sideEffects": false,
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
import { type ReactElement, Suspense } from 'react';
|
|
2
|
+
|
|
3
|
+
export function wrapTanstackSsrHydrationBoundary(
|
|
4
|
+
routerContent: ReactElement,
|
|
5
|
+
shouldWrap: boolean,
|
|
6
|
+
) {
|
|
7
|
+
return shouldWrap ? (
|
|
8
|
+
<Suspense fallback={null}>{routerContent}</Suspense>
|
|
9
|
+
) : (
|
|
10
|
+
routerContent
|
|
11
|
+
);
|
|
12
|
+
}
|
|
@@ -39,6 +39,7 @@ import {
|
|
|
39
39
|
onBeforeHydrateRouter as onBeforeHydrateRouterHook,
|
|
40
40
|
type RouterExtendsHooks,
|
|
41
41
|
} from './hooks';
|
|
42
|
+
import { wrapTanstackSsrHydrationBoundary } from './hydrationBoundary';
|
|
42
43
|
import {
|
|
43
44
|
applyRouterServerPrepareResult,
|
|
44
45
|
createRouterServerSnapshot,
|
|
@@ -564,8 +565,9 @@ export const tanstackRouterPlugin = (
|
|
|
564
565
|
return App ? <App {...props} /> : null;
|
|
565
566
|
}
|
|
566
567
|
|
|
567
|
-
const routerWrapper = (
|
|
568
|
-
<RouterProvider router={router as AnyRouter}
|
|
568
|
+
const routerWrapper = wrapTanstackSsrHydrationBoundary(
|
|
569
|
+
<RouterProvider router={router as AnyRouter} />,
|
|
570
|
+
true,
|
|
569
571
|
);
|
|
570
572
|
|
|
571
573
|
return App ? <App>{routerWrapper}</App> : routerWrapper;
|
package/src/runtime/plugin.tsx
CHANGED
|
@@ -36,6 +36,7 @@ import {
|
|
|
36
36
|
onBeforeHydrateRouter as onBeforeHydrateRouterHook,
|
|
37
37
|
type RouterExtendsHooks,
|
|
38
38
|
} from './hooks';
|
|
39
|
+
import { wrapTanstackSsrHydrationBoundary } from './hydrationBoundary';
|
|
39
40
|
import {
|
|
40
41
|
applyRouterRuntimeState,
|
|
41
42
|
type RouterLifecycleContext,
|
|
@@ -377,6 +378,10 @@ export const tanstackRouterPlugin = (
|
|
|
377
378
|
) : (
|
|
378
379
|
<RouterProvider router={router} />
|
|
379
380
|
);
|
|
381
|
+
const HydratableRouterContent = wrapTanstackSsrHydrationBoundary(
|
|
382
|
+
RouterContent,
|
|
383
|
+
hasSSRBootstrap,
|
|
384
|
+
);
|
|
380
385
|
if (hasSSRBootstrap) {
|
|
381
386
|
hooks.onAfterHydrateRouter.call({
|
|
382
387
|
...lifecycleContext,
|
|
@@ -386,7 +391,11 @@ export const tanstackRouterPlugin = (
|
|
|
386
391
|
});
|
|
387
392
|
}
|
|
388
393
|
|
|
389
|
-
return App ?
|
|
394
|
+
return App ? (
|
|
395
|
+
<App>{HydratableRouterContent}</App>
|
|
396
|
+
) : (
|
|
397
|
+
HydratableRouterContent
|
|
398
|
+
);
|
|
390
399
|
};
|
|
391
400
|
|
|
392
401
|
return RouterWrapper;
|
package/src/runtime/routeTree.ts
CHANGED
|
@@ -1038,18 +1038,38 @@ export function createRouteTreeFromRouteObjects(
|
|
|
1038
1038
|
|
|
1039
1039
|
export function getModernRouteIdsFromMatches(router: AnyRouter): string[] {
|
|
1040
1040
|
const matches = router.state.matches || [];
|
|
1041
|
+
const routesById = (
|
|
1042
|
+
router as AnyRouter & {
|
|
1043
|
+
routesById?: Record<
|
|
1044
|
+
string,
|
|
1045
|
+
{
|
|
1046
|
+
options?: {
|
|
1047
|
+
staticData?: { modernRouteId?: unknown };
|
|
1048
|
+
};
|
|
1049
|
+
}
|
|
1050
|
+
>;
|
|
1051
|
+
}
|
|
1052
|
+
).routesById;
|
|
1041
1053
|
const ids = matches
|
|
1042
1054
|
.map(match => {
|
|
1043
|
-
const
|
|
1044
|
-
|
|
1045
|
-
|
|
1046
|
-
|
|
1047
|
-
staticData?: { modernRouteId?: unknown };
|
|
1048
|
-
};
|
|
1055
|
+
const normalizedMatch = match as {
|
|
1056
|
+
route?: {
|
|
1057
|
+
options?: {
|
|
1058
|
+
staticData?: { modernRouteId?: unknown };
|
|
1049
1059
|
};
|
|
1050
|
-
}
|
|
1051
|
-
|
|
1052
|
-
|
|
1060
|
+
};
|
|
1061
|
+
routeId?: unknown;
|
|
1062
|
+
};
|
|
1063
|
+
const routeId =
|
|
1064
|
+
typeof normalizedMatch.routeId === 'string'
|
|
1065
|
+
? normalizedMatch.routeId
|
|
1066
|
+
: undefined;
|
|
1067
|
+
return (
|
|
1068
|
+
normalizedMatch.route?.options?.staticData?.modernRouteId ??
|
|
1069
|
+
(routeId
|
|
1070
|
+
? routesById?.[routeId]?.options?.staticData?.modernRouteId
|
|
1071
|
+
: undefined)
|
|
1072
|
+
);
|
|
1053
1073
|
})
|
|
1054
1074
|
.filter((id): id is string => typeof id === 'string');
|
|
1055
1075
|
return Array.from(new Set(ids));
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
import { isValidElement, Suspense } from 'react';
|
|
2
|
+
import { wrapTanstackSsrHydrationBoundary } from '../../src/runtime/hydrationBoundary';
|
|
3
|
+
|
|
4
|
+
describe('tanstack SSR hydration boundary', () => {
|
|
5
|
+
it('wraps SSR hydration content in a Suspense boundary', () => {
|
|
6
|
+
const routerContent = <main data-testid="router" />;
|
|
7
|
+
|
|
8
|
+
const wrapped = wrapTanstackSsrHydrationBoundary(routerContent, true);
|
|
9
|
+
|
|
10
|
+
expect(isValidElement(wrapped)).toBe(true);
|
|
11
|
+
expect(wrapped.type).toBe(Suspense);
|
|
12
|
+
expect(wrapped.props.fallback).toBe(null);
|
|
13
|
+
expect(wrapped.props.children).toBe(routerContent);
|
|
14
|
+
});
|
|
15
|
+
|
|
16
|
+
it('keeps non-SSR router content unwrapped', () => {
|
|
17
|
+
const routerContent = <main data-testid="router" />;
|
|
18
|
+
|
|
19
|
+
expect(wrapTanstackSsrHydrationBoundary(routerContent, false)).toBe(
|
|
20
|
+
routerContent,
|
|
21
|
+
);
|
|
22
|
+
});
|
|
23
|
+
});
|
|
@@ -8,6 +8,7 @@ import { renderToStaticMarkup } from 'react-dom/server';
|
|
|
8
8
|
import {
|
|
9
9
|
createRouteTreeFromModernRoutes,
|
|
10
10
|
createRouteTreeFromRouteObjects,
|
|
11
|
+
getModernRouteIdsFromMatches,
|
|
11
12
|
} from '../../src/runtime/routeTree';
|
|
12
13
|
import { __setTanstackRscPayloadDecoderForTests } from '../../src/runtime/rsc/payloadRouter';
|
|
13
14
|
import { createRouteObjectsFromConfig } from '../../src/runtime/utils';
|
|
@@ -181,6 +182,58 @@ describe('tanstack route tree from RouteObject[]', () => {
|
|
|
181
182
|
).toBeUndefined();
|
|
182
183
|
});
|
|
183
184
|
|
|
185
|
+
test('resolves matched Modern route ids from TanStack route registry fallback', () => {
|
|
186
|
+
const router = {
|
|
187
|
+
state: {
|
|
188
|
+
matches: [
|
|
189
|
+
{ routeId: '__root__' },
|
|
190
|
+
{ routeId: '/$lang' },
|
|
191
|
+
{ routeId: '/$lang/tractors' },
|
|
192
|
+
{
|
|
193
|
+
route: {
|
|
194
|
+
options: {
|
|
195
|
+
staticData: {
|
|
196
|
+
modernRouteId: '(lang)/stores/page',
|
|
197
|
+
},
|
|
198
|
+
},
|
|
199
|
+
},
|
|
200
|
+
routeId: '/$lang/stores',
|
|
201
|
+
},
|
|
202
|
+
],
|
|
203
|
+
},
|
|
204
|
+
routesById: {
|
|
205
|
+
__root__: {
|
|
206
|
+
options: {
|
|
207
|
+
staticData: {
|
|
208
|
+
modernRouteId: 'layout',
|
|
209
|
+
},
|
|
210
|
+
},
|
|
211
|
+
},
|
|
212
|
+
'/$lang': {
|
|
213
|
+
options: {
|
|
214
|
+
staticData: {
|
|
215
|
+
modernRouteId: '(lang)/page',
|
|
216
|
+
},
|
|
217
|
+
},
|
|
218
|
+
},
|
|
219
|
+
'/$lang/tractors': {
|
|
220
|
+
options: {
|
|
221
|
+
staticData: {
|
|
222
|
+
modernRouteId: '(lang)/tractors/page',
|
|
223
|
+
},
|
|
224
|
+
},
|
|
225
|
+
},
|
|
226
|
+
},
|
|
227
|
+
};
|
|
228
|
+
|
|
229
|
+
expect(getModernRouteIdsFromMatches(router as never)).toEqual([
|
|
230
|
+
'layout',
|
|
231
|
+
'(lang)/page',
|
|
232
|
+
'(lang)/tractors/page',
|
|
233
|
+
'(lang)/stores/page',
|
|
234
|
+
]);
|
|
235
|
+
});
|
|
236
|
+
|
|
184
237
|
test('preserves TanStack search contracts from RouteObject routes', () => {
|
|
185
238
|
const rootValidateSearch = (search: unknown) => ({ root: search });
|
|
186
239
|
const rootLoaderDeps = ({ search }: { search: unknown }) => ({ search });
|