@bleedingdev/modern-js-plugin-tanstack 3.2.0-ultramodern.12 → 3.2.0-ultramodern.120
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/cjs/cli/index.js +47 -9
- package/dist/cjs/cli/routeSplitting.js +87 -0
- package/dist/cjs/cli/tanstackTypes.js +230 -63
- package/dist/cjs/cli.js +12 -8
- package/dist/cjs/runtime/DefaultNotFound.js +9 -5
- package/dist/cjs/runtime/basepathRewrite.js +12 -8
- package/dist/cjs/runtime/dataMutation.js +9 -5
- package/dist/cjs/runtime/hooks.js +9 -5
- package/dist/cjs/runtime/hydrationBoundary.js +48 -0
- package/dist/cjs/runtime/index.js +330 -74
- package/dist/cjs/runtime/lifecycle.js +15 -11
- package/dist/cjs/runtime/outlet.js +58 -0
- package/dist/cjs/runtime/plugin.js +203 -98
- package/dist/cjs/runtime/plugin.node.js +38 -16
- package/dist/cjs/runtime/plugin.worker.js +53 -0
- package/dist/cjs/runtime/prefetchLink.js +10 -6
- package/dist/cjs/runtime/routeTree.js +81 -17
- package/dist/cjs/runtime/rsc/ClientSlot.js +9 -5
- package/dist/cjs/runtime/rsc/CompositeComponent.js +9 -5
- package/dist/cjs/runtime/rsc/ReplayableStream.js +14 -9
- package/dist/cjs/runtime/rsc/RscNodeRenderer.js +9 -5
- package/dist/cjs/runtime/rsc/SlotContext.js +9 -5
- package/dist/cjs/runtime/rsc/client.js +9 -5
- package/dist/cjs/runtime/rsc/createRscProxy.js +9 -5
- package/dist/cjs/runtime/rsc/index.js +9 -5
- package/dist/cjs/runtime/rsc/payloadRouter.js +9 -5
- package/dist/cjs/runtime/rsc/server.js +9 -5
- package/dist/cjs/runtime/rsc/slotUsageSanitizer.js +9 -5
- package/dist/cjs/runtime/rsc/symbols.js +20 -15
- package/dist/cjs/runtime/types.js +31 -1
- package/dist/cjs/runtime/utils.js +9 -5
- package/dist/cjs/runtime.js +9 -5
- package/dist/esm/cli/index.mjs +28 -6
- package/dist/esm/cli/routeSplitting.mjs +43 -0
- package/dist/esm/cli/tanstackTypes.mjs +219 -59
- package/dist/esm/runtime/hydrationBoundary.mjs +10 -0
- package/dist/esm/runtime/index.mjs +3 -2
- package/dist/esm/runtime/outlet.mjs +17 -0
- package/dist/esm/runtime/plugin.mjs +197 -96
- package/dist/esm/runtime/plugin.node.mjs +30 -12
- package/dist/esm/runtime/plugin.worker.mjs +1 -0
- package/dist/esm/runtime/prefetchLink.mjs +1 -1
- package/dist/esm/runtime/routeTree.mjs +73 -13
- package/dist/esm/runtime/types.mjs +7 -0
- package/dist/esm-node/cli/index.mjs +28 -6
- package/dist/esm-node/cli/routeSplitting.mjs +44 -0
- package/dist/esm-node/cli/tanstackTypes.mjs +219 -59
- package/dist/esm-node/runtime/hydrationBoundary.mjs +11 -0
- package/dist/esm-node/runtime/index.mjs +3 -2
- package/dist/esm-node/runtime/outlet.mjs +18 -0
- package/dist/esm-node/runtime/plugin.mjs +197 -96
- package/dist/esm-node/runtime/plugin.node.mjs +30 -12
- package/dist/esm-node/runtime/plugin.worker.mjs +2 -0
- package/dist/esm-node/runtime/prefetchLink.mjs +1 -1
- package/dist/esm-node/runtime/routeTree.mjs +73 -13
- package/dist/esm-node/runtime/types.mjs +7 -0
- package/dist/types/cli/index.d.ts +7 -1
- package/dist/types/cli/routeSplitting.d.ts +29 -0
- package/dist/types/cli/tanstackTypes.d.ts +9 -0
- package/dist/types/runtime/hooks.d.ts +9 -24
- package/dist/types/runtime/hydrationBoundary.d.ts +2 -0
- package/dist/types/runtime/index.d.ts +5 -2
- package/dist/types/runtime/outlet.d.ts +2 -0
- package/dist/types/runtime/plugin.d.ts +1 -1
- package/dist/types/runtime/plugin.node.d.ts +1 -1
- package/dist/types/runtime/plugin.worker.d.ts +1 -0
- package/dist/types/runtime/types.d.ts +7 -0
- package/package.json +20 -20
- package/src/cli/index.ts +59 -2
- package/src/cli/routeSplitting.ts +81 -0
- package/src/cli/tanstackTypes.ts +347 -67
- package/src/runtime/hydrationBoundary.tsx +12 -0
- package/src/runtime/index.tsx +107 -2
- package/src/runtime/outlet.tsx +48 -0
- package/src/runtime/plugin.node.tsx +58 -8
- package/src/runtime/plugin.tsx +372 -157
- package/src/runtime/plugin.worker.tsx +4 -0
- package/src/runtime/prefetchLink.tsx +1 -1
- package/src/runtime/routeTree.ts +194 -23
- package/src/runtime/ssr-shim.d.ts +1 -3
- package/src/runtime/types.ts +13 -0
- package/tests/router/cli.test.ts +315 -0
- package/tests/router/fastDefaults.test.ts +25 -0
- package/tests/router/hydrationBoundary.test.tsx +23 -0
- package/tests/router/prefetchLink.test.tsx +43 -7
- package/tests/router/routeTree.test.ts +416 -1
- package/tests/router/tanstackTypes.test.ts +415 -1
|
@@ -4,14 +4,18 @@ import { InternalRuntimeContext, getGlobalEnableRsc, getGlobalLayoutApp, getGlob
|
|
|
4
4
|
import { merge } from "@modern-js/runtime-utils/merge";
|
|
5
5
|
import { normalizePathname } from "@modern-js/runtime-utils/url";
|
|
6
6
|
import { RouterProvider, createBrowserHistory, createHashHistory, createRouter, useLocation, useMatches, useNavigate, useRouter } from "@tanstack/react-router";
|
|
7
|
-
import {
|
|
7
|
+
import { hydrate } from "@tanstack/react-router/ssr/client";
|
|
8
|
+
import { useContext, useMemo } from "react";
|
|
8
9
|
import { createModernBasepathRewrite } from "./basepathRewrite.mjs";
|
|
9
10
|
import { modifyRoutes, onAfterCreateRouter, onAfterHydrateRouter, onBeforeCreateRouter, onBeforeCreateRoutes, onBeforeHydrateRouter } from "./hooks.mjs";
|
|
11
|
+
import { wrapTanstackSsrHydrationBoundary } from "./hydrationBoundary.mjs";
|
|
10
12
|
import { applyRouterRuntimeState } from "./lifecycle.mjs";
|
|
13
|
+
import { withModernRouteMatchContext } from "./outlet.mjs";
|
|
14
|
+
import { Link } from "./prefetchLink.mjs";
|
|
11
15
|
import { createRouteTreeFromRouteObjects } from "./routeTree.mjs";
|
|
12
16
|
import { getTanstackRscSerializationAdapters } from "./rsc/client.mjs";
|
|
17
|
+
import { getModernTanstackRouterFastDefaults } from "./types.mjs";
|
|
13
18
|
import { createRouteObjectsFromConfig, urlJoin } from "./utils.mjs";
|
|
14
|
-
import * as __rspack_external_react from "react";
|
|
15
19
|
const BLOCKING_SUBSCRIBE_SYMBOL = Symbol.for('@modern-js/plugin-tanstack:blocking-subscribe');
|
|
16
20
|
const BLOCKING_STATE_SYMBOL = Symbol.for('@modern-js/plugin-tanstack:blocking-state');
|
|
17
21
|
function normalizeBase(b) {
|
|
@@ -39,6 +43,82 @@ function wrapRouterSubscribeWithBlockState(router, getBlockNavState) {
|
|
|
39
43
|
};
|
|
40
44
|
target[BLOCKING_SUBSCRIBE_SYMBOL] = true;
|
|
41
45
|
}
|
|
46
|
+
const routerHydrationRecords = new WeakMap();
|
|
47
|
+
const routeModulesKey = '_routeModules';
|
|
48
|
+
function pickRouteModuleComponent(routeModule, seen = new Set()) {
|
|
49
|
+
if ('function' == typeof routeModule || routeModule && 'object' == typeof routeModule && '$$typeof' in routeModule) return routeModule;
|
|
50
|
+
if (!routeModule || 'object' != typeof routeModule) return;
|
|
51
|
+
if (seen.has(routeModule)) return;
|
|
52
|
+
seen.add(routeModule);
|
|
53
|
+
const module = routeModule;
|
|
54
|
+
for (const candidate of [
|
|
55
|
+
module.default,
|
|
56
|
+
module.Component
|
|
57
|
+
]){
|
|
58
|
+
const component = pickRouteModuleComponent(candidate, seen);
|
|
59
|
+
if (component) return component;
|
|
60
|
+
}
|
|
61
|
+
}
|
|
62
|
+
function getCachedRouteModule(routeId) {
|
|
63
|
+
if ("u" < typeof window) return;
|
|
64
|
+
return window[routeModulesKey]?.[routeId];
|
|
65
|
+
}
|
|
66
|
+
function preloadHydratedRouteComponents(router) {
|
|
67
|
+
const preloadableRouter = router;
|
|
68
|
+
const routesById = preloadableRouter.routesById || {};
|
|
69
|
+
const matches = preloadableRouter.stores.matches.get();
|
|
70
|
+
return Promise.all(matches.map((match)=>{
|
|
71
|
+
if (void 0 === match.routeId || '' === match.routeId) return;
|
|
72
|
+
const route = routesById[match.routeId];
|
|
73
|
+
const component = route?.options?.component;
|
|
74
|
+
const preload = component?.load || component?.preload;
|
|
75
|
+
if ('function' != typeof preload) return;
|
|
76
|
+
return Promise.resolve(preload.call(component)).then((routeModule)=>{
|
|
77
|
+
const modernRouteId = route?.options?.staticData?.modernRouteId;
|
|
78
|
+
const cachedRouteModule = 'string' == typeof modernRouteId && '' !== modernRouteId ? getCachedRouteModule(modernRouteId) : void 0;
|
|
79
|
+
const resolvedComponent = pickRouteModuleComponent(cachedRouteModule ?? routeModule);
|
|
80
|
+
if (void 0 !== resolvedComponent && 'string' == typeof modernRouteId && '' !== modernRouteId) route.options.component = withModernRouteMatchContext(resolvedComponent, modernRouteId);
|
|
81
|
+
});
|
|
82
|
+
})).then(()=>void 0);
|
|
83
|
+
}
|
|
84
|
+
function getTanstackSsrHydrationRecord(router) {
|
|
85
|
+
const existingHydrationRecord = routerHydrationRecords.get(router);
|
|
86
|
+
if (void 0 !== existingHydrationRecord) return existingHydrationRecord;
|
|
87
|
+
const hydrationRecord = {
|
|
88
|
+
promise: Promise.resolve(),
|
|
89
|
+
status: 'pending'
|
|
90
|
+
};
|
|
91
|
+
routerHydrationRecords.set(router, hydrationRecord);
|
|
92
|
+
try {
|
|
93
|
+
hydrationRecord.promise = hydrate(router).then((value)=>preloadHydratedRouteComponents(router).then(()=>value)).then((value)=>{
|
|
94
|
+
hydrationRecord.status = 'fulfilled';
|
|
95
|
+
return value;
|
|
96
|
+
}, (error)=>{
|
|
97
|
+
hydrationRecord.status = 'rejected';
|
|
98
|
+
hydrationRecord.error = error;
|
|
99
|
+
throw error;
|
|
100
|
+
});
|
|
101
|
+
} catch (error) {
|
|
102
|
+
hydrationRecord.status = 'rejected';
|
|
103
|
+
hydrationRecord.error = error;
|
|
104
|
+
hydrationRecord.promise = Promise.reject(error);
|
|
105
|
+
hydrationRecord.promise.catch(()=>{});
|
|
106
|
+
}
|
|
107
|
+
return hydrationRecord;
|
|
108
|
+
}
|
|
109
|
+
function getTanstackSsrHydrationPromise(router) {
|
|
110
|
+
return getTanstackSsrHydrationRecord(router).promise;
|
|
111
|
+
}
|
|
112
|
+
function hasTanstackSsrHydrationRecord(router) {
|
|
113
|
+
return routerHydrationRecords.has(router);
|
|
114
|
+
}
|
|
115
|
+
function ModernRouterClient({ router }) {
|
|
116
|
+
const hydrationRecord = getTanstackSsrHydrationRecord(router);
|
|
117
|
+
if ('rejected' === hydrationRecord.status) throw hydrationRecord.error;
|
|
118
|
+
return /*#__PURE__*/ jsx(RouterProvider, {
|
|
119
|
+
router: router
|
|
120
|
+
});
|
|
121
|
+
}
|
|
42
122
|
function stripSyntheticNotFoundRoute(routes) {
|
|
43
123
|
return routes.filter((route)=>!('*' === route.path && !route.id && !route.loader)).map((route)=>{
|
|
44
124
|
if (!route.children?.length) return route;
|
|
@@ -60,112 +140,134 @@ const tanstackRouterPlugin = (userConfig = {})=>{
|
|
|
60
140
|
onBeforeHydrateRouter: onBeforeHydrateRouter
|
|
61
141
|
},
|
|
62
142
|
setup: (api)=>{
|
|
63
|
-
api.
|
|
143
|
+
const hooks = api.getHooks();
|
|
144
|
+
let cachedRouteObjects;
|
|
145
|
+
let cachedRouteTree = null;
|
|
146
|
+
let cachedRouter = null;
|
|
147
|
+
let cachedRouterBasepath = null;
|
|
148
|
+
const getMergedConfig = ()=>{
|
|
64
149
|
const pluginConfig = api.getRuntimeConfig();
|
|
65
|
-
|
|
66
|
-
|
|
150
|
+
return merge(pluginConfig.router || {}, userConfig);
|
|
151
|
+
};
|
|
152
|
+
const getRouteObjects = ()=>{
|
|
153
|
+
if (void 0 !== cachedRouteObjects) return cachedRouteObjects;
|
|
154
|
+
const mergedConfig = getMergedConfig();
|
|
155
|
+
const { routesConfig, createRoutes } = mergedConfig;
|
|
156
|
+
const finalRouteConfig = {
|
|
157
|
+
routes: getGlobalRoutes(),
|
|
158
|
+
globalApp: getGlobalLayoutApp(),
|
|
159
|
+
...routesConfig
|
|
160
|
+
};
|
|
161
|
+
const routeObjects = createRoutes ? createRoutes() : createRouteObjectsFromConfig({
|
|
162
|
+
routesConfig: finalRouteConfig
|
|
163
|
+
}) || [];
|
|
164
|
+
const normalizedRouteObjects = createRoutes ? routeObjects : stripSyntheticNotFoundRoute(routeObjects);
|
|
165
|
+
cachedRouteObjects = hooks.modifyRoutes.call(normalizedRouteObjects);
|
|
166
|
+
return cachedRouteObjects;
|
|
167
|
+
};
|
|
168
|
+
const getRouteTree = ()=>{
|
|
169
|
+
if (cachedRouteTree) return cachedRouteTree;
|
|
170
|
+
const routeObjects = getRouteObjects();
|
|
171
|
+
if (!routeObjects.length) return null;
|
|
172
|
+
cachedRouteTree = createRouteTreeFromRouteObjects(routeObjects, {
|
|
173
|
+
rscPayloadRouter: getGlobalEnableRsc()
|
|
174
|
+
});
|
|
175
|
+
return cachedRouteTree;
|
|
176
|
+
};
|
|
177
|
+
const selectBasePath = (pathname)=>{
|
|
178
|
+
const { serverBase = [] } = getMergedConfig();
|
|
179
|
+
const match = serverBase.find((baseUrl)=>isSegmentPrefix(pathname, baseUrl));
|
|
180
|
+
return match || '/';
|
|
181
|
+
};
|
|
182
|
+
const getClientBasename = (runtimeContext)=>{
|
|
183
|
+
const { basename = '' } = getMergedConfig();
|
|
184
|
+
const baseUrl = selectBasePath(location.pathname).replace(/^\/*/, '/');
|
|
185
|
+
return '/' === baseUrl ? urlJoin(baseUrl, runtimeContext._internalRouterBaseName || basename || '') : baseUrl;
|
|
186
|
+
};
|
|
187
|
+
const getRouter = (runtimeContext, _basename)=>{
|
|
188
|
+
const routeTree = getRouteTree();
|
|
189
|
+
if (!routeTree) return null;
|
|
190
|
+
const lifecycleContext = {
|
|
191
|
+
framework: 'tanstack',
|
|
192
|
+
phase: 'client-create',
|
|
193
|
+
routes: getRouteObjects(),
|
|
194
|
+
runtimeContext,
|
|
195
|
+
basename: _basename
|
|
196
|
+
};
|
|
197
|
+
hooks.onBeforeCreateRouter.call(lifecycleContext);
|
|
198
|
+
if (cachedRouter && cachedRouterBasepath === _basename) {
|
|
199
|
+
wrapRouterSubscribeWithBlockState(cachedRouter, runtimeContext.unstable_getBlockNavState);
|
|
200
|
+
hooks.onAfterCreateRouter.call({
|
|
201
|
+
...lifecycleContext,
|
|
202
|
+
router: cachedRouter,
|
|
203
|
+
runtimeContext
|
|
204
|
+
});
|
|
205
|
+
return cachedRouter;
|
|
206
|
+
}
|
|
207
|
+
const mergedConfig = getMergedConfig();
|
|
208
|
+
const { supportHtml5History = true } = mergedConfig;
|
|
209
|
+
const history = supportHtml5History ? createBrowserHistory() : createHashHistory();
|
|
210
|
+
const rewrite = createModernBasepathRewrite(_basename);
|
|
211
|
+
const serializationAdapters = getGlobalEnableRsc() ? getTanstackRscSerializationAdapters() : void 0;
|
|
212
|
+
cachedRouter = createRouter({
|
|
213
|
+
...getModernTanstackRouterFastDefaults(mergedConfig),
|
|
214
|
+
routeTree,
|
|
215
|
+
basepath: '/',
|
|
216
|
+
rewrite,
|
|
217
|
+
history,
|
|
218
|
+
context: {},
|
|
219
|
+
...serializationAdapters ? {
|
|
220
|
+
serializationAdapters
|
|
221
|
+
} : {}
|
|
222
|
+
});
|
|
223
|
+
cachedRouterBasepath = _basename;
|
|
224
|
+
wrapRouterSubscribeWithBlockState(cachedRouter, runtimeContext.unstable_getBlockNavState);
|
|
225
|
+
hooks.onAfterCreateRouter.call({
|
|
226
|
+
...lifecycleContext,
|
|
227
|
+
router: cachedRouter,
|
|
228
|
+
runtimeContext
|
|
229
|
+
});
|
|
230
|
+
return cachedRouter;
|
|
231
|
+
};
|
|
232
|
+
api.onBeforeRender((context)=>{
|
|
233
|
+
const mergedConfig = getMergedConfig();
|
|
234
|
+
if ("u" > typeof window && void 0 !== window._SSR_DATA && mergedConfig.unstable_reloadOnURLMismatch) {
|
|
67
235
|
const { ssrContext } = context;
|
|
68
236
|
const currentPathname = normalizePathname(window.location.pathname);
|
|
69
|
-
const initialPathname = ssrContext?.request?.pathname
|
|
70
|
-
if (initialPathname && initialPathname !== currentPathname) {
|
|
237
|
+
const initialPathname = 'string' == typeof ssrContext?.request?.pathname ? normalizePathname(ssrContext.request.pathname) : void 0;
|
|
238
|
+
if (void 0 !== initialPathname && '' !== initialPathname && initialPathname !== currentPathname) {
|
|
71
239
|
const errorMsg = `The initial URL ${initialPathname} and the URL ${currentPathname} to be hydrated do not match, reload.`;
|
|
72
240
|
console.error(errorMsg);
|
|
73
241
|
window.location.reload();
|
|
74
242
|
}
|
|
75
243
|
}
|
|
76
244
|
context.router = {
|
|
245
|
+
Link: Link,
|
|
77
246
|
useMatches: useMatches,
|
|
78
247
|
useLocation: useLocation,
|
|
79
248
|
useNavigate: useNavigate,
|
|
80
249
|
useRouter: useRouter
|
|
81
250
|
};
|
|
251
|
+
const hasSSRBootstrap = "u" > typeof window && Boolean(window.$_TSR);
|
|
252
|
+
if (hasSSRBootstrap && getRouteObjects().length > 0) {
|
|
253
|
+
const runtimeContext = context;
|
|
254
|
+
const router = getRouter(runtimeContext, getClientBasename(runtimeContext));
|
|
255
|
+
if (null != router) return getTanstackSsrHydrationPromise(router).then(()=>void 0);
|
|
256
|
+
}
|
|
82
257
|
});
|
|
83
258
|
api.wrapRoot((App)=>{
|
|
84
|
-
|
|
85
|
-
const { serverBase = [], supportHtml5History = true, basename = '', routesConfig, createRoutes } = mergedConfig;
|
|
86
|
-
const finalRouteConfig = {
|
|
87
|
-
routes: getGlobalRoutes(),
|
|
88
|
-
globalApp: getGlobalLayoutApp(),
|
|
89
|
-
...routesConfig
|
|
90
|
-
};
|
|
91
|
-
if (!finalRouteConfig.routes && !createRoutes) return App;
|
|
92
|
-
const hooks = api.getHooks();
|
|
93
|
-
let cachedRouteObjects;
|
|
94
|
-
const getRouteObjects = ()=>{
|
|
95
|
-
if (void 0 !== cachedRouteObjects) return cachedRouteObjects;
|
|
96
|
-
const routeObjects = createRoutes ? createRoutes() : createRouteObjectsFromConfig({
|
|
97
|
-
routesConfig: finalRouteConfig
|
|
98
|
-
}) || [];
|
|
99
|
-
const normalizedRouteObjects = createRoutes ? routeObjects : stripSyntheticNotFoundRoute(routeObjects);
|
|
100
|
-
cachedRouteObjects = hooks.modifyRoutes.call(normalizedRouteObjects);
|
|
101
|
-
return cachedRouteObjects;
|
|
102
|
-
};
|
|
103
|
-
const selectBasePath = (pathname)=>{
|
|
104
|
-
const match = serverBase.find((baseUrl)=>isSegmentPrefix(pathname, baseUrl));
|
|
105
|
-
return match || '/';
|
|
106
|
-
};
|
|
107
|
-
let cachedRouteTree = null;
|
|
108
|
-
let cachedRouter = null;
|
|
109
|
-
let cachedRouterBasepath = null;
|
|
259
|
+
if (0 === getRouteObjects().length) return App;
|
|
110
260
|
const RouterWrapper = ()=>{
|
|
111
|
-
const runtimeContext =
|
|
112
|
-
const
|
|
113
|
-
const
|
|
114
|
-
const routeTree = (0, __rspack_external_react.useMemo)(()=>{
|
|
115
|
-
if (cachedRouteTree) return cachedRouteTree;
|
|
116
|
-
const routeObjects = getRouteObjects();
|
|
117
|
-
if (!routeObjects.length) return null;
|
|
118
|
-
cachedRouteTree = createRouteTreeFromRouteObjects(routeObjects, {
|
|
119
|
-
rscPayloadRouter: getGlobalEnableRsc()
|
|
120
|
-
});
|
|
121
|
-
return cachedRouteTree;
|
|
122
|
-
}, []);
|
|
261
|
+
const runtimeContext = useContext(InternalRuntimeContext);
|
|
262
|
+
const _basename = getClientBasename(runtimeContext);
|
|
263
|
+
const routeTree = useMemo(()=>getRouteTree(), []);
|
|
123
264
|
if (!routeTree) return App ? /*#__PURE__*/ jsx(App, {}) : null;
|
|
124
|
-
const router =
|
|
125
|
-
const lifecycleContext = {
|
|
126
|
-
framework: 'tanstack',
|
|
127
|
-
phase: 'client-create',
|
|
128
|
-
routes: getRouteObjects(),
|
|
129
|
-
runtimeContext,
|
|
130
|
-
basename: _basename
|
|
131
|
-
};
|
|
132
|
-
hooks.onBeforeCreateRouter.call(lifecycleContext);
|
|
133
|
-
if (cachedRouter && cachedRouterBasepath === _basename) {
|
|
134
|
-
wrapRouterSubscribeWithBlockState(cachedRouter, runtimeContext.unstable_getBlockNavState);
|
|
135
|
-
hooks.onAfterCreateRouter.call({
|
|
136
|
-
...lifecycleContext,
|
|
137
|
-
router: cachedRouter,
|
|
138
|
-
runtimeContext
|
|
139
|
-
});
|
|
140
|
-
return cachedRouter;
|
|
141
|
-
}
|
|
142
|
-
const history = supportHtml5History ? createBrowserHistory() : createHashHistory();
|
|
143
|
-
const rewrite = createModernBasepathRewrite(_basename);
|
|
144
|
-
const serializationAdapters = getGlobalEnableRsc() ? getTanstackRscSerializationAdapters() : void 0;
|
|
145
|
-
cachedRouter = createRouter({
|
|
146
|
-
routeTree,
|
|
147
|
-
basepath: '/',
|
|
148
|
-
rewrite,
|
|
149
|
-
history,
|
|
150
|
-
context: {},
|
|
151
|
-
...serializationAdapters ? {
|
|
152
|
-
serializationAdapters
|
|
153
|
-
} : {}
|
|
154
|
-
});
|
|
155
|
-
cachedRouterBasepath = _basename;
|
|
156
|
-
wrapRouterSubscribeWithBlockState(cachedRouter, runtimeContext.unstable_getBlockNavState);
|
|
157
|
-
hooks.onAfterCreateRouter.call({
|
|
158
|
-
...lifecycleContext,
|
|
159
|
-
router: cachedRouter,
|
|
160
|
-
runtimeContext
|
|
161
|
-
});
|
|
162
|
-
return cachedRouter;
|
|
163
|
-
}, [
|
|
265
|
+
const router = useMemo(()=>getRouter(runtimeContext, _basename), [
|
|
164
266
|
_basename,
|
|
165
267
|
routeTree,
|
|
166
|
-
supportHtml5History,
|
|
167
268
|
runtimeContext
|
|
168
269
|
]);
|
|
270
|
+
if (!router) return App ? /*#__PURE__*/ jsx(App, {}) : null;
|
|
169
271
|
const runtimeState = applyRouterRuntimeState(runtimeContext, {
|
|
170
272
|
framework: 'tanstack',
|
|
171
273
|
basename: _basename,
|
|
@@ -179,30 +281,29 @@ const tanstackRouterPlugin = (userConfig = {})=>{
|
|
|
179
281
|
basename: _basename,
|
|
180
282
|
router
|
|
181
283
|
};
|
|
182
|
-
const hasSSRBootstrap = "u" > typeof window && Boolean(window.$_TSR);
|
|
183
|
-
|
|
284
|
+
const hasSSRBootstrap = "u" > typeof window && (Boolean(window.$_TSR) || hasTanstackSsrHydrationRecord(router));
|
|
285
|
+
const needsRouterClient = hasSSRBootstrap;
|
|
286
|
+
if (needsRouterClient) hooks.onBeforeHydrateRouter.call({
|
|
184
287
|
...lifecycleContext,
|
|
185
288
|
phase: 'hydrate',
|
|
186
289
|
router,
|
|
187
290
|
runtimeContext: runtimeState
|
|
188
291
|
});
|
|
189
|
-
const RouterContent =
|
|
190
|
-
|
|
191
|
-
children: /*#__PURE__*/ jsx(RouterClient, {
|
|
192
|
-
router: router
|
|
193
|
-
})
|
|
292
|
+
const RouterContent = needsRouterClient ? /*#__PURE__*/ jsx(ModernRouterClient, {
|
|
293
|
+
router: router
|
|
194
294
|
}) : /*#__PURE__*/ jsx(RouterProvider, {
|
|
195
295
|
router: router
|
|
196
296
|
});
|
|
197
|
-
|
|
297
|
+
const HydratableRouterContent = wrapTanstackSsrHydrationBoundary(RouterContent, hasSSRBootstrap);
|
|
298
|
+
if (needsRouterClient) hooks.onAfterHydrateRouter.call({
|
|
198
299
|
...lifecycleContext,
|
|
199
300
|
phase: 'hydrate',
|
|
200
301
|
router,
|
|
201
302
|
runtimeContext: runtimeState
|
|
202
303
|
});
|
|
203
304
|
return App ? /*#__PURE__*/ jsx(App, {
|
|
204
|
-
children:
|
|
205
|
-
}) :
|
|
305
|
+
children: HydratableRouterContent
|
|
306
|
+
}) : HydratableRouterContent;
|
|
206
307
|
};
|
|
207
308
|
return RouterWrapper;
|
|
208
309
|
});
|
|
@@ -6,24 +6,42 @@ import { createRequestContext, storage } from "@modern-js/runtime-utils/node";
|
|
|
6
6
|
import { time } from "@modern-js/runtime-utils/time";
|
|
7
7
|
import { LOADER_REPORTER_NAME } from "@modern-js/utils/universal/constants";
|
|
8
8
|
import { RouterProvider, createMemoryHistory, createRouter } from "@tanstack/react-router";
|
|
9
|
-
import { attachRouterServerSsrUtils } from "@tanstack/
|
|
10
|
-
import {
|
|
9
|
+
import { attachRouterServerSsrUtils } from "@tanstack/router-core/ssr/server";
|
|
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";
|
|
17
|
+
import { getModernTanstackRouterFastDefaults } from "./types.mjs";
|
|
16
18
|
import { createRouteObjectsFromConfig, urlJoin } from "./utils.mjs";
|
|
17
19
|
const setTanstackRscServerPayload = (payload)=>{
|
|
18
20
|
const storageContext = storage.useContext?.();
|
|
19
21
|
if (storageContext) storageContext.serverPayload = payload;
|
|
20
22
|
};
|
|
23
|
+
function isPromiseLike(value) {
|
|
24
|
+
return Boolean(value && 'function' == typeof value.then);
|
|
25
|
+
}
|
|
21
26
|
function isPreloadableRouteComponent(component) {
|
|
22
27
|
if (!component || 'function' != typeof component) return false;
|
|
23
28
|
const preloadable = component;
|
|
24
29
|
return 'function' == typeof preloadable.load || 'function' == typeof preloadable.preload;
|
|
25
30
|
}
|
|
31
|
+
function isReactLazyRouteComponent(component) {
|
|
32
|
+
return null != component && 'object' == typeof component && 'function' == typeof component._init && '_payload' in component;
|
|
33
|
+
}
|
|
34
|
+
async function preloadReactLazyRouteComponent(component) {
|
|
35
|
+
try {
|
|
36
|
+
component._init?.(component._payload);
|
|
37
|
+
} catch (thrown) {
|
|
38
|
+
if (!isPromiseLike(thrown)) throw thrown;
|
|
39
|
+
await thrown;
|
|
40
|
+
component._init?.(component._payload);
|
|
41
|
+
}
|
|
42
|
+
}
|
|
26
43
|
async function preloadRouteComponent(component) {
|
|
44
|
+
if (isReactLazyRouteComponent(component)) return void await preloadReactLazyRouteComponent(component);
|
|
27
45
|
if (!isPreloadableRouteComponent(component)) return;
|
|
28
46
|
if ('function' == typeof component.load) return void await component.load({});
|
|
29
47
|
await component.preload?.({});
|
|
@@ -162,6 +180,7 @@ const tanstackRouterPlugin = (userConfig = {})=>{
|
|
|
162
180
|
};
|
|
163
181
|
hooks.onBeforeCreateRouter.call(routerLifecycleContext);
|
|
164
182
|
const tanstackRouter = createRouter({
|
|
183
|
+
...getModernTanstackRouterFastDefaults(mergedConfig),
|
|
165
184
|
routeTree,
|
|
166
185
|
history,
|
|
167
186
|
basepath: '/',
|
|
@@ -207,10 +226,12 @@ const tanstackRouterPlugin = (userConfig = {})=>{
|
|
|
207
226
|
await preloadMatchedRouteComponents(serverRouter);
|
|
208
227
|
context.ssrContext?.response.status(tanstackRouter.state.statusCode);
|
|
209
228
|
await serverRouter.serverSsr?.dehydrate?.();
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
229
|
+
if (isRSCNavigation) {
|
|
230
|
+
await waitForRouterSerialization(serverRouter);
|
|
231
|
+
setTanstackRscServerPayload(createTanstackRscServerPayload(serverRouter, {
|
|
232
|
+
omitClientLoaderData: true
|
|
233
|
+
}));
|
|
234
|
+
}
|
|
214
235
|
const ssrScriptTags = serverRouter.serverSsr?.takeBufferedScripts?.();
|
|
215
236
|
const hydrationScripts = routerManagedTagsToHtml(ssrScriptTags);
|
|
216
237
|
const matchedRouteIds = getModernRouteIdsFromMatches(serverRouter);
|
|
@@ -248,12 +269,9 @@ const tanstackRouterPlugin = (userConfig = {})=>{
|
|
|
248
269
|
if (!router) return App ? /*#__PURE__*/ jsx(App, {
|
|
249
270
|
...props
|
|
250
271
|
}) : null;
|
|
251
|
-
const routerWrapper = /*#__PURE__*/ jsx(
|
|
252
|
-
|
|
253
|
-
|
|
254
|
-
router: router
|
|
255
|
-
})
|
|
256
|
-
});
|
|
272
|
+
const routerWrapper = wrapTanstackSsrHydrationBoundary(/*#__PURE__*/ jsx(RouterProvider, {
|
|
273
|
+
router: router
|
|
274
|
+
}), true);
|
|
257
275
|
return App ? /*#__PURE__*/ jsx(App, {
|
|
258
276
|
children: routerWrapper
|
|
259
277
|
}) : routerWrapper;
|
|
@@ -5,7 +5,7 @@ function resolvePreloadFromPrefetch(prefetch, preload) {
|
|
|
5
5
|
if (void 0 !== preload) return preload;
|
|
6
6
|
if ('none' === prefetch) return false;
|
|
7
7
|
if ('intent' === prefetch || 'render' === prefetch || 'viewport' === prefetch) return prefetch;
|
|
8
|
-
return
|
|
8
|
+
return 'viewport';
|
|
9
9
|
}
|
|
10
10
|
const LinkComponentImpl = (props)=>{
|
|
11
11
|
const { prefetch, preload, ...rest } = props;
|