@bleedingdev/modern-js-plugin-tanstack 3.2.0-ultramodern.10 → 3.2.0-ultramodern.100
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 +12 -0
- package/dist/cjs/cli/routeSplitting.js +83 -0
- package/dist/cjs/cli/tanstackTypes.js +146 -58
- package/dist/cjs/runtime/hydrationBoundary.js +44 -0
- package/dist/cjs/runtime/index.js +321 -69
- package/dist/cjs/runtime/outlet.js +54 -0
- package/dist/cjs/runtime/plugin.js +194 -90
- package/dist/cjs/runtime/plugin.node.js +29 -11
- package/dist/cjs/runtime/plugin.worker.js +49 -0
- package/dist/cjs/runtime/routeTree.js +72 -12
- package/dist/cjs/runtime/types.js +27 -1
- package/dist/esm/cli/index.mjs +4 -1
- package/dist/esm/cli/routeSplitting.mjs +43 -0
- package/dist/esm/cli/tanstackTypes.mjs +146 -58
- 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 -93
- package/dist/esm/runtime/plugin.node.mjs +30 -12
- package/dist/esm/runtime/plugin.worker.mjs +1 -0
- package/dist/esm/runtime/routeTree.mjs +73 -13
- package/dist/esm/runtime/types.mjs +7 -0
- package/dist/esm-node/cli/index.mjs +4 -1
- package/dist/esm-node/cli/routeSplitting.mjs +44 -0
- package/dist/esm-node/cli/tanstackTypes.mjs +146 -58
- 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 -93
- 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/routeTree.mjs +73 -13
- package/dist/esm-node/runtime/types.mjs +7 -0
- package/dist/types/cli/index.d.ts +4 -0
- package/dist/types/cli/routeSplitting.d.ts +29 -0
- 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 +15 -15
- package/src/cli/index.ts +17 -0
- package/src/cli/routeSplitting.ts +81 -0
- package/src/cli/tanstackTypes.ts +216 -67
- package/src/runtime/hydrationBoundary.tsx +12 -0
- package/src/runtime/index.tsx +107 -2
- package/src/runtime/outlet.tsx +42 -0
- package/src/runtime/plugin.node.tsx +57 -8
- package/src/runtime/plugin.tsx +353 -149
- package/src/runtime/plugin.worker.tsx +4 -0
- 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 +239 -0
- package/tests/router/fastDefaults.test.ts +25 -0
- package/tests/router/hydrationBoundary.test.tsx +23 -0
- package/tests/router/routeTree.test.ts +416 -1
- package/tests/router/tanstackTypes.test.ts +184 -0
|
@@ -1,6 +1,7 @@
|
|
|
1
|
-
export
|
|
2
|
-
export { useMatch } from "@tanstack/react-router";
|
|
1
|
+
export { Asset, Await, Block, CatchBoundary, CatchNotFound, ClientOnly, DEFAULT_PROTOCOL_ALLOWLIST, DefaultGlobalNotFound, ErrorComponent, FileRoute, FileRouteLoader, HeadContent, LazyRoute, Match, MatchRoute, Matches, Navigate, NotFoundRoute, RootRoute, Route, RouteApi, Router, RouterContextProvider, RouterProvider, ScriptOnce, Scripts, ScrollRestoration, SearchParamError, cleanPath, composeRewrites, createBrowserHistory, createControlledPromise, createFileRoute, createHashHistory, createHistory, createLazyFileRoute, createLazyRoute, createLink, createMemoryHistory, createRootRoute, createRootRouteWithContext, createRoute, createRouteMask, createRouter, createRouterConfig, createSerializationAdapter, deepEqual, defaultParseSearch, defaultStringifySearch, defer, functionalUpdate, getRouteApi, interpolatePath, isMatch, isNotFound, isPlainArray, isPlainObject, isRedirect, joinPaths, lazyFn, lazyRouteComponent, linkOptions, notFound, parseSearchWith, reactUse, redirect, replaceEqualDeep, resolvePath, retainSearchParams, rootRouteId, rootRouteWithContext, stringifySearchWith, stripSearchParams, trimPath, trimPathLeft, trimPathRight, useAwaited, useBlocker, useCanGoBack, useChildMatches, useElementScrollRestoration, useHydrated, useLayoutEffect, useLinkProps, useLoaderData, useLoaderDeps, useLocation, useMatch, useMatchRoute, useMatches, useNavigate, useParams, useParentMatches, useRouteContext, useRouter, useRouterState, useSearch, useTags } from "@tanstack/react-router";
|
|
3
2
|
export { Form, RouteActionResponseError, useFetcher } from "./dataMutation.mjs";
|
|
3
|
+
export { Outlet } from "./outlet.mjs";
|
|
4
4
|
export { tanstackRouterPlugin as default, tanstackRouterPlugin } from "./plugin.mjs";
|
|
5
5
|
export { Link, NavLink } from "./prefetchLink.mjs";
|
|
6
6
|
export { CompositeComponent } from "./rsc/client.mjs";
|
|
7
|
+
export { getModernTanstackRouterFastDefaults, modernTanstackRouterFastDefaults } from "./types.mjs";
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
import { jsx } from "react/jsx-runtime";
|
|
2
|
+
import { Outlet } from "@tanstack/react-router";
|
|
3
|
+
import { createElement, memo } from "react";
|
|
4
|
+
const outlet_Outlet = /*#__PURE__*/ memo(function() {
|
|
5
|
+
return /*#__PURE__*/ jsx(Outlet, {});
|
|
6
|
+
});
|
|
7
|
+
function withModernRouteMatchContext(component, _routeId) {
|
|
8
|
+
if (!component) return component;
|
|
9
|
+
const Component = component;
|
|
10
|
+
const WrappedRouteComponent = (props)=>/*#__PURE__*/ createElement(Component, props);
|
|
11
|
+
const preloadable = component;
|
|
12
|
+
if ('function' == typeof preloadable.load) WrappedRouteComponent.load = preloadable.load.bind(preloadable);
|
|
13
|
+
if ('function' == typeof preloadable.preload) WrappedRouteComponent.preload = preloadable.preload.bind(preloadable);
|
|
14
|
+
else if ('function' == typeof preloadable.load) WrappedRouteComponent.preload = WrappedRouteComponent.load;
|
|
15
|
+
return WrappedRouteComponent;
|
|
16
|
+
}
|
|
17
|
+
export { outlet_Outlet as Outlet, withModernRouteMatchContext };
|
|
@@ -3,14 +3,18 @@ import { InternalRuntimeContext, getGlobalEnableRsc, getGlobalLayoutApp, getGlob
|
|
|
3
3
|
import { merge } from "@modern-js/runtime-utils/merge";
|
|
4
4
|
import { normalizePathname } from "@modern-js/runtime-utils/url";
|
|
5
5
|
import { RouterProvider, createBrowserHistory, createHashHistory, createRouter, useLocation, useMatches, useNavigate, useRouter } from "@tanstack/react-router";
|
|
6
|
-
import {
|
|
6
|
+
import { hydrate } from "@tanstack/react-router/ssr/client";
|
|
7
|
+
import { useContext, useMemo } from "react";
|
|
7
8
|
import { createModernBasepathRewrite } from "./basepathRewrite.mjs";
|
|
8
9
|
import { modifyRoutes, onAfterCreateRouter, onAfterHydrateRouter, onBeforeCreateRouter, onBeforeCreateRoutes, onBeforeHydrateRouter } from "./hooks.mjs";
|
|
10
|
+
import { wrapTanstackSsrHydrationBoundary } from "./hydrationBoundary.mjs";
|
|
9
11
|
import { applyRouterRuntimeState } from "./lifecycle.mjs";
|
|
12
|
+
import { withModernRouteMatchContext } from "./outlet.mjs";
|
|
13
|
+
import { Link } from "./prefetchLink.mjs";
|
|
10
14
|
import { createRouteTreeFromRouteObjects } from "./routeTree.mjs";
|
|
11
15
|
import { getTanstackRscSerializationAdapters } from "./rsc/client.mjs";
|
|
16
|
+
import { getModernTanstackRouterFastDefaults } from "./types.mjs";
|
|
12
17
|
import { createRouteObjectsFromConfig, urlJoin } from "./utils.mjs";
|
|
13
|
-
import * as __rspack_external_react from "react";
|
|
14
18
|
const BLOCKING_SUBSCRIBE_SYMBOL = Symbol.for('@modern-js/plugin-tanstack:blocking-subscribe');
|
|
15
19
|
const BLOCKING_STATE_SYMBOL = Symbol.for('@modern-js/plugin-tanstack:blocking-state');
|
|
16
20
|
function normalizeBase(b) {
|
|
@@ -38,6 +42,85 @@ function wrapRouterSubscribeWithBlockState(router, getBlockNavState) {
|
|
|
38
42
|
};
|
|
39
43
|
target[BLOCKING_SUBSCRIBE_SYMBOL] = true;
|
|
40
44
|
}
|
|
45
|
+
const routerHydrationRecords = new WeakMap();
|
|
46
|
+
const routeModulesKey = '_routeModules';
|
|
47
|
+
function pickRouteModuleComponent(routeModule, seen = new Set()) {
|
|
48
|
+
if ('function' == typeof routeModule || routeModule && 'object' == typeof routeModule && '$$typeof' in routeModule) return routeModule;
|
|
49
|
+
if (!routeModule || 'object' != typeof routeModule) return;
|
|
50
|
+
if (seen.has(routeModule)) return;
|
|
51
|
+
seen.add(routeModule);
|
|
52
|
+
const module = routeModule;
|
|
53
|
+
for (const candidate of [
|
|
54
|
+
module.default,
|
|
55
|
+
module.Component
|
|
56
|
+
]){
|
|
57
|
+
const component = pickRouteModuleComponent(candidate, seen);
|
|
58
|
+
if (component) return component;
|
|
59
|
+
}
|
|
60
|
+
}
|
|
61
|
+
function getCachedRouteModule(routeId) {
|
|
62
|
+
if ("u" < typeof window) return;
|
|
63
|
+
return window[routeModulesKey]?.[routeId];
|
|
64
|
+
}
|
|
65
|
+
async function preloadHydratedRouteComponents(router) {
|
|
66
|
+
const preloadableRouter = router;
|
|
67
|
+
const routesById = preloadableRouter.routesById || {};
|
|
68
|
+
const matches = preloadableRouter.stores.matches.get();
|
|
69
|
+
await Promise.all(matches.map((match)=>{
|
|
70
|
+
if (!match.routeId) return;
|
|
71
|
+
const route = routesById[match.routeId];
|
|
72
|
+
const component = route?.options?.component;
|
|
73
|
+
const preload = component?.load || component?.preload;
|
|
74
|
+
if ('function' != typeof preload) return;
|
|
75
|
+
return Promise.resolve(preload.call(component)).then((routeModule)=>{
|
|
76
|
+
const modernRouteId = route?.options?.staticData?.modernRouteId;
|
|
77
|
+
const resolvedComponent = pickRouteModuleComponent(modernRouteId && getCachedRouteModule(modernRouteId) || routeModule);
|
|
78
|
+
if (resolvedComponent && modernRouteId) route.options.component = withModernRouteMatchContext(resolvedComponent, modernRouteId);
|
|
79
|
+
});
|
|
80
|
+
}));
|
|
81
|
+
}
|
|
82
|
+
function getTanstackSsrHydrationRecord(router) {
|
|
83
|
+
let hydrationRecord = routerHydrationRecords.get(router);
|
|
84
|
+
if (!hydrationRecord) {
|
|
85
|
+
hydrationRecord = {
|
|
86
|
+
promise: Promise.resolve(),
|
|
87
|
+
status: 'pending'
|
|
88
|
+
};
|
|
89
|
+
routerHydrationRecords.set(router, hydrationRecord);
|
|
90
|
+
try {
|
|
91
|
+
hydrationRecord.promise = hydrate(router).then(async (value)=>{
|
|
92
|
+
await preloadHydratedRouteComponents(router);
|
|
93
|
+
return value;
|
|
94
|
+
}).then((value)=>{
|
|
95
|
+
hydrationRecord.status = 'fulfilled';
|
|
96
|
+
return value;
|
|
97
|
+
}, (error)=>{
|
|
98
|
+
hydrationRecord.status = 'rejected';
|
|
99
|
+
hydrationRecord.error = error;
|
|
100
|
+
throw error;
|
|
101
|
+
});
|
|
102
|
+
} catch (error) {
|
|
103
|
+
hydrationRecord.status = 'rejected';
|
|
104
|
+
hydrationRecord.error = error;
|
|
105
|
+
hydrationRecord.promise = Promise.reject(error);
|
|
106
|
+
hydrationRecord.promise.catch(()=>{});
|
|
107
|
+
}
|
|
108
|
+
}
|
|
109
|
+
return hydrationRecord;
|
|
110
|
+
}
|
|
111
|
+
function getTanstackSsrHydrationPromise(router) {
|
|
112
|
+
return getTanstackSsrHydrationRecord(router).promise;
|
|
113
|
+
}
|
|
114
|
+
function hasTanstackSsrHydrationRecord(router) {
|
|
115
|
+
return routerHydrationRecords.has(router);
|
|
116
|
+
}
|
|
117
|
+
function ModernRouterClient({ router }) {
|
|
118
|
+
const hydrationRecord = getTanstackSsrHydrationRecord(router);
|
|
119
|
+
if ('rejected' === hydrationRecord.status) throw hydrationRecord.error;
|
|
120
|
+
return /*#__PURE__*/ jsx(RouterProvider, {
|
|
121
|
+
router: router
|
|
122
|
+
});
|
|
123
|
+
}
|
|
41
124
|
function stripSyntheticNotFoundRoute(routes) {
|
|
42
125
|
return routes.filter((route)=>!('*' === route.path && !route.id && !route.loader)).map((route)=>{
|
|
43
126
|
if (!route.children?.length) return route;
|
|
@@ -59,9 +142,97 @@ const tanstackRouterPlugin = (userConfig = {})=>{
|
|
|
59
142
|
onBeforeHydrateRouter: onBeforeHydrateRouter
|
|
60
143
|
},
|
|
61
144
|
setup: (api)=>{
|
|
62
|
-
api.
|
|
145
|
+
const hooks = api.getHooks();
|
|
146
|
+
let cachedRouteObjects;
|
|
147
|
+
let cachedRouteTree = null;
|
|
148
|
+
let cachedRouter = null;
|
|
149
|
+
let cachedRouterBasepath = null;
|
|
150
|
+
const getMergedConfig = ()=>{
|
|
63
151
|
const pluginConfig = api.getRuntimeConfig();
|
|
64
|
-
|
|
152
|
+
return merge(pluginConfig.router || {}, userConfig);
|
|
153
|
+
};
|
|
154
|
+
const getRouteObjects = ()=>{
|
|
155
|
+
if (void 0 !== cachedRouteObjects) return cachedRouteObjects;
|
|
156
|
+
const mergedConfig = getMergedConfig();
|
|
157
|
+
const { routesConfig, createRoutes } = mergedConfig;
|
|
158
|
+
const finalRouteConfig = {
|
|
159
|
+
routes: getGlobalRoutes(),
|
|
160
|
+
globalApp: getGlobalLayoutApp(),
|
|
161
|
+
...routesConfig
|
|
162
|
+
};
|
|
163
|
+
const routeObjects = createRoutes ? createRoutes() : createRouteObjectsFromConfig({
|
|
164
|
+
routesConfig: finalRouteConfig
|
|
165
|
+
}) || [];
|
|
166
|
+
const normalizedRouteObjects = createRoutes ? routeObjects : stripSyntheticNotFoundRoute(routeObjects);
|
|
167
|
+
cachedRouteObjects = hooks.modifyRoutes.call(normalizedRouteObjects);
|
|
168
|
+
return cachedRouteObjects;
|
|
169
|
+
};
|
|
170
|
+
const getRouteTree = ()=>{
|
|
171
|
+
if (cachedRouteTree) return cachedRouteTree;
|
|
172
|
+
const routeObjects = getRouteObjects();
|
|
173
|
+
if (!routeObjects.length) return null;
|
|
174
|
+
cachedRouteTree = createRouteTreeFromRouteObjects(routeObjects, {
|
|
175
|
+
rscPayloadRouter: getGlobalEnableRsc()
|
|
176
|
+
});
|
|
177
|
+
return cachedRouteTree;
|
|
178
|
+
};
|
|
179
|
+
const selectBasePath = (pathname)=>{
|
|
180
|
+
const { serverBase = [] } = getMergedConfig();
|
|
181
|
+
const match = serverBase.find((baseUrl)=>isSegmentPrefix(pathname, baseUrl));
|
|
182
|
+
return match || '/';
|
|
183
|
+
};
|
|
184
|
+
const getClientBasename = (runtimeContext)=>{
|
|
185
|
+
const { basename = '' } = getMergedConfig();
|
|
186
|
+
const baseUrl = selectBasePath(location.pathname).replace(/^\/*/, '/');
|
|
187
|
+
return '/' === baseUrl ? urlJoin(baseUrl, runtimeContext._internalRouterBaseName || basename || '') : baseUrl;
|
|
188
|
+
};
|
|
189
|
+
const getRouter = (runtimeContext, _basename)=>{
|
|
190
|
+
const routeTree = getRouteTree();
|
|
191
|
+
if (!routeTree) return null;
|
|
192
|
+
const lifecycleContext = {
|
|
193
|
+
framework: 'tanstack',
|
|
194
|
+
phase: 'client-create',
|
|
195
|
+
routes: getRouteObjects(),
|
|
196
|
+
runtimeContext,
|
|
197
|
+
basename: _basename
|
|
198
|
+
};
|
|
199
|
+
hooks.onBeforeCreateRouter.call(lifecycleContext);
|
|
200
|
+
if (cachedRouter && cachedRouterBasepath === _basename) {
|
|
201
|
+
wrapRouterSubscribeWithBlockState(cachedRouter, runtimeContext.unstable_getBlockNavState);
|
|
202
|
+
hooks.onAfterCreateRouter.call({
|
|
203
|
+
...lifecycleContext,
|
|
204
|
+
router: cachedRouter,
|
|
205
|
+
runtimeContext
|
|
206
|
+
});
|
|
207
|
+
return cachedRouter;
|
|
208
|
+
}
|
|
209
|
+
const mergedConfig = getMergedConfig();
|
|
210
|
+
const { supportHtml5History = true } = mergedConfig;
|
|
211
|
+
const history = supportHtml5History ? createBrowserHistory() : createHashHistory();
|
|
212
|
+
const rewrite = createModernBasepathRewrite(_basename);
|
|
213
|
+
const serializationAdapters = getGlobalEnableRsc() ? getTanstackRscSerializationAdapters() : void 0;
|
|
214
|
+
cachedRouter = createRouter({
|
|
215
|
+
...getModernTanstackRouterFastDefaults(mergedConfig),
|
|
216
|
+
routeTree,
|
|
217
|
+
basepath: '/',
|
|
218
|
+
rewrite,
|
|
219
|
+
history,
|
|
220
|
+
context: {},
|
|
221
|
+
...serializationAdapters ? {
|
|
222
|
+
serializationAdapters
|
|
223
|
+
} : {}
|
|
224
|
+
});
|
|
225
|
+
cachedRouterBasepath = _basename;
|
|
226
|
+
wrapRouterSubscribeWithBlockState(cachedRouter, runtimeContext.unstable_getBlockNavState);
|
|
227
|
+
hooks.onAfterCreateRouter.call({
|
|
228
|
+
...lifecycleContext,
|
|
229
|
+
router: cachedRouter,
|
|
230
|
+
runtimeContext
|
|
231
|
+
});
|
|
232
|
+
return cachedRouter;
|
|
233
|
+
};
|
|
234
|
+
api.onBeforeRender(async (context)=>{
|
|
235
|
+
const mergedConfig = getMergedConfig();
|
|
65
236
|
if ("u" > typeof window && window._SSR_DATA && mergedConfig.unstable_reloadOnURLMismatch) {
|
|
66
237
|
const { ssrContext } = context;
|
|
67
238
|
const currentPathname = normalizePathname(window.location.pathname);
|
|
@@ -73,98 +244,32 @@ const tanstackRouterPlugin = (userConfig = {})=>{
|
|
|
73
244
|
}
|
|
74
245
|
}
|
|
75
246
|
context.router = {
|
|
247
|
+
Link: Link,
|
|
76
248
|
useMatches: useMatches,
|
|
77
249
|
useLocation: useLocation,
|
|
78
250
|
useNavigate: useNavigate,
|
|
79
251
|
useRouter: useRouter
|
|
80
252
|
};
|
|
253
|
+
const hasSSRBootstrap = "u" > typeof window && Boolean(window.$_TSR);
|
|
254
|
+
if (hasSSRBootstrap && getRouteObjects().length) {
|
|
255
|
+
const runtimeContext = context;
|
|
256
|
+
const router = getRouter(runtimeContext, getClientBasename(runtimeContext));
|
|
257
|
+
if (router) await getTanstackSsrHydrationPromise(router);
|
|
258
|
+
}
|
|
81
259
|
});
|
|
82
260
|
api.wrapRoot((App)=>{
|
|
83
|
-
|
|
84
|
-
const { serverBase = [], supportHtml5History = true, basename = '', routesConfig, createRoutes } = mergedConfig;
|
|
85
|
-
const finalRouteConfig = {
|
|
86
|
-
routes: getGlobalRoutes(),
|
|
87
|
-
globalApp: getGlobalLayoutApp(),
|
|
88
|
-
...routesConfig
|
|
89
|
-
};
|
|
90
|
-
if (!finalRouteConfig.routes && !createRoutes) return App;
|
|
91
|
-
const hooks = api.getHooks();
|
|
92
|
-
let cachedRouteObjects;
|
|
93
|
-
const getRouteObjects = ()=>{
|
|
94
|
-
if (void 0 !== cachedRouteObjects) return cachedRouteObjects;
|
|
95
|
-
const routeObjects = createRoutes ? createRoutes() : createRouteObjectsFromConfig({
|
|
96
|
-
routesConfig: finalRouteConfig
|
|
97
|
-
}) || [];
|
|
98
|
-
const normalizedRouteObjects = createRoutes ? routeObjects : stripSyntheticNotFoundRoute(routeObjects);
|
|
99
|
-
cachedRouteObjects = hooks.modifyRoutes.call(normalizedRouteObjects);
|
|
100
|
-
return cachedRouteObjects;
|
|
101
|
-
};
|
|
102
|
-
const selectBasePath = (pathname)=>{
|
|
103
|
-
const match = serverBase.find((baseUrl)=>isSegmentPrefix(pathname, baseUrl));
|
|
104
|
-
return match || '/';
|
|
105
|
-
};
|
|
106
|
-
let cachedRouteTree = null;
|
|
107
|
-
let cachedRouter = null;
|
|
108
|
-
let cachedRouterBasepath = null;
|
|
261
|
+
if (!getRouteObjects().length) return App;
|
|
109
262
|
const RouterWrapper = ()=>{
|
|
110
|
-
const runtimeContext =
|
|
111
|
-
const
|
|
112
|
-
const
|
|
113
|
-
const routeTree = (0, __rspack_external_react.useMemo)(()=>{
|
|
114
|
-
if (cachedRouteTree) return cachedRouteTree;
|
|
115
|
-
const routeObjects = getRouteObjects();
|
|
116
|
-
if (!routeObjects.length) return null;
|
|
117
|
-
cachedRouteTree = createRouteTreeFromRouteObjects(routeObjects, {
|
|
118
|
-
rscPayloadRouter: getGlobalEnableRsc()
|
|
119
|
-
});
|
|
120
|
-
return cachedRouteTree;
|
|
121
|
-
}, []);
|
|
263
|
+
const runtimeContext = useContext(InternalRuntimeContext);
|
|
264
|
+
const _basename = getClientBasename(runtimeContext);
|
|
265
|
+
const routeTree = useMemo(()=>getRouteTree(), []);
|
|
122
266
|
if (!routeTree) return App ? /*#__PURE__*/ jsx(App, {}) : null;
|
|
123
|
-
const router =
|
|
124
|
-
const lifecycleContext = {
|
|
125
|
-
framework: 'tanstack',
|
|
126
|
-
phase: 'client-create',
|
|
127
|
-
routes: getRouteObjects(),
|
|
128
|
-
runtimeContext,
|
|
129
|
-
basename: _basename
|
|
130
|
-
};
|
|
131
|
-
hooks.onBeforeCreateRouter.call(lifecycleContext);
|
|
132
|
-
if (cachedRouter && cachedRouterBasepath === _basename) {
|
|
133
|
-
wrapRouterSubscribeWithBlockState(cachedRouter, runtimeContext.unstable_getBlockNavState);
|
|
134
|
-
hooks.onAfterCreateRouter.call({
|
|
135
|
-
...lifecycleContext,
|
|
136
|
-
router: cachedRouter,
|
|
137
|
-
runtimeContext
|
|
138
|
-
});
|
|
139
|
-
return cachedRouter;
|
|
140
|
-
}
|
|
141
|
-
const history = supportHtml5History ? createBrowserHistory() : createHashHistory();
|
|
142
|
-
const rewrite = createModernBasepathRewrite(_basename);
|
|
143
|
-
const serializationAdapters = getGlobalEnableRsc() ? getTanstackRscSerializationAdapters() : void 0;
|
|
144
|
-
cachedRouter = createRouter({
|
|
145
|
-
routeTree,
|
|
146
|
-
basepath: '/',
|
|
147
|
-
rewrite,
|
|
148
|
-
history,
|
|
149
|
-
context: {},
|
|
150
|
-
...serializationAdapters ? {
|
|
151
|
-
serializationAdapters
|
|
152
|
-
} : {}
|
|
153
|
-
});
|
|
154
|
-
cachedRouterBasepath = _basename;
|
|
155
|
-
wrapRouterSubscribeWithBlockState(cachedRouter, runtimeContext.unstable_getBlockNavState);
|
|
156
|
-
hooks.onAfterCreateRouter.call({
|
|
157
|
-
...lifecycleContext,
|
|
158
|
-
router: cachedRouter,
|
|
159
|
-
runtimeContext
|
|
160
|
-
});
|
|
161
|
-
return cachedRouter;
|
|
162
|
-
}, [
|
|
267
|
+
const router = useMemo(()=>getRouter(runtimeContext, _basename), [
|
|
163
268
|
_basename,
|
|
164
269
|
routeTree,
|
|
165
|
-
supportHtml5History,
|
|
166
270
|
runtimeContext
|
|
167
271
|
]);
|
|
272
|
+
if (!router) return App ? /*#__PURE__*/ jsx(App, {}) : null;
|
|
168
273
|
const runtimeState = applyRouterRuntimeState(runtimeContext, {
|
|
169
274
|
framework: 'tanstack',
|
|
170
275
|
basename: _basename,
|
|
@@ -178,30 +283,29 @@ const tanstackRouterPlugin = (userConfig = {})=>{
|
|
|
178
283
|
basename: _basename,
|
|
179
284
|
router
|
|
180
285
|
};
|
|
181
|
-
const hasSSRBootstrap = "u" > typeof window && Boolean(window.$_TSR);
|
|
182
|
-
|
|
286
|
+
const hasSSRBootstrap = "u" > typeof window && (Boolean(window.$_TSR) || hasTanstackSsrHydrationRecord(router));
|
|
287
|
+
const needsRouterClient = hasSSRBootstrap;
|
|
288
|
+
if (needsRouterClient) hooks.onBeforeHydrateRouter.call({
|
|
183
289
|
...lifecycleContext,
|
|
184
290
|
phase: 'hydrate',
|
|
185
291
|
router,
|
|
186
292
|
runtimeContext: runtimeState
|
|
187
293
|
});
|
|
188
|
-
const RouterContent =
|
|
189
|
-
|
|
190
|
-
children: /*#__PURE__*/ jsx(RouterClient, {
|
|
191
|
-
router: router
|
|
192
|
-
})
|
|
294
|
+
const RouterContent = needsRouterClient ? /*#__PURE__*/ jsx(ModernRouterClient, {
|
|
295
|
+
router: router
|
|
193
296
|
}) : /*#__PURE__*/ jsx(RouterProvider, {
|
|
194
297
|
router: router
|
|
195
298
|
});
|
|
196
|
-
|
|
299
|
+
const HydratableRouterContent = wrapTanstackSsrHydrationBoundary(RouterContent, hasSSRBootstrap);
|
|
300
|
+
if (needsRouterClient) hooks.onAfterHydrateRouter.call({
|
|
197
301
|
...lifecycleContext,
|
|
198
302
|
phase: 'hydrate',
|
|
199
303
|
router,
|
|
200
304
|
runtimeContext: runtimeState
|
|
201
305
|
});
|
|
202
306
|
return App ? /*#__PURE__*/ jsx(App, {
|
|
203
|
-
children:
|
|
204
|
-
}) :
|
|
307
|
+
children: HydratableRouterContent
|
|
308
|
+
}) : HydratableRouterContent;
|
|
205
309
|
};
|
|
206
310
|
return RouterWrapper;
|
|
207
311
|
});
|
|
@@ -5,24 +5,42 @@ import { createRequestContext, storage } from "@modern-js/runtime-utils/node";
|
|
|
5
5
|
import { time } from "@modern-js/runtime-utils/time";
|
|
6
6
|
import { LOADER_REPORTER_NAME } from "@modern-js/utils/universal/constants";
|
|
7
7
|
import { RouterProvider, createMemoryHistory, createRouter } from "@tanstack/react-router";
|
|
8
|
-
import { attachRouterServerSsrUtils } from "@tanstack/
|
|
9
|
-
import {
|
|
8
|
+
import { attachRouterServerSsrUtils } from "@tanstack/router-core/ssr/server";
|
|
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";
|
|
16
|
+
import { getModernTanstackRouterFastDefaults } from "./types.mjs";
|
|
15
17
|
import { createRouteObjectsFromConfig, urlJoin } from "./utils.mjs";
|
|
16
18
|
const setTanstackRscServerPayload = (payload)=>{
|
|
17
19
|
const storageContext = storage.useContext?.();
|
|
18
20
|
if (storageContext) storageContext.serverPayload = payload;
|
|
19
21
|
};
|
|
22
|
+
function isPromiseLike(value) {
|
|
23
|
+
return Boolean(value && 'function' == typeof value.then);
|
|
24
|
+
}
|
|
20
25
|
function isPreloadableRouteComponent(component) {
|
|
21
26
|
if (!component || 'function' != typeof component) return false;
|
|
22
27
|
const preloadable = component;
|
|
23
28
|
return 'function' == typeof preloadable.load || 'function' == typeof preloadable.preload;
|
|
24
29
|
}
|
|
30
|
+
function isReactLazyRouteComponent(component) {
|
|
31
|
+
return Boolean(component) && 'object' == typeof component && 'function' == typeof component._init && '_payload' in component;
|
|
32
|
+
}
|
|
33
|
+
async function preloadReactLazyRouteComponent(component) {
|
|
34
|
+
try {
|
|
35
|
+
component._init?.(component._payload);
|
|
36
|
+
} catch (thrown) {
|
|
37
|
+
if (!isPromiseLike(thrown)) throw thrown;
|
|
38
|
+
await thrown;
|
|
39
|
+
component._init?.(component._payload);
|
|
40
|
+
}
|
|
41
|
+
}
|
|
25
42
|
async function preloadRouteComponent(component) {
|
|
43
|
+
if (isReactLazyRouteComponent(component)) return void await preloadReactLazyRouteComponent(component);
|
|
26
44
|
if (!isPreloadableRouteComponent(component)) return;
|
|
27
45
|
if ('function' == typeof component.load) return void await component.load({});
|
|
28
46
|
await component.preload?.({});
|
|
@@ -161,6 +179,7 @@ const tanstackRouterPlugin = (userConfig = {})=>{
|
|
|
161
179
|
};
|
|
162
180
|
hooks.onBeforeCreateRouter.call(routerLifecycleContext);
|
|
163
181
|
const tanstackRouter = createRouter({
|
|
182
|
+
...getModernTanstackRouterFastDefaults(mergedConfig),
|
|
164
183
|
routeTree,
|
|
165
184
|
history,
|
|
166
185
|
basepath: '/',
|
|
@@ -206,10 +225,12 @@ const tanstackRouterPlugin = (userConfig = {})=>{
|
|
|
206
225
|
await preloadMatchedRouteComponents(serverRouter);
|
|
207
226
|
context.ssrContext?.response.status(tanstackRouter.state.statusCode);
|
|
208
227
|
await serverRouter.serverSsr?.dehydrate?.();
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
228
|
+
if (isRSCNavigation) {
|
|
229
|
+
await waitForRouterSerialization(serverRouter);
|
|
230
|
+
setTanstackRscServerPayload(createTanstackRscServerPayload(serverRouter, {
|
|
231
|
+
omitClientLoaderData: true
|
|
232
|
+
}));
|
|
233
|
+
}
|
|
213
234
|
const ssrScriptTags = serverRouter.serverSsr?.takeBufferedScripts?.();
|
|
214
235
|
const hydrationScripts = routerManagedTagsToHtml(ssrScriptTags);
|
|
215
236
|
const matchedRouteIds = getModernRouteIdsFromMatches(serverRouter);
|
|
@@ -247,12 +268,9 @@ const tanstackRouterPlugin = (userConfig = {})=>{
|
|
|
247
268
|
if (!router) return App ? /*#__PURE__*/ jsx(App, {
|
|
248
269
|
...props
|
|
249
270
|
}) : null;
|
|
250
|
-
const routerWrapper = /*#__PURE__*/ jsx(
|
|
251
|
-
|
|
252
|
-
|
|
253
|
-
router: router
|
|
254
|
-
})
|
|
255
|
-
});
|
|
271
|
+
const routerWrapper = wrapTanstackSsrHydrationBoundary(/*#__PURE__*/ jsx(RouterProvider, {
|
|
272
|
+
router: router
|
|
273
|
+
}), true);
|
|
256
274
|
return App ? /*#__PURE__*/ jsx(App, {
|
|
257
275
|
children: routerWrapper
|
|
258
276
|
}) : routerWrapper;
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export { default, tanstackRouterPlugin } from "./plugin.node.mjs";
|