@tanstack/react-router 1.124.2 → 1.125.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.
- package/dist/cjs/Match.cjs +50 -43
- package/dist/cjs/Match.cjs.map +1 -1
- package/dist/cjs/lazyRouteComponent.cjs +3 -16
- package/dist/cjs/lazyRouteComponent.cjs.map +1 -1
- package/dist/cjs/lazyRouteComponent.d.cts +1 -1
- package/dist/cjs/ssr/renderRouterToStream.cjs +0 -2
- package/dist/cjs/ssr/renderRouterToStream.cjs.map +1 -1
- package/dist/esm/Match.js +51 -44
- package/dist/esm/Match.js.map +1 -1
- package/dist/esm/lazyRouteComponent.d.ts +1 -1
- package/dist/esm/lazyRouteComponent.js +2 -15
- package/dist/esm/lazyRouteComponent.js.map +1 -1
- package/dist/esm/ssr/renderRouterToStream.js +0 -2
- package/dist/esm/ssr/renderRouterToStream.js.map +1 -1
- package/package.json +2 -2
- package/src/Match.tsx +70 -58
- package/src/lazyRouteComponent.tsx +6 -31
- package/src/ssr/renderRouterToStream.tsx +1 -3
package/dist/cjs/Match.cjs
CHANGED
|
@@ -13,6 +13,7 @@ const matchContext = require("./matchContext.cjs");
|
|
|
13
13
|
const SafeFragment = require("./SafeFragment.cjs");
|
|
14
14
|
const renderRouteNotFound = require("./renderRouteNotFound.cjs");
|
|
15
15
|
const scrollRestoration = require("./scroll-restoration.cjs");
|
|
16
|
+
const ClientOnly = require("./ClientOnly.cjs");
|
|
16
17
|
function _interopNamespaceDefault(e) {
|
|
17
18
|
const n = Object.create(null, { [Symbol.toStringTag]: { value: "Module" } });
|
|
18
19
|
if (e) {
|
|
@@ -35,17 +36,18 @@ const Match = React__namespace.memo(function MatchImpl({
|
|
|
35
36
|
}) {
|
|
36
37
|
var _a, _b;
|
|
37
38
|
const router = useRouter.useRouter();
|
|
38
|
-
const
|
|
39
|
+
const matchState = useRouterState.useRouterState({
|
|
39
40
|
select: (s) => {
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
41
|
+
const match = s.matches.find((d) => d.id === matchId);
|
|
42
|
+
invariant(
|
|
43
|
+
match,
|
|
44
|
+
`Could not find match for matchId "${matchId}". Please file an issue!`
|
|
45
|
+
);
|
|
46
|
+
return routerCore.pick(match, ["routeId", "ssr", "_displayPending"]);
|
|
47
|
+
},
|
|
48
|
+
structuralSharing: true
|
|
43
49
|
});
|
|
44
|
-
|
|
45
|
-
routeId,
|
|
46
|
-
`Could not find routeId for matchId "${matchId}". Please file an issue!`
|
|
47
|
-
);
|
|
48
|
-
const route = router.routesById[routeId];
|
|
50
|
+
const route = router.routesById[matchState.routeId];
|
|
49
51
|
const PendingComponent = route.options.pendingComponent ?? router.options.defaultPendingComponent;
|
|
50
52
|
const pendingElement = PendingComponent ? /* @__PURE__ */ jsxRuntime.jsx(PendingComponent, {}) : null;
|
|
51
53
|
const routeErrorComponent = route.options.errorComponent ?? router.options.defaultErrorComponent;
|
|
@@ -54,9 +56,10 @@ const Match = React__namespace.memo(function MatchImpl({
|
|
|
54
56
|
// If it's the root route, use the globalNotFound option, with fallback to the notFoundRoute's component
|
|
55
57
|
route.options.notFoundComponent ?? ((_a = router.options.notFoundRoute) == null ? void 0 : _a.options.component)
|
|
56
58
|
) : route.options.notFoundComponent;
|
|
59
|
+
const resolvedNoSsr = matchState.ssr === false || matchState.ssr === "data-only";
|
|
57
60
|
const ResolvedSuspenseBoundary = (
|
|
58
61
|
// If we're on the root route, allow forcefully wrapping in suspense
|
|
59
|
-
(!route.isRoot || route.options.wrapInSuspense) && (route.options.wrapInSuspense ?? PendingComponent ?? ((_b = route.options.errorComponent) == null ? void 0 : _b.preload)) ? React__namespace.Suspense : SafeFragment.SafeFragment
|
|
62
|
+
(!route.isRoot || route.options.wrapInSuspense || resolvedNoSsr) && (route.options.wrapInSuspense ?? PendingComponent ?? (((_b = route.options.errorComponent) == null ? void 0 : _b.preload) || resolvedNoSsr)) ? React__namespace.Suspense : SafeFragment.SafeFragment
|
|
60
63
|
);
|
|
61
64
|
const ResolvedCatchBoundary = routeErrorComponent ? CatchBoundary.CatchBoundary : SafeFragment.SafeFragment;
|
|
62
65
|
const ResolvedNotFoundBoundary = routeNotFoundComponent ? notFound.CatchNotFound : SafeFragment.SafeFragment;
|
|
@@ -86,11 +89,11 @@ const Match = React__namespace.memo(function MatchImpl({
|
|
|
86
89
|
ResolvedNotFoundBoundary,
|
|
87
90
|
{
|
|
88
91
|
fallback: (error) => {
|
|
89
|
-
if (!routeNotFoundComponent || error.routeId && error.routeId !== routeId || !error.routeId && !route.isRoot)
|
|
92
|
+
if (!routeNotFoundComponent || error.routeId && error.routeId !== matchState.routeId || !error.routeId && !route.isRoot)
|
|
90
93
|
throw error;
|
|
91
94
|
return React__namespace.createElement(routeNotFoundComponent, error);
|
|
92
95
|
},
|
|
93
|
-
children: /* @__PURE__ */ jsxRuntime.jsx(MatchInner, { matchId })
|
|
96
|
+
children: resolvedNoSsr || router.isShell || matchState._displayPending ? /* @__PURE__ */ jsxRuntime.jsx(ClientOnly.ClientOnly, { fallback: pendingElement, children: /* @__PURE__ */ jsxRuntime.jsx(MatchInner, { matchId }) }) : /* @__PURE__ */ jsxRuntime.jsx(MatchInner, { matchId })
|
|
94
97
|
}
|
|
95
98
|
)
|
|
96
99
|
}
|
|
@@ -126,7 +129,7 @@ function OnRendered() {
|
|
|
126
129
|
const MatchInner = React__namespace.memo(function MatchInnerImpl({
|
|
127
130
|
matchId
|
|
128
131
|
}) {
|
|
129
|
-
var _a, _b, _c;
|
|
132
|
+
var _a, _b, _c, _d;
|
|
130
133
|
const router = useRouter.useRouter();
|
|
131
134
|
const { match, key, routeId } = useRouterState.useRouterState({
|
|
132
135
|
select: (s) => {
|
|
@@ -144,7 +147,13 @@ const MatchInner = React__namespace.memo(function MatchInnerImpl({
|
|
|
144
147
|
return {
|
|
145
148
|
key: key2,
|
|
146
149
|
routeId: routeId2,
|
|
147
|
-
match: routerCore.pick(match2, [
|
|
150
|
+
match: routerCore.pick(match2, [
|
|
151
|
+
"id",
|
|
152
|
+
"status",
|
|
153
|
+
"error",
|
|
154
|
+
"_forcePending",
|
|
155
|
+
"_displayPending"
|
|
156
|
+
])
|
|
148
157
|
};
|
|
149
158
|
},
|
|
150
159
|
structuralSharing: true
|
|
@@ -157,31 +166,10 @@ const MatchInner = React__namespace.memo(function MatchInnerImpl({
|
|
|
157
166
|
}
|
|
158
167
|
return /* @__PURE__ */ jsxRuntime.jsx(Outlet, {});
|
|
159
168
|
}, [key, route.options.component, router.options.defaultComponent]);
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
invariant(routerCore.isNotFound(match.error), "Expected a notFound error");
|
|
163
|
-
return renderRouteNotFound.renderRouteNotFound(router, route, match.error);
|
|
169
|
+
if (match._displayPending) {
|
|
170
|
+
throw (_a = router.getMatch(match.id)) == null ? void 0 : _a.displayPendingPromise;
|
|
164
171
|
}
|
|
165
|
-
if (match.status === "
|
|
166
|
-
invariant(routerCore.isRedirect(match.error), "Expected a redirect error");
|
|
167
|
-
throw (_a = router.getMatch(match.id)) == null ? void 0 : _a.loadPromise;
|
|
168
|
-
}
|
|
169
|
-
if (match.status === "error") {
|
|
170
|
-
if (router.isServer) {
|
|
171
|
-
return /* @__PURE__ */ jsxRuntime.jsx(
|
|
172
|
-
RouteErrorComponent,
|
|
173
|
-
{
|
|
174
|
-
error: match.error,
|
|
175
|
-
reset: void 0,
|
|
176
|
-
info: {
|
|
177
|
-
componentStack: ""
|
|
178
|
-
}
|
|
179
|
-
}
|
|
180
|
-
);
|
|
181
|
-
}
|
|
182
|
-
throw match.error;
|
|
183
|
-
}
|
|
184
|
-
if (match.status === "pending") {
|
|
172
|
+
if (match.status === "pending" || match._forcePending) {
|
|
185
173
|
const pendingMinMs = route.options.pendingMinMs ?? router.options.defaultPendingMinMs;
|
|
186
174
|
if (pendingMinMs && !((_b = router.getMatch(match.id)) == null ? void 0 : _b.minPendingPromise)) {
|
|
187
175
|
if (!router.isServer) {
|
|
@@ -203,6 +191,30 @@ const MatchInner = React__namespace.memo(function MatchInnerImpl({
|
|
|
203
191
|
}
|
|
204
192
|
throw (_c = router.getMatch(match.id)) == null ? void 0 : _c.loadPromise;
|
|
205
193
|
}
|
|
194
|
+
if (match.status === "notFound") {
|
|
195
|
+
invariant(routerCore.isNotFound(match.error), "Expected a notFound error");
|
|
196
|
+
return renderRouteNotFound.renderRouteNotFound(router, route, match.error);
|
|
197
|
+
}
|
|
198
|
+
if (match.status === "redirected") {
|
|
199
|
+
invariant(routerCore.isRedirect(match.error), "Expected a redirect error");
|
|
200
|
+
throw (_d = router.getMatch(match.id)) == null ? void 0 : _d.loadPromise;
|
|
201
|
+
}
|
|
202
|
+
if (match.status === "error") {
|
|
203
|
+
if (router.isServer) {
|
|
204
|
+
const RouteErrorComponent = (route.options.errorComponent ?? router.options.defaultErrorComponent) || CatchBoundary.ErrorComponent;
|
|
205
|
+
return /* @__PURE__ */ jsxRuntime.jsx(
|
|
206
|
+
RouteErrorComponent,
|
|
207
|
+
{
|
|
208
|
+
error: match.error,
|
|
209
|
+
reset: void 0,
|
|
210
|
+
info: {
|
|
211
|
+
componentStack: ""
|
|
212
|
+
}
|
|
213
|
+
}
|
|
214
|
+
);
|
|
215
|
+
}
|
|
216
|
+
throw match.error;
|
|
217
|
+
}
|
|
206
218
|
return out;
|
|
207
219
|
});
|
|
208
220
|
const Outlet = React__namespace.memo(function OutletImpl() {
|
|
@@ -235,8 +247,6 @@ const Outlet = React__namespace.memo(function OutletImpl() {
|
|
|
235
247
|
}
|
|
236
248
|
});
|
|
237
249
|
const pendingElement = router.options.defaultPendingComponent ? /* @__PURE__ */ jsxRuntime.jsx(router.options.defaultPendingComponent, {}) : null;
|
|
238
|
-
if (router.isShell)
|
|
239
|
-
return /* @__PURE__ */ jsxRuntime.jsx(React__namespace.Suspense, { fallback: pendingElement, children: /* @__PURE__ */ jsxRuntime.jsx(ShellInner, {}) });
|
|
240
250
|
if (parentGlobalNotFound) {
|
|
241
251
|
return renderRouteNotFound.renderRouteNotFound(router, route, void 0);
|
|
242
252
|
}
|
|
@@ -249,9 +259,6 @@ const Outlet = React__namespace.memo(function OutletImpl() {
|
|
|
249
259
|
}
|
|
250
260
|
return nextMatch;
|
|
251
261
|
});
|
|
252
|
-
function ShellInner() {
|
|
253
|
-
throw new Error("ShellBoundaryError");
|
|
254
|
-
}
|
|
255
262
|
exports.Match = Match;
|
|
256
263
|
exports.MatchInner = MatchInner;
|
|
257
264
|
exports.Outlet = Outlet;
|
package/dist/cjs/Match.cjs.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"Match.cjs","sources":["../../src/Match.tsx"],"sourcesContent":["import * as React from 'react'\nimport invariant from 'tiny-invariant'\nimport warning from 'tiny-warning'\nimport {\n createControlledPromise,\n getLocationChangeInfo,\n isNotFound,\n isRedirect,\n pick,\n rootRouteId,\n} from '@tanstack/router-core'\nimport { CatchBoundary, ErrorComponent } from './CatchBoundary'\nimport { useRouterState } from './useRouterState'\nimport { useRouter } from './useRouter'\nimport { CatchNotFound } from './not-found'\nimport { matchContext } from './matchContext'\nimport { SafeFragment } from './SafeFragment'\nimport { renderRouteNotFound } from './renderRouteNotFound'\nimport { ScrollRestoration } from './scroll-restoration'\nimport type {\n AnyRoute,\n ParsedLocation,\n RootRouteOptions,\n} from '@tanstack/router-core'\n\nexport const Match = React.memo(function MatchImpl({\n matchId,\n}: {\n matchId: string\n}) {\n const router = useRouter()\n const routeId = useRouterState({\n select: (s) => s.matches.find((d) => d.id === matchId)?.routeId as string,\n })\n\n invariant(\n routeId,\n `Could not find routeId for matchId \"${matchId}\". Please file an issue!`,\n )\n\n const route: AnyRoute = router.routesById[routeId]\n\n const PendingComponent =\n route.options.pendingComponent ?? router.options.defaultPendingComponent\n\n const pendingElement = PendingComponent ? <PendingComponent /> : null\n\n const routeErrorComponent =\n route.options.errorComponent ?? router.options.defaultErrorComponent\n\n const routeOnCatch = route.options.onCatch ?? router.options.defaultOnCatch\n\n const routeNotFoundComponent = route.isRoot\n ? // If it's the root route, use the globalNotFound option, with fallback to the notFoundRoute's component\n (route.options.notFoundComponent ??\n router.options.notFoundRoute?.options.component)\n : route.options.notFoundComponent\n\n const ResolvedSuspenseBoundary =\n // If we're on the root route, allow forcefully wrapping in suspense\n (!route.isRoot || route.options.wrapInSuspense) &&\n (route.options.wrapInSuspense ??\n PendingComponent ??\n (route.options.errorComponent as any)?.preload)\n ? React.Suspense\n : SafeFragment\n\n const ResolvedCatchBoundary = routeErrorComponent\n ? CatchBoundary\n : SafeFragment\n\n const ResolvedNotFoundBoundary = routeNotFoundComponent\n ? CatchNotFound\n : SafeFragment\n\n const resetKey = useRouterState({\n select: (s) => s.loadedAt,\n })\n\n const parentRouteId = useRouterState({\n select: (s) => {\n const index = s.matches.findIndex((d) => d.id === matchId)\n return s.matches[index - 1]?.routeId as string\n },\n })\n\n const ShellComponent = route.isRoot\n ? ((route.options as RootRouteOptions).shellComponent ?? SafeFragment)\n : SafeFragment\n return (\n <ShellComponent>\n <matchContext.Provider value={matchId}>\n <ResolvedSuspenseBoundary fallback={pendingElement}>\n <ResolvedCatchBoundary\n getResetKey={() => resetKey}\n errorComponent={routeErrorComponent || ErrorComponent}\n onCatch={(error, errorInfo) => {\n // Forward not found errors (we don't want to show the error component for these)\n if (isNotFound(error)) throw error\n warning(false, `Error in route match: ${matchId}`)\n routeOnCatch?.(error, errorInfo)\n }}\n >\n <ResolvedNotFoundBoundary\n fallback={(error) => {\n // If the current not found handler doesn't exist or it has a\n // route ID which doesn't match the current route, rethrow the error\n if (\n !routeNotFoundComponent ||\n (error.routeId && error.routeId !== routeId) ||\n (!error.routeId && !route.isRoot)\n )\n throw error\n\n return React.createElement(routeNotFoundComponent, error as any)\n }}\n >\n <MatchInner matchId={matchId} />\n </ResolvedNotFoundBoundary>\n </ResolvedCatchBoundary>\n </ResolvedSuspenseBoundary>\n </matchContext.Provider>\n {parentRouteId === rootRouteId && router.options.scrollRestoration ? (\n <>\n <OnRendered />\n <ScrollRestoration />\n </>\n ) : null}\n </ShellComponent>\n )\n})\n\n// On Rendered can't happen above the root layout because it actually\n// renders a dummy dom element to track the rendered state of the app.\n// We render a script tag with a key that changes based on the current\n// location state.__TSR_key. Also, because it's below the root layout, it\n// allows us to fire onRendered events even after a hydration mismatch\n// error that occurred above the root layout (like bad head/link tags,\n// which is common).\nfunction OnRendered() {\n const router = useRouter()\n\n const prevLocationRef = React.useRef<undefined | ParsedLocation<{}>>(\n undefined,\n )\n\n return (\n <script\n key={router.latestLocation.state.__TSR_key}\n suppressHydrationWarning\n ref={(el) => {\n if (\n el &&\n (prevLocationRef.current === undefined ||\n prevLocationRef.current.href !== router.latestLocation.href)\n ) {\n router.emit({\n type: 'onRendered',\n ...getLocationChangeInfo(router.state),\n })\n prevLocationRef.current = router.latestLocation\n }\n }}\n />\n )\n}\n\nexport const MatchInner = React.memo(function MatchInnerImpl({\n matchId,\n}: {\n matchId: string\n}): any {\n const router = useRouter()\n\n const { match, key, routeId } = useRouterState({\n select: (s) => {\n const matchIndex = s.matches.findIndex((d) => d.id === matchId)\n const match = s.matches[matchIndex]!\n const routeId = match.routeId as string\n\n const remountFn =\n (router.routesById[routeId] as AnyRoute).options.remountDeps ??\n router.options.defaultRemountDeps\n const remountDeps = remountFn?.({\n routeId,\n loaderDeps: match.loaderDeps,\n params: match._strictParams,\n search: match._strictSearch,\n })\n const key = remountDeps ? JSON.stringify(remountDeps) : undefined\n\n return {\n key,\n routeId,\n match: pick(match, ['id', 'status', 'error']),\n }\n },\n structuralSharing: true as any,\n })\n\n const route = router.routesById[routeId] as AnyRoute\n\n const out = React.useMemo(() => {\n const Comp = route.options.component ?? router.options.defaultComponent\n if (Comp) {\n return <Comp key={key} />\n }\n return <Outlet />\n }, [key, route.options.component, router.options.defaultComponent])\n\n const RouteErrorComponent =\n (route.options.errorComponent ?? router.options.defaultErrorComponent) ||\n ErrorComponent\n\n if (match.status === 'notFound') {\n invariant(isNotFound(match.error), 'Expected a notFound error')\n return renderRouteNotFound(router, route, match.error)\n }\n\n if (match.status === 'redirected') {\n // Redirects should be handled by the router transition. If we happen to\n // encounter a redirect here, it's a bug. Let's warn, but render nothing.\n invariant(isRedirect(match.error), 'Expected a redirect error')\n\n // warning(\n // false,\n // 'Tried to render a redirected route match! This is a weird circumstance, please file an issue!',\n // )\n throw router.getMatch(match.id)?.loadPromise\n }\n\n if (match.status === 'error') {\n // If we're on the server, we need to use React's new and super\n // wonky api for throwing errors from a server side render inside\n // of a suspense boundary. This is the only way to get\n // renderToPipeableStream to not hang indefinitely.\n // We'll serialize the error and rethrow it on the client.\n if (router.isServer) {\n return (\n <RouteErrorComponent\n error={match.error as any}\n reset={undefined as any}\n info={{\n componentStack: '',\n }}\n />\n )\n }\n\n throw match.error\n }\n\n if (match.status === 'pending') {\n // We're pending, and if we have a minPendingMs, we need to wait for it\n const pendingMinMs =\n route.options.pendingMinMs ?? router.options.defaultPendingMinMs\n\n if (pendingMinMs && !router.getMatch(match.id)?.minPendingPromise) {\n // Create a promise that will resolve after the minPendingMs\n if (!router.isServer) {\n const minPendingPromise = createControlledPromise<void>()\n\n Promise.resolve().then(() => {\n router.updateMatch(match.id, (prev) => ({\n ...prev,\n minPendingPromise,\n }))\n })\n\n setTimeout(() => {\n minPendingPromise.resolve()\n\n // We've handled the minPendingPromise, so we can delete it\n router.updateMatch(match.id, (prev) => ({\n ...prev,\n minPendingPromise: undefined,\n }))\n }, pendingMinMs)\n }\n }\n throw router.getMatch(match.id)?.loadPromise\n }\n\n return out\n})\n\nexport const Outlet = React.memo(function OutletImpl() {\n const router = useRouter()\n const matchId = React.useContext(matchContext)\n const routeId = useRouterState({\n select: (s) => s.matches.find((d) => d.id === matchId)?.routeId as string,\n })\n\n const route = router.routesById[routeId]!\n\n const parentGlobalNotFound = useRouterState({\n select: (s) => {\n const matches = s.matches\n const parentMatch = matches.find((d) => d.id === matchId)\n invariant(\n parentMatch,\n `Could not find parent match for matchId \"${matchId}\"`,\n )\n return parentMatch.globalNotFound\n },\n })\n\n const childMatchId = useRouterState({\n select: (s) => {\n const matches = s.matches\n const index = matches.findIndex((d) => d.id === matchId)\n return matches[index + 1]?.id\n },\n })\n\n const pendingElement = router.options.defaultPendingComponent ? (\n <router.options.defaultPendingComponent />\n ) : null\n\n if (router.isShell)\n return (\n <React.Suspense fallback={pendingElement}>\n <ShellInner />\n </React.Suspense>\n )\n\n if (parentGlobalNotFound) {\n return renderRouteNotFound(router, route, undefined)\n }\n\n if (!childMatchId) {\n return null\n }\n\n const nextMatch = <Match matchId={childMatchId} />\n\n if (matchId === rootRouteId) {\n return (\n <React.Suspense fallback={pendingElement}>{nextMatch}</React.Suspense>\n )\n }\n\n return nextMatch\n})\n\nfunction ShellInner(): React.ReactElement {\n throw new Error('ShellBoundaryError')\n}\n"],"names":["React","useRouter","useRouterState","_a","jsx","SafeFragment","CatchBoundary","CatchNotFound","matchContext","ErrorComponent","isNotFound","rootRouteId","jsxs","Fragment","ScrollRestoration","getLocationChangeInfo","match","routeId","key","pick","renderRouteNotFound","isRedirect","createControlledPromise"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"Match.cjs","sources":["../../src/Match.tsx"],"sourcesContent":["import * as React from 'react'\nimport invariant from 'tiny-invariant'\nimport warning from 'tiny-warning'\nimport {\n createControlledPromise,\n getLocationChangeInfo,\n isNotFound,\n isRedirect,\n pick,\n rootRouteId,\n} from '@tanstack/router-core'\nimport { CatchBoundary, ErrorComponent } from './CatchBoundary'\nimport { useRouterState } from './useRouterState'\nimport { useRouter } from './useRouter'\nimport { CatchNotFound } from './not-found'\nimport { matchContext } from './matchContext'\nimport { SafeFragment } from './SafeFragment'\nimport { renderRouteNotFound } from './renderRouteNotFound'\nimport { ScrollRestoration } from './scroll-restoration'\nimport { ClientOnly } from './ClientOnly'\nimport type {\n AnyRoute,\n ParsedLocation,\n RootRouteOptions,\n} from '@tanstack/router-core'\n\nexport const Match = React.memo(function MatchImpl({\n matchId,\n}: {\n matchId: string\n}) {\n const router = useRouter()\n const matchState = useRouterState({\n select: (s) => {\n const match = s.matches.find((d) => d.id === matchId)\n invariant(\n match,\n `Could not find match for matchId \"${matchId}\". Please file an issue!`,\n )\n return pick(match, ['routeId', 'ssr', '_displayPending'])\n },\n structuralSharing: true as any,\n })\n\n const route: AnyRoute = router.routesById[matchState.routeId]\n\n const PendingComponent =\n route.options.pendingComponent ?? router.options.defaultPendingComponent\n\n const pendingElement = PendingComponent ? <PendingComponent /> : null\n\n const routeErrorComponent =\n route.options.errorComponent ?? router.options.defaultErrorComponent\n\n const routeOnCatch = route.options.onCatch ?? router.options.defaultOnCatch\n\n const routeNotFoundComponent = route.isRoot\n ? // If it's the root route, use the globalNotFound option, with fallback to the notFoundRoute's component\n (route.options.notFoundComponent ??\n router.options.notFoundRoute?.options.component)\n : route.options.notFoundComponent\n\n const resolvedNoSsr =\n matchState.ssr === false || matchState.ssr === 'data-only'\n const ResolvedSuspenseBoundary =\n // If we're on the root route, allow forcefully wrapping in suspense\n (!route.isRoot || route.options.wrapInSuspense || resolvedNoSsr) &&\n (route.options.wrapInSuspense ??\n PendingComponent ??\n ((route.options.errorComponent as any)?.preload || resolvedNoSsr))\n ? React.Suspense\n : SafeFragment\n\n const ResolvedCatchBoundary = routeErrorComponent\n ? CatchBoundary\n : SafeFragment\n\n const ResolvedNotFoundBoundary = routeNotFoundComponent\n ? CatchNotFound\n : SafeFragment\n\n const resetKey = useRouterState({\n select: (s) => s.loadedAt,\n })\n\n const parentRouteId = useRouterState({\n select: (s) => {\n const index = s.matches.findIndex((d) => d.id === matchId)\n return s.matches[index - 1]?.routeId as string\n },\n })\n\n const ShellComponent = route.isRoot\n ? ((route.options as RootRouteOptions).shellComponent ?? SafeFragment)\n : SafeFragment\n return (\n <ShellComponent>\n <matchContext.Provider value={matchId}>\n <ResolvedSuspenseBoundary fallback={pendingElement}>\n <ResolvedCatchBoundary\n getResetKey={() => resetKey}\n errorComponent={routeErrorComponent || ErrorComponent}\n onCatch={(error, errorInfo) => {\n // Forward not found errors (we don't want to show the error component for these)\n if (isNotFound(error)) throw error\n warning(false, `Error in route match: ${matchId}`)\n routeOnCatch?.(error, errorInfo)\n }}\n >\n <ResolvedNotFoundBoundary\n fallback={(error) => {\n // If the current not found handler doesn't exist or it has a\n // route ID which doesn't match the current route, rethrow the error\n if (\n !routeNotFoundComponent ||\n (error.routeId && error.routeId !== matchState.routeId) ||\n (!error.routeId && !route.isRoot)\n )\n throw error\n\n return React.createElement(routeNotFoundComponent, error as any)\n }}\n >\n {resolvedNoSsr || router.isShell || matchState._displayPending ? (\n <ClientOnly fallback={pendingElement}>\n <MatchInner matchId={matchId} />\n </ClientOnly>\n ) : (\n <MatchInner matchId={matchId} />\n )}\n </ResolvedNotFoundBoundary>\n </ResolvedCatchBoundary>\n </ResolvedSuspenseBoundary>\n </matchContext.Provider>\n {parentRouteId === rootRouteId && router.options.scrollRestoration ? (\n <>\n <OnRendered />\n <ScrollRestoration />\n </>\n ) : null}\n </ShellComponent>\n )\n})\n\n// On Rendered can't happen above the root layout because it actually\n// renders a dummy dom element to track the rendered state of the app.\n// We render a script tag with a key that changes based on the current\n// location state.__TSR_key. Also, because it's below the root layout, it\n// allows us to fire onRendered events even after a hydration mismatch\n// error that occurred above the root layout (like bad head/link tags,\n// which is common).\nfunction OnRendered() {\n const router = useRouter()\n\n const prevLocationRef = React.useRef<undefined | ParsedLocation<{}>>(\n undefined,\n )\n\n return (\n <script\n key={router.latestLocation.state.__TSR_key}\n suppressHydrationWarning\n ref={(el) => {\n if (\n el &&\n (prevLocationRef.current === undefined ||\n prevLocationRef.current.href !== router.latestLocation.href)\n ) {\n router.emit({\n type: 'onRendered',\n ...getLocationChangeInfo(router.state),\n })\n prevLocationRef.current = router.latestLocation\n }\n }}\n />\n )\n}\n\nexport const MatchInner = React.memo(function MatchInnerImpl({\n matchId,\n}: {\n matchId: string\n}): any {\n const router = useRouter()\n\n const { match, key, routeId } = useRouterState({\n select: (s) => {\n const matchIndex = s.matches.findIndex((d) => d.id === matchId)\n const match = s.matches[matchIndex]!\n const routeId = match.routeId as string\n\n const remountFn =\n (router.routesById[routeId] as AnyRoute).options.remountDeps ??\n router.options.defaultRemountDeps\n const remountDeps = remountFn?.({\n routeId,\n loaderDeps: match.loaderDeps,\n params: match._strictParams,\n search: match._strictSearch,\n })\n const key = remountDeps ? JSON.stringify(remountDeps) : undefined\n\n return {\n key,\n routeId,\n match: pick(match, [\n 'id',\n 'status',\n 'error',\n '_forcePending',\n '_displayPending',\n ]),\n }\n },\n structuralSharing: true as any,\n })\n\n const route = router.routesById[routeId] as AnyRoute\n\n const out = React.useMemo(() => {\n const Comp = route.options.component ?? router.options.defaultComponent\n if (Comp) {\n return <Comp key={key} />\n }\n return <Outlet />\n }, [key, route.options.component, router.options.defaultComponent])\n\n if (match._displayPending) {\n throw router.getMatch(match.id)?.displayPendingPromise\n }\n\n // see also triggerOnReady() in packages/router-core/src/router.ts\n if (match.status === 'pending' || match._forcePending) {\n // We're pending, and if we have a minPendingMs, we need to wait for it\n const pendingMinMs =\n route.options.pendingMinMs ?? router.options.defaultPendingMinMs\n\n if (pendingMinMs && !router.getMatch(match.id)?.minPendingPromise) {\n // Create a promise that will resolve after the minPendingMs\n if (!router.isServer) {\n const minPendingPromise = createControlledPromise<void>()\n\n Promise.resolve().then(() => {\n router.updateMatch(match.id, (prev) => ({\n ...prev,\n minPendingPromise,\n }))\n })\n\n setTimeout(() => {\n minPendingPromise.resolve()\n\n // We've handled the minPendingPromise, so we can delete it\n router.updateMatch(match.id, (prev) => ({\n ...prev,\n minPendingPromise: undefined,\n }))\n }, pendingMinMs)\n }\n }\n throw router.getMatch(match.id)?.loadPromise\n }\n\n if (match.status === 'notFound') {\n invariant(isNotFound(match.error), 'Expected a notFound error')\n return renderRouteNotFound(router, route, match.error)\n }\n\n if (match.status === 'redirected') {\n // Redirects should be handled by the router transition. If we happen to\n // encounter a redirect here, it's a bug. Let's warn, but render nothing.\n invariant(isRedirect(match.error), 'Expected a redirect error')\n\n // warning(\n // false,\n // 'Tried to render a redirected route match! This is a weird circumstance, please file an issue!',\n // )\n throw router.getMatch(match.id)?.loadPromise\n }\n\n if (match.status === 'error') {\n // If we're on the server, we need to use React's new and super\n // wonky api for throwing errors from a server side render inside\n // of a suspense boundary. This is the only way to get\n // renderToPipeableStream to not hang indefinitely.\n // We'll serialize the error and rethrow it on the client.\n if (router.isServer) {\n const RouteErrorComponent =\n (route.options.errorComponent ??\n router.options.defaultErrorComponent) ||\n ErrorComponent\n return (\n <RouteErrorComponent\n error={match.error as any}\n reset={undefined as any}\n info={{\n componentStack: '',\n }}\n />\n )\n }\n\n throw match.error\n }\n\n return out\n})\n\nexport const Outlet = React.memo(function OutletImpl() {\n const router = useRouter()\n const matchId = React.useContext(matchContext)\n const routeId = useRouterState({\n select: (s) => s.matches.find((d) => d.id === matchId)?.routeId as string,\n })\n\n const route = router.routesById[routeId]!\n\n const parentGlobalNotFound = useRouterState({\n select: (s) => {\n const matches = s.matches\n const parentMatch = matches.find((d) => d.id === matchId)\n invariant(\n parentMatch,\n `Could not find parent match for matchId \"${matchId}\"`,\n )\n return parentMatch.globalNotFound\n },\n })\n\n const childMatchId = useRouterState({\n select: (s) => {\n const matches = s.matches\n const index = matches.findIndex((d) => d.id === matchId)\n return matches[index + 1]?.id\n },\n })\n\n const pendingElement = router.options.defaultPendingComponent ? (\n <router.options.defaultPendingComponent />\n ) : null\n\n if (parentGlobalNotFound) {\n return renderRouteNotFound(router, route, undefined)\n }\n\n if (!childMatchId) {\n return null\n }\n\n const nextMatch = <Match matchId={childMatchId} />\n\n if (matchId === rootRouteId) {\n return (\n <React.Suspense fallback={pendingElement}>{nextMatch}</React.Suspense>\n )\n }\n\n return nextMatch\n})\n"],"names":["React","useRouter","useRouterState","pick","jsx","SafeFragment","CatchBoundary","CatchNotFound","_a","matchContext","ErrorComponent","isNotFound","ClientOnly","rootRouteId","jsxs","Fragment","ScrollRestoration","getLocationChangeInfo","match","routeId","key","createControlledPromise","renderRouteNotFound","isRedirect"],"mappings":"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"}
|
|
@@ -1,9 +1,7 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
|
|
3
|
-
const jsxRuntime = require("react/jsx-runtime");
|
|
4
3
|
const React = require("react");
|
|
5
|
-
const
|
|
6
|
-
const ClientOnly = require("./ClientOnly.cjs");
|
|
4
|
+
const routerCore = require("@tanstack/router-core");
|
|
7
5
|
function _interopNamespaceDefault(e) {
|
|
8
6
|
const n = Object.create(null, { [Symbol.toStringTag]: { value: "Module" } });
|
|
9
7
|
if (e) {
|
|
@@ -21,27 +19,19 @@ function _interopNamespaceDefault(e) {
|
|
|
21
19
|
return Object.freeze(n);
|
|
22
20
|
}
|
|
23
21
|
const React__namespace = /* @__PURE__ */ _interopNamespaceDefault(React);
|
|
24
|
-
function
|
|
25
|
-
if (typeof (error == null ? void 0 : error.message) !== "string") return false;
|
|
26
|
-
return error.message.startsWith("Failed to fetch dynamically imported module") || error.message.startsWith("error loading dynamically imported module") || error.message.startsWith("Importing a module script failed");
|
|
27
|
-
}
|
|
28
|
-
function lazyRouteComponent(importer, exportName, ssr) {
|
|
22
|
+
function lazyRouteComponent(importer, exportName) {
|
|
29
23
|
let loadPromise;
|
|
30
24
|
let comp;
|
|
31
25
|
let error;
|
|
32
26
|
let reload;
|
|
33
27
|
const load = () => {
|
|
34
|
-
if (typeof document === "undefined" && (ssr == null ? void 0 : ssr()) === false) {
|
|
35
|
-
comp = () => null;
|
|
36
|
-
return Promise.resolve();
|
|
37
|
-
}
|
|
38
28
|
if (!loadPromise) {
|
|
39
29
|
loadPromise = importer().then((res) => {
|
|
40
30
|
loadPromise = void 0;
|
|
41
31
|
comp = res[exportName ?? "default"];
|
|
42
32
|
}).catch((err) => {
|
|
43
33
|
error = err;
|
|
44
|
-
if (isModuleNotFoundError(error)) {
|
|
34
|
+
if (routerCore.isModuleNotFoundError(error)) {
|
|
45
35
|
if (error instanceof Error && typeof window !== "undefined" && typeof sessionStorage !== "undefined") {
|
|
46
36
|
const storageKey = `tanstack_router_reload:${error.message}`;
|
|
47
37
|
if (!sessionStorage.getItem(storageKey)) {
|
|
@@ -66,9 +56,6 @@ function lazyRouteComponent(importer, exportName, ssr) {
|
|
|
66
56
|
if (!comp) {
|
|
67
57
|
throw load();
|
|
68
58
|
}
|
|
69
|
-
if ((ssr == null ? void 0 : ssr()) === false) {
|
|
70
|
-
return /* @__PURE__ */ jsxRuntime.jsx(ClientOnly.ClientOnly, { fallback: /* @__PURE__ */ jsxRuntime.jsx(Match.Outlet, {}), children: React__namespace.createElement(comp, props) });
|
|
71
|
-
}
|
|
72
59
|
return React__namespace.createElement(comp, props);
|
|
73
60
|
};
|
|
74
61
|
lazyComp.preload = load;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"lazyRouteComponent.cjs","sources":["../../src/lazyRouteComponent.tsx"],"sourcesContent":["import * as React from 'react'\nimport {
|
|
1
|
+
{"version":3,"file":"lazyRouteComponent.cjs","sources":["../../src/lazyRouteComponent.tsx"],"sourcesContent":["import * as React from 'react'\nimport { isModuleNotFoundError } from '@tanstack/router-core'\nimport type { AsyncRouteComponent } from './route'\n\nexport function lazyRouteComponent<\n T extends Record<string, any>,\n TKey extends keyof T = 'default',\n>(\n importer: () => Promise<T>,\n exportName?: TKey,\n): T[TKey] extends (props: infer TProps) => any\n ? AsyncRouteComponent<TProps>\n : never {\n let loadPromise: Promise<any> | undefined\n let comp: T[TKey] | T['default']\n let error: any\n let reload: boolean\n\n const load = () => {\n if (!loadPromise) {\n loadPromise = importer()\n .then((res) => {\n loadPromise = undefined\n comp = res[exportName ?? 'default']\n })\n .catch((err) => {\n // We don't want an error thrown from preload in this case, because\n // there's nothing we want to do about module not found during preload.\n // Record the error, the rest is handled during the render path.\n error = err\n // If the load fails due to module not found, it may mean a new version of\n // the build was deployed and the user's browser is still using an old version.\n // If this happens, the old version in the user's browser would have an outdated\n // URL to the lazy module.\n // In that case, we want to attempt one window refresh to get the latest.\n if (isModuleNotFoundError(error)) {\n if (\n error instanceof Error &&\n typeof window !== 'undefined' &&\n typeof sessionStorage !== 'undefined'\n ) {\n // Again, we want to reload one time on module not found error and not enter\n // a reload loop if there is some other issue besides an old deploy.\n // That's why we store our reload attempt in sessionStorage.\n // Use error.message as key because it contains the module path that failed.\n const storageKey = `tanstack_router_reload:${error.message}`\n if (!sessionStorage.getItem(storageKey)) {\n sessionStorage.setItem(storageKey, '1')\n reload = true\n }\n }\n }\n })\n }\n\n return loadPromise\n }\n\n const lazyComp = function Lazy(props: any) {\n // Now that we're out of preload and into actual render path,\n if (reload) {\n // If it was a module loading error,\n // throw eternal suspense while we wait for window to reload\n window.location.reload()\n throw new Promise(() => {})\n }\n if (error) {\n // Otherwise, just throw the error\n throw error\n }\n\n if (!comp) {\n throw load()\n }\n\n return React.createElement(comp, props)\n }\n\n ;(lazyComp as any).preload = load\n\n return lazyComp as any\n}\n"],"names":["isModuleNotFoundError","React"],"mappings":";;;;;;;;;;;;;;;;;;;;;AAIgB,SAAA,mBAId,UACA,YAGQ;AACJ,MAAA;AACA,MAAA;AACA,MAAA;AACA,MAAA;AAEJ,QAAM,OAAO,MAAM;AACjB,QAAI,CAAC,aAAa;AAChB,oBAAc,SAAS,EACpB,KAAK,CAAC,QAAQ;AACC,sBAAA;AACP,eAAA,IAAI,cAAc,SAAS;AAAA,MAAA,CACnC,EACA,MAAM,CAAC,QAAQ;AAIN,gBAAA;AAMJ,YAAAA,WAAAA,sBAAsB,KAAK,GAAG;AAChC,cACE,iBAAiB,SACjB,OAAO,WAAW,eAClB,OAAO,mBAAmB,aAC1B;AAKM,kBAAA,aAAa,0BAA0B,MAAM,OAAO;AAC1D,gBAAI,CAAC,eAAe,QAAQ,UAAU,GAAG;AACxB,6BAAA,QAAQ,YAAY,GAAG;AAC7B,uBAAA;AAAA,YAAA;AAAA,UACX;AAAA,QACF;AAAA,MACF,CACD;AAAA,IAAA;AAGE,WAAA;AAAA,EACT;AAEM,QAAA,WAAW,SAAS,KAAK,OAAY;AAEzC,QAAI,QAAQ;AAGV,aAAO,SAAS,OAAO;AACjB,YAAA,IAAI,QAAQ,MAAM;AAAA,MAAA,CAAE;AAAA,IAAA;AAE5B,QAAI,OAAO;AAEH,YAAA;AAAA,IAAA;AAGR,QAAI,CAAC,MAAM;AACT,YAAM,KAAK;AAAA,IAAA;AAGN,WAAAC,iBAAM,cAAc,MAAM,KAAK;AAAA,EACxC;AAEE,WAAiB,UAAU;AAEtB,SAAA;AACT;;"}
|
|
@@ -1,2 +1,2 @@
|
|
|
1
1
|
import { AsyncRouteComponent } from './route.cjs';
|
|
2
|
-
export declare function lazyRouteComponent<T extends Record<string, any>, TKey extends keyof T = 'default'>(importer: () => Promise<T>, exportName?: TKey
|
|
2
|
+
export declare function lazyRouteComponent<T extends Record<string, any>, TKey extends keyof T = 'default'>(importer: () => Promise<T>, exportName?: TKey): T[TKey] extends (props: infer TProps) => any ? AsyncRouteComponent<TProps> : never;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"renderRouterToStream.cjs","sources":["../../../src/ssr/renderRouterToStream.tsx"],"sourcesContent":["import { PassThrough } from 'node:stream'\nimport ReactDOMServer from 'react-dom/server'\nimport { isbot } from 'isbot'\nimport {\n transformPipeableStreamWithRouter,\n transformReadableStreamWithRouter,\n} from '@tanstack/router-core/ssr/server'\nimport type {
|
|
1
|
+
{"version":3,"file":"renderRouterToStream.cjs","sources":["../../../src/ssr/renderRouterToStream.tsx"],"sourcesContent":["import { PassThrough } from 'node:stream'\nimport ReactDOMServer from 'react-dom/server'\nimport { isbot } from 'isbot'\nimport {\n transformPipeableStreamWithRouter,\n transformReadableStreamWithRouter,\n} from '@tanstack/router-core/ssr/server'\nimport type { AnyRouter } from '@tanstack/router-core'\nimport type { ReadableStream } from 'node:stream/web'\nimport type { ReactNode } from 'react'\n\nexport const renderRouterToStream = async ({\n request,\n router,\n responseHeaders,\n children,\n}: {\n request: Request\n router: AnyRouter\n responseHeaders: Headers\n children: ReactNode\n}) => {\n if (typeof ReactDOMServer.renderToReadableStream === 'function') {\n const stream = await ReactDOMServer.renderToReadableStream(children, {\n signal: request.signal,\n })\n\n if (isbot(request.headers.get('User-Agent'))) {\n await stream.allReady\n }\n\n const responseStream = transformReadableStreamWithRouter(\n router,\n stream as unknown as ReadableStream,\n )\n return new Response(responseStream as any, {\n status: router.state.statusCode,\n headers: responseHeaders,\n })\n }\n\n if (typeof ReactDOMServer.renderToPipeableStream === 'function') {\n const reactAppPassthrough = new PassThrough()\n\n try {\n const pipeable = ReactDOMServer.renderToPipeableStream(children, {\n ...(isbot(request.headers.get('User-Agent'))\n ? {\n onAllReady() {\n pipeable.pipe(reactAppPassthrough)\n },\n }\n : {\n onShellReady() {\n pipeable.pipe(reactAppPassthrough)\n },\n }),\n onError: (error, info) => {\n console.error('Error in renderToPipeableStream:', error, info)\n },\n })\n } catch (e) {\n console.error('Error in renderToPipeableStream:', e)\n }\n\n const responseStream = transformPipeableStreamWithRouter(\n router,\n reactAppPassthrough,\n )\n return new Response(responseStream as any, {\n status: router.state.statusCode,\n headers: responseHeaders,\n })\n }\n\n throw new Error(\n 'No renderToReadableStream or renderToPipeableStream found in react-dom/server. Ensure you are using a version of react-dom that supports streaming.',\n )\n}\n"],"names":["isbot","transformReadableStreamWithRouter","PassThrough","transformPipeableStreamWithRouter"],"mappings":";;;;;;AAWO,MAAM,uBAAuB,OAAO;AAAA,EACzC;AAAA,EACA;AAAA,EACA;AAAA,EACA;AACF,MAKM;AACA,MAAA,OAAO,eAAe,2BAA2B,YAAY;AAC/D,UAAM,SAAS,MAAM,eAAe,uBAAuB,UAAU;AAAA,MACnE,QAAQ,QAAQ;AAAA,IAAA,CACjB;AAED,QAAIA,MAAAA,MAAM,QAAQ,QAAQ,IAAI,YAAY,CAAC,GAAG;AAC5C,YAAM,OAAO;AAAA,IAAA;AAGf,UAAM,iBAAiBC,OAAA;AAAA,MACrB;AAAA,MACA;AAAA,IACF;AACO,WAAA,IAAI,SAAS,gBAAuB;AAAA,MACzC,QAAQ,OAAO,MAAM;AAAA,MACrB,SAAS;AAAA,IAAA,CACV;AAAA,EAAA;AAGC,MAAA,OAAO,eAAe,2BAA2B,YAAY;AACzD,UAAA,sBAAsB,IAAIC,wBAAY;AAExC,QAAA;AACI,YAAA,WAAW,eAAe,uBAAuB,UAAU;AAAA,QAC/D,GAAIF,MAAAA,MAAM,QAAQ,QAAQ,IAAI,YAAY,CAAC,IACvC;AAAA,UACE,aAAa;AACX,qBAAS,KAAK,mBAAmB;AAAA,UAAA;AAAA,QACnC,IAEF;AAAA,UACE,eAAe;AACb,qBAAS,KAAK,mBAAmB;AAAA,UAAA;AAAA,QAErC;AAAA,QACJ,SAAS,CAAC,OAAO,SAAS;AAChB,kBAAA,MAAM,oCAAoC,OAAO,IAAI;AAAA,QAAA;AAAA,MAC/D,CACD;AAAA,aACM,GAAG;AACF,cAAA,MAAM,oCAAoC,CAAC;AAAA,IAAA;AAGrD,UAAM,iBAAiBG,OAAA;AAAA,MACrB;AAAA,MACA;AAAA,IACF;AACO,WAAA,IAAI,SAAS,gBAAuB;AAAA,MACzC,QAAQ,OAAO,MAAM;AAAA,MACrB,SAAS;AAAA,IAAA,CACV;AAAA,EAAA;AAGH,QAAM,IAAI;AAAA,IACR;AAAA,EACF;AACF;;"}
|
package/dist/esm/Match.js
CHANGED
|
@@ -2,7 +2,7 @@ import { jsxs, jsx, Fragment } from "react/jsx-runtime";
|
|
|
2
2
|
import * as React from "react";
|
|
3
3
|
import invariant from "tiny-invariant";
|
|
4
4
|
import warning from "tiny-warning";
|
|
5
|
-
import { isNotFound, rootRouteId, pick,
|
|
5
|
+
import { isNotFound, rootRouteId, pick, createControlledPromise, isRedirect, getLocationChangeInfo } from "@tanstack/router-core";
|
|
6
6
|
import { CatchBoundary, ErrorComponent } from "./CatchBoundary.js";
|
|
7
7
|
import { useRouterState } from "./useRouterState.js";
|
|
8
8
|
import { useRouter } from "./useRouter.js";
|
|
@@ -11,22 +11,24 @@ import { matchContext } from "./matchContext.js";
|
|
|
11
11
|
import { SafeFragment } from "./SafeFragment.js";
|
|
12
12
|
import { renderRouteNotFound } from "./renderRouteNotFound.js";
|
|
13
13
|
import { ScrollRestoration } from "./scroll-restoration.js";
|
|
14
|
+
import { ClientOnly } from "./ClientOnly.js";
|
|
14
15
|
const Match = React.memo(function MatchImpl({
|
|
15
16
|
matchId
|
|
16
17
|
}) {
|
|
17
18
|
var _a, _b;
|
|
18
19
|
const router = useRouter();
|
|
19
|
-
const
|
|
20
|
+
const matchState = useRouterState({
|
|
20
21
|
select: (s) => {
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
22
|
+
const match = s.matches.find((d) => d.id === matchId);
|
|
23
|
+
invariant(
|
|
24
|
+
match,
|
|
25
|
+
`Could not find match for matchId "${matchId}". Please file an issue!`
|
|
26
|
+
);
|
|
27
|
+
return pick(match, ["routeId", "ssr", "_displayPending"]);
|
|
28
|
+
},
|
|
29
|
+
structuralSharing: true
|
|
24
30
|
});
|
|
25
|
-
|
|
26
|
-
routeId,
|
|
27
|
-
`Could not find routeId for matchId "${matchId}". Please file an issue!`
|
|
28
|
-
);
|
|
29
|
-
const route = router.routesById[routeId];
|
|
31
|
+
const route = router.routesById[matchState.routeId];
|
|
30
32
|
const PendingComponent = route.options.pendingComponent ?? router.options.defaultPendingComponent;
|
|
31
33
|
const pendingElement = PendingComponent ? /* @__PURE__ */ jsx(PendingComponent, {}) : null;
|
|
32
34
|
const routeErrorComponent = route.options.errorComponent ?? router.options.defaultErrorComponent;
|
|
@@ -35,9 +37,10 @@ const Match = React.memo(function MatchImpl({
|
|
|
35
37
|
// If it's the root route, use the globalNotFound option, with fallback to the notFoundRoute's component
|
|
36
38
|
route.options.notFoundComponent ?? ((_a = router.options.notFoundRoute) == null ? void 0 : _a.options.component)
|
|
37
39
|
) : route.options.notFoundComponent;
|
|
40
|
+
const resolvedNoSsr = matchState.ssr === false || matchState.ssr === "data-only";
|
|
38
41
|
const ResolvedSuspenseBoundary = (
|
|
39
42
|
// If we're on the root route, allow forcefully wrapping in suspense
|
|
40
|
-
(!route.isRoot || route.options.wrapInSuspense) && (route.options.wrapInSuspense ?? PendingComponent ?? ((_b = route.options.errorComponent) == null ? void 0 : _b.preload)) ? React.Suspense : SafeFragment
|
|
43
|
+
(!route.isRoot || route.options.wrapInSuspense || resolvedNoSsr) && (route.options.wrapInSuspense ?? PendingComponent ?? (((_b = route.options.errorComponent) == null ? void 0 : _b.preload) || resolvedNoSsr)) ? React.Suspense : SafeFragment
|
|
41
44
|
);
|
|
42
45
|
const ResolvedCatchBoundary = routeErrorComponent ? CatchBoundary : SafeFragment;
|
|
43
46
|
const ResolvedNotFoundBoundary = routeNotFoundComponent ? CatchNotFound : SafeFragment;
|
|
@@ -67,11 +70,11 @@ const Match = React.memo(function MatchImpl({
|
|
|
67
70
|
ResolvedNotFoundBoundary,
|
|
68
71
|
{
|
|
69
72
|
fallback: (error) => {
|
|
70
|
-
if (!routeNotFoundComponent || error.routeId && error.routeId !== routeId || !error.routeId && !route.isRoot)
|
|
73
|
+
if (!routeNotFoundComponent || error.routeId && error.routeId !== matchState.routeId || !error.routeId && !route.isRoot)
|
|
71
74
|
throw error;
|
|
72
75
|
return React.createElement(routeNotFoundComponent, error);
|
|
73
76
|
},
|
|
74
|
-
children: /* @__PURE__ */ jsx(MatchInner, { matchId })
|
|
77
|
+
children: resolvedNoSsr || router.isShell || matchState._displayPending ? /* @__PURE__ */ jsx(ClientOnly, { fallback: pendingElement, children: /* @__PURE__ */ jsx(MatchInner, { matchId }) }) : /* @__PURE__ */ jsx(MatchInner, { matchId })
|
|
75
78
|
}
|
|
76
79
|
)
|
|
77
80
|
}
|
|
@@ -107,7 +110,7 @@ function OnRendered() {
|
|
|
107
110
|
const MatchInner = React.memo(function MatchInnerImpl({
|
|
108
111
|
matchId
|
|
109
112
|
}) {
|
|
110
|
-
var _a, _b, _c;
|
|
113
|
+
var _a, _b, _c, _d;
|
|
111
114
|
const router = useRouter();
|
|
112
115
|
const { match, key, routeId } = useRouterState({
|
|
113
116
|
select: (s) => {
|
|
@@ -125,7 +128,13 @@ const MatchInner = React.memo(function MatchInnerImpl({
|
|
|
125
128
|
return {
|
|
126
129
|
key: key2,
|
|
127
130
|
routeId: routeId2,
|
|
128
|
-
match: pick(match2, [
|
|
131
|
+
match: pick(match2, [
|
|
132
|
+
"id",
|
|
133
|
+
"status",
|
|
134
|
+
"error",
|
|
135
|
+
"_forcePending",
|
|
136
|
+
"_displayPending"
|
|
137
|
+
])
|
|
129
138
|
};
|
|
130
139
|
},
|
|
131
140
|
structuralSharing: true
|
|
@@ -138,31 +147,10 @@ const MatchInner = React.memo(function MatchInnerImpl({
|
|
|
138
147
|
}
|
|
139
148
|
return /* @__PURE__ */ jsx(Outlet, {});
|
|
140
149
|
}, [key, route.options.component, router.options.defaultComponent]);
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
invariant(isNotFound(match.error), "Expected a notFound error");
|
|
144
|
-
return renderRouteNotFound(router, route, match.error);
|
|
150
|
+
if (match._displayPending) {
|
|
151
|
+
throw (_a = router.getMatch(match.id)) == null ? void 0 : _a.displayPendingPromise;
|
|
145
152
|
}
|
|
146
|
-
if (match.status === "
|
|
147
|
-
invariant(isRedirect(match.error), "Expected a redirect error");
|
|
148
|
-
throw (_a = router.getMatch(match.id)) == null ? void 0 : _a.loadPromise;
|
|
149
|
-
}
|
|
150
|
-
if (match.status === "error") {
|
|
151
|
-
if (router.isServer) {
|
|
152
|
-
return /* @__PURE__ */ jsx(
|
|
153
|
-
RouteErrorComponent,
|
|
154
|
-
{
|
|
155
|
-
error: match.error,
|
|
156
|
-
reset: void 0,
|
|
157
|
-
info: {
|
|
158
|
-
componentStack: ""
|
|
159
|
-
}
|
|
160
|
-
}
|
|
161
|
-
);
|
|
162
|
-
}
|
|
163
|
-
throw match.error;
|
|
164
|
-
}
|
|
165
|
-
if (match.status === "pending") {
|
|
153
|
+
if (match.status === "pending" || match._forcePending) {
|
|
166
154
|
const pendingMinMs = route.options.pendingMinMs ?? router.options.defaultPendingMinMs;
|
|
167
155
|
if (pendingMinMs && !((_b = router.getMatch(match.id)) == null ? void 0 : _b.minPendingPromise)) {
|
|
168
156
|
if (!router.isServer) {
|
|
@@ -184,6 +172,30 @@ const MatchInner = React.memo(function MatchInnerImpl({
|
|
|
184
172
|
}
|
|
185
173
|
throw (_c = router.getMatch(match.id)) == null ? void 0 : _c.loadPromise;
|
|
186
174
|
}
|
|
175
|
+
if (match.status === "notFound") {
|
|
176
|
+
invariant(isNotFound(match.error), "Expected a notFound error");
|
|
177
|
+
return renderRouteNotFound(router, route, match.error);
|
|
178
|
+
}
|
|
179
|
+
if (match.status === "redirected") {
|
|
180
|
+
invariant(isRedirect(match.error), "Expected a redirect error");
|
|
181
|
+
throw (_d = router.getMatch(match.id)) == null ? void 0 : _d.loadPromise;
|
|
182
|
+
}
|
|
183
|
+
if (match.status === "error") {
|
|
184
|
+
if (router.isServer) {
|
|
185
|
+
const RouteErrorComponent = (route.options.errorComponent ?? router.options.defaultErrorComponent) || ErrorComponent;
|
|
186
|
+
return /* @__PURE__ */ jsx(
|
|
187
|
+
RouteErrorComponent,
|
|
188
|
+
{
|
|
189
|
+
error: match.error,
|
|
190
|
+
reset: void 0,
|
|
191
|
+
info: {
|
|
192
|
+
componentStack: ""
|
|
193
|
+
}
|
|
194
|
+
}
|
|
195
|
+
);
|
|
196
|
+
}
|
|
197
|
+
throw match.error;
|
|
198
|
+
}
|
|
187
199
|
return out;
|
|
188
200
|
});
|
|
189
201
|
const Outlet = React.memo(function OutletImpl() {
|
|
@@ -216,8 +228,6 @@ const Outlet = React.memo(function OutletImpl() {
|
|
|
216
228
|
}
|
|
217
229
|
});
|
|
218
230
|
const pendingElement = router.options.defaultPendingComponent ? /* @__PURE__ */ jsx(router.options.defaultPendingComponent, {}) : null;
|
|
219
|
-
if (router.isShell)
|
|
220
|
-
return /* @__PURE__ */ jsx(React.Suspense, { fallback: pendingElement, children: /* @__PURE__ */ jsx(ShellInner, {}) });
|
|
221
231
|
if (parentGlobalNotFound) {
|
|
222
232
|
return renderRouteNotFound(router, route, void 0);
|
|
223
233
|
}
|
|
@@ -230,9 +240,6 @@ const Outlet = React.memo(function OutletImpl() {
|
|
|
230
240
|
}
|
|
231
241
|
return nextMatch;
|
|
232
242
|
});
|
|
233
|
-
function ShellInner() {
|
|
234
|
-
throw new Error("ShellBoundaryError");
|
|
235
|
-
}
|
|
236
243
|
export {
|
|
237
244
|
Match,
|
|
238
245
|
MatchInner,
|
package/dist/esm/Match.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"Match.js","sources":["../../src/Match.tsx"],"sourcesContent":["import * as React from 'react'\nimport invariant from 'tiny-invariant'\nimport warning from 'tiny-warning'\nimport {\n createControlledPromise,\n getLocationChangeInfo,\n isNotFound,\n isRedirect,\n pick,\n rootRouteId,\n} from '@tanstack/router-core'\nimport { CatchBoundary, ErrorComponent } from './CatchBoundary'\nimport { useRouterState } from './useRouterState'\nimport { useRouter } from './useRouter'\nimport { CatchNotFound } from './not-found'\nimport { matchContext } from './matchContext'\nimport { SafeFragment } from './SafeFragment'\nimport { renderRouteNotFound } from './renderRouteNotFound'\nimport { ScrollRestoration } from './scroll-restoration'\nimport type {\n AnyRoute,\n ParsedLocation,\n RootRouteOptions,\n} from '@tanstack/router-core'\n\nexport const Match = React.memo(function MatchImpl({\n matchId,\n}: {\n matchId: string\n}) {\n const router = useRouter()\n const routeId = useRouterState({\n select: (s) => s.matches.find((d) => d.id === matchId)?.routeId as string,\n })\n\n invariant(\n routeId,\n `Could not find routeId for matchId \"${matchId}\". Please file an issue!`,\n )\n\n const route: AnyRoute = router.routesById[routeId]\n\n const PendingComponent =\n route.options.pendingComponent ?? router.options.defaultPendingComponent\n\n const pendingElement = PendingComponent ? <PendingComponent /> : null\n\n const routeErrorComponent =\n route.options.errorComponent ?? router.options.defaultErrorComponent\n\n const routeOnCatch = route.options.onCatch ?? router.options.defaultOnCatch\n\n const routeNotFoundComponent = route.isRoot\n ? // If it's the root route, use the globalNotFound option, with fallback to the notFoundRoute's component\n (route.options.notFoundComponent ??\n router.options.notFoundRoute?.options.component)\n : route.options.notFoundComponent\n\n const ResolvedSuspenseBoundary =\n // If we're on the root route, allow forcefully wrapping in suspense\n (!route.isRoot || route.options.wrapInSuspense) &&\n (route.options.wrapInSuspense ??\n PendingComponent ??\n (route.options.errorComponent as any)?.preload)\n ? React.Suspense\n : SafeFragment\n\n const ResolvedCatchBoundary = routeErrorComponent\n ? CatchBoundary\n : SafeFragment\n\n const ResolvedNotFoundBoundary = routeNotFoundComponent\n ? CatchNotFound\n : SafeFragment\n\n const resetKey = useRouterState({\n select: (s) => s.loadedAt,\n })\n\n const parentRouteId = useRouterState({\n select: (s) => {\n const index = s.matches.findIndex((d) => d.id === matchId)\n return s.matches[index - 1]?.routeId as string\n },\n })\n\n const ShellComponent = route.isRoot\n ? ((route.options as RootRouteOptions).shellComponent ?? SafeFragment)\n : SafeFragment\n return (\n <ShellComponent>\n <matchContext.Provider value={matchId}>\n <ResolvedSuspenseBoundary fallback={pendingElement}>\n <ResolvedCatchBoundary\n getResetKey={() => resetKey}\n errorComponent={routeErrorComponent || ErrorComponent}\n onCatch={(error, errorInfo) => {\n // Forward not found errors (we don't want to show the error component for these)\n if (isNotFound(error)) throw error\n warning(false, `Error in route match: ${matchId}`)\n routeOnCatch?.(error, errorInfo)\n }}\n >\n <ResolvedNotFoundBoundary\n fallback={(error) => {\n // If the current not found handler doesn't exist or it has a\n // route ID which doesn't match the current route, rethrow the error\n if (\n !routeNotFoundComponent ||\n (error.routeId && error.routeId !== routeId) ||\n (!error.routeId && !route.isRoot)\n )\n throw error\n\n return React.createElement(routeNotFoundComponent, error as any)\n }}\n >\n <MatchInner matchId={matchId} />\n </ResolvedNotFoundBoundary>\n </ResolvedCatchBoundary>\n </ResolvedSuspenseBoundary>\n </matchContext.Provider>\n {parentRouteId === rootRouteId && router.options.scrollRestoration ? (\n <>\n <OnRendered />\n <ScrollRestoration />\n </>\n ) : null}\n </ShellComponent>\n )\n})\n\n// On Rendered can't happen above the root layout because it actually\n// renders a dummy dom element to track the rendered state of the app.\n// We render a script tag with a key that changes based on the current\n// location state.__TSR_key. Also, because it's below the root layout, it\n// allows us to fire onRendered events even after a hydration mismatch\n// error that occurred above the root layout (like bad head/link tags,\n// which is common).\nfunction OnRendered() {\n const router = useRouter()\n\n const prevLocationRef = React.useRef<undefined | ParsedLocation<{}>>(\n undefined,\n )\n\n return (\n <script\n key={router.latestLocation.state.__TSR_key}\n suppressHydrationWarning\n ref={(el) => {\n if (\n el &&\n (prevLocationRef.current === undefined ||\n prevLocationRef.current.href !== router.latestLocation.href)\n ) {\n router.emit({\n type: 'onRendered',\n ...getLocationChangeInfo(router.state),\n })\n prevLocationRef.current = router.latestLocation\n }\n }}\n />\n )\n}\n\nexport const MatchInner = React.memo(function MatchInnerImpl({\n matchId,\n}: {\n matchId: string\n}): any {\n const router = useRouter()\n\n const { match, key, routeId } = useRouterState({\n select: (s) => {\n const matchIndex = s.matches.findIndex((d) => d.id === matchId)\n const match = s.matches[matchIndex]!\n const routeId = match.routeId as string\n\n const remountFn =\n (router.routesById[routeId] as AnyRoute).options.remountDeps ??\n router.options.defaultRemountDeps\n const remountDeps = remountFn?.({\n routeId,\n loaderDeps: match.loaderDeps,\n params: match._strictParams,\n search: match._strictSearch,\n })\n const key = remountDeps ? JSON.stringify(remountDeps) : undefined\n\n return {\n key,\n routeId,\n match: pick(match, ['id', 'status', 'error']),\n }\n },\n structuralSharing: true as any,\n })\n\n const route = router.routesById[routeId] as AnyRoute\n\n const out = React.useMemo(() => {\n const Comp = route.options.component ?? router.options.defaultComponent\n if (Comp) {\n return <Comp key={key} />\n }\n return <Outlet />\n }, [key, route.options.component, router.options.defaultComponent])\n\n const RouteErrorComponent =\n (route.options.errorComponent ?? router.options.defaultErrorComponent) ||\n ErrorComponent\n\n if (match.status === 'notFound') {\n invariant(isNotFound(match.error), 'Expected a notFound error')\n return renderRouteNotFound(router, route, match.error)\n }\n\n if (match.status === 'redirected') {\n // Redirects should be handled by the router transition. If we happen to\n // encounter a redirect here, it's a bug. Let's warn, but render nothing.\n invariant(isRedirect(match.error), 'Expected a redirect error')\n\n // warning(\n // false,\n // 'Tried to render a redirected route match! This is a weird circumstance, please file an issue!',\n // )\n throw router.getMatch(match.id)?.loadPromise\n }\n\n if (match.status === 'error') {\n // If we're on the server, we need to use React's new and super\n // wonky api for throwing errors from a server side render inside\n // of a suspense boundary. This is the only way to get\n // renderToPipeableStream to not hang indefinitely.\n // We'll serialize the error and rethrow it on the client.\n if (router.isServer) {\n return (\n <RouteErrorComponent\n error={match.error as any}\n reset={undefined as any}\n info={{\n componentStack: '',\n }}\n />\n )\n }\n\n throw match.error\n }\n\n if (match.status === 'pending') {\n // We're pending, and if we have a minPendingMs, we need to wait for it\n const pendingMinMs =\n route.options.pendingMinMs ?? router.options.defaultPendingMinMs\n\n if (pendingMinMs && !router.getMatch(match.id)?.minPendingPromise) {\n // Create a promise that will resolve after the minPendingMs\n if (!router.isServer) {\n const minPendingPromise = createControlledPromise<void>()\n\n Promise.resolve().then(() => {\n router.updateMatch(match.id, (prev) => ({\n ...prev,\n minPendingPromise,\n }))\n })\n\n setTimeout(() => {\n minPendingPromise.resolve()\n\n // We've handled the minPendingPromise, so we can delete it\n router.updateMatch(match.id, (prev) => ({\n ...prev,\n minPendingPromise: undefined,\n }))\n }, pendingMinMs)\n }\n }\n throw router.getMatch(match.id)?.loadPromise\n }\n\n return out\n})\n\nexport const Outlet = React.memo(function OutletImpl() {\n const router = useRouter()\n const matchId = React.useContext(matchContext)\n const routeId = useRouterState({\n select: (s) => s.matches.find((d) => d.id === matchId)?.routeId as string,\n })\n\n const route = router.routesById[routeId]!\n\n const parentGlobalNotFound = useRouterState({\n select: (s) => {\n const matches = s.matches\n const parentMatch = matches.find((d) => d.id === matchId)\n invariant(\n parentMatch,\n `Could not find parent match for matchId \"${matchId}\"`,\n )\n return parentMatch.globalNotFound\n },\n })\n\n const childMatchId = useRouterState({\n select: (s) => {\n const matches = s.matches\n const index = matches.findIndex((d) => d.id === matchId)\n return matches[index + 1]?.id\n },\n })\n\n const pendingElement = router.options.defaultPendingComponent ? (\n <router.options.defaultPendingComponent />\n ) : null\n\n if (router.isShell)\n return (\n <React.Suspense fallback={pendingElement}>\n <ShellInner />\n </React.Suspense>\n )\n\n if (parentGlobalNotFound) {\n return renderRouteNotFound(router, route, undefined)\n }\n\n if (!childMatchId) {\n return null\n }\n\n const nextMatch = <Match matchId={childMatchId} />\n\n if (matchId === rootRouteId) {\n return (\n <React.Suspense fallback={pendingElement}>{nextMatch}</React.Suspense>\n )\n }\n\n return nextMatch\n})\n\nfunction ShellInner(): React.ReactElement {\n throw new Error('ShellBoundaryError')\n}\n"],"names":["_a","match","routeId","key"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"Match.js","sources":["../../src/Match.tsx"],"sourcesContent":["import * as React from 'react'\nimport invariant from 'tiny-invariant'\nimport warning from 'tiny-warning'\nimport {\n createControlledPromise,\n getLocationChangeInfo,\n isNotFound,\n isRedirect,\n pick,\n rootRouteId,\n} from '@tanstack/router-core'\nimport { CatchBoundary, ErrorComponent } from './CatchBoundary'\nimport { useRouterState } from './useRouterState'\nimport { useRouter } from './useRouter'\nimport { CatchNotFound } from './not-found'\nimport { matchContext } from './matchContext'\nimport { SafeFragment } from './SafeFragment'\nimport { renderRouteNotFound } from './renderRouteNotFound'\nimport { ScrollRestoration } from './scroll-restoration'\nimport { ClientOnly } from './ClientOnly'\nimport type {\n AnyRoute,\n ParsedLocation,\n RootRouteOptions,\n} from '@tanstack/router-core'\n\nexport const Match = React.memo(function MatchImpl({\n matchId,\n}: {\n matchId: string\n}) {\n const router = useRouter()\n const matchState = useRouterState({\n select: (s) => {\n const match = s.matches.find((d) => d.id === matchId)\n invariant(\n match,\n `Could not find match for matchId \"${matchId}\". Please file an issue!`,\n )\n return pick(match, ['routeId', 'ssr', '_displayPending'])\n },\n structuralSharing: true as any,\n })\n\n const route: AnyRoute = router.routesById[matchState.routeId]\n\n const PendingComponent =\n route.options.pendingComponent ?? router.options.defaultPendingComponent\n\n const pendingElement = PendingComponent ? <PendingComponent /> : null\n\n const routeErrorComponent =\n route.options.errorComponent ?? router.options.defaultErrorComponent\n\n const routeOnCatch = route.options.onCatch ?? router.options.defaultOnCatch\n\n const routeNotFoundComponent = route.isRoot\n ? // If it's the root route, use the globalNotFound option, with fallback to the notFoundRoute's component\n (route.options.notFoundComponent ??\n router.options.notFoundRoute?.options.component)\n : route.options.notFoundComponent\n\n const resolvedNoSsr =\n matchState.ssr === false || matchState.ssr === 'data-only'\n const ResolvedSuspenseBoundary =\n // If we're on the root route, allow forcefully wrapping in suspense\n (!route.isRoot || route.options.wrapInSuspense || resolvedNoSsr) &&\n (route.options.wrapInSuspense ??\n PendingComponent ??\n ((route.options.errorComponent as any)?.preload || resolvedNoSsr))\n ? React.Suspense\n : SafeFragment\n\n const ResolvedCatchBoundary = routeErrorComponent\n ? CatchBoundary\n : SafeFragment\n\n const ResolvedNotFoundBoundary = routeNotFoundComponent\n ? CatchNotFound\n : SafeFragment\n\n const resetKey = useRouterState({\n select: (s) => s.loadedAt,\n })\n\n const parentRouteId = useRouterState({\n select: (s) => {\n const index = s.matches.findIndex((d) => d.id === matchId)\n return s.matches[index - 1]?.routeId as string\n },\n })\n\n const ShellComponent = route.isRoot\n ? ((route.options as RootRouteOptions).shellComponent ?? SafeFragment)\n : SafeFragment\n return (\n <ShellComponent>\n <matchContext.Provider value={matchId}>\n <ResolvedSuspenseBoundary fallback={pendingElement}>\n <ResolvedCatchBoundary\n getResetKey={() => resetKey}\n errorComponent={routeErrorComponent || ErrorComponent}\n onCatch={(error, errorInfo) => {\n // Forward not found errors (we don't want to show the error component for these)\n if (isNotFound(error)) throw error\n warning(false, `Error in route match: ${matchId}`)\n routeOnCatch?.(error, errorInfo)\n }}\n >\n <ResolvedNotFoundBoundary\n fallback={(error) => {\n // If the current not found handler doesn't exist or it has a\n // route ID which doesn't match the current route, rethrow the error\n if (\n !routeNotFoundComponent ||\n (error.routeId && error.routeId !== matchState.routeId) ||\n (!error.routeId && !route.isRoot)\n )\n throw error\n\n return React.createElement(routeNotFoundComponent, error as any)\n }}\n >\n {resolvedNoSsr || router.isShell || matchState._displayPending ? (\n <ClientOnly fallback={pendingElement}>\n <MatchInner matchId={matchId} />\n </ClientOnly>\n ) : (\n <MatchInner matchId={matchId} />\n )}\n </ResolvedNotFoundBoundary>\n </ResolvedCatchBoundary>\n </ResolvedSuspenseBoundary>\n </matchContext.Provider>\n {parentRouteId === rootRouteId && router.options.scrollRestoration ? (\n <>\n <OnRendered />\n <ScrollRestoration />\n </>\n ) : null}\n </ShellComponent>\n )\n})\n\n// On Rendered can't happen above the root layout because it actually\n// renders a dummy dom element to track the rendered state of the app.\n// We render a script tag with a key that changes based on the current\n// location state.__TSR_key. Also, because it's below the root layout, it\n// allows us to fire onRendered events even after a hydration mismatch\n// error that occurred above the root layout (like bad head/link tags,\n// which is common).\nfunction OnRendered() {\n const router = useRouter()\n\n const prevLocationRef = React.useRef<undefined | ParsedLocation<{}>>(\n undefined,\n )\n\n return (\n <script\n key={router.latestLocation.state.__TSR_key}\n suppressHydrationWarning\n ref={(el) => {\n if (\n el &&\n (prevLocationRef.current === undefined ||\n prevLocationRef.current.href !== router.latestLocation.href)\n ) {\n router.emit({\n type: 'onRendered',\n ...getLocationChangeInfo(router.state),\n })\n prevLocationRef.current = router.latestLocation\n }\n }}\n />\n )\n}\n\nexport const MatchInner = React.memo(function MatchInnerImpl({\n matchId,\n}: {\n matchId: string\n}): any {\n const router = useRouter()\n\n const { match, key, routeId } = useRouterState({\n select: (s) => {\n const matchIndex = s.matches.findIndex((d) => d.id === matchId)\n const match = s.matches[matchIndex]!\n const routeId = match.routeId as string\n\n const remountFn =\n (router.routesById[routeId] as AnyRoute).options.remountDeps ??\n router.options.defaultRemountDeps\n const remountDeps = remountFn?.({\n routeId,\n loaderDeps: match.loaderDeps,\n params: match._strictParams,\n search: match._strictSearch,\n })\n const key = remountDeps ? JSON.stringify(remountDeps) : undefined\n\n return {\n key,\n routeId,\n match: pick(match, [\n 'id',\n 'status',\n 'error',\n '_forcePending',\n '_displayPending',\n ]),\n }\n },\n structuralSharing: true as any,\n })\n\n const route = router.routesById[routeId] as AnyRoute\n\n const out = React.useMemo(() => {\n const Comp = route.options.component ?? router.options.defaultComponent\n if (Comp) {\n return <Comp key={key} />\n }\n return <Outlet />\n }, [key, route.options.component, router.options.defaultComponent])\n\n if (match._displayPending) {\n throw router.getMatch(match.id)?.displayPendingPromise\n }\n\n // see also triggerOnReady() in packages/router-core/src/router.ts\n if (match.status === 'pending' || match._forcePending) {\n // We're pending, and if we have a minPendingMs, we need to wait for it\n const pendingMinMs =\n route.options.pendingMinMs ?? router.options.defaultPendingMinMs\n\n if (pendingMinMs && !router.getMatch(match.id)?.minPendingPromise) {\n // Create a promise that will resolve after the minPendingMs\n if (!router.isServer) {\n const minPendingPromise = createControlledPromise<void>()\n\n Promise.resolve().then(() => {\n router.updateMatch(match.id, (prev) => ({\n ...prev,\n minPendingPromise,\n }))\n })\n\n setTimeout(() => {\n minPendingPromise.resolve()\n\n // We've handled the minPendingPromise, so we can delete it\n router.updateMatch(match.id, (prev) => ({\n ...prev,\n minPendingPromise: undefined,\n }))\n }, pendingMinMs)\n }\n }\n throw router.getMatch(match.id)?.loadPromise\n }\n\n if (match.status === 'notFound') {\n invariant(isNotFound(match.error), 'Expected a notFound error')\n return renderRouteNotFound(router, route, match.error)\n }\n\n if (match.status === 'redirected') {\n // Redirects should be handled by the router transition. If we happen to\n // encounter a redirect here, it's a bug. Let's warn, but render nothing.\n invariant(isRedirect(match.error), 'Expected a redirect error')\n\n // warning(\n // false,\n // 'Tried to render a redirected route match! This is a weird circumstance, please file an issue!',\n // )\n throw router.getMatch(match.id)?.loadPromise\n }\n\n if (match.status === 'error') {\n // If we're on the server, we need to use React's new and super\n // wonky api for throwing errors from a server side render inside\n // of a suspense boundary. This is the only way to get\n // renderToPipeableStream to not hang indefinitely.\n // We'll serialize the error and rethrow it on the client.\n if (router.isServer) {\n const RouteErrorComponent =\n (route.options.errorComponent ??\n router.options.defaultErrorComponent) ||\n ErrorComponent\n return (\n <RouteErrorComponent\n error={match.error as any}\n reset={undefined as any}\n info={{\n componentStack: '',\n }}\n />\n )\n }\n\n throw match.error\n }\n\n return out\n})\n\nexport const Outlet = React.memo(function OutletImpl() {\n const router = useRouter()\n const matchId = React.useContext(matchContext)\n const routeId = useRouterState({\n select: (s) => s.matches.find((d) => d.id === matchId)?.routeId as string,\n })\n\n const route = router.routesById[routeId]!\n\n const parentGlobalNotFound = useRouterState({\n select: (s) => {\n const matches = s.matches\n const parentMatch = matches.find((d) => d.id === matchId)\n invariant(\n parentMatch,\n `Could not find parent match for matchId \"${matchId}\"`,\n )\n return parentMatch.globalNotFound\n },\n })\n\n const childMatchId = useRouterState({\n select: (s) => {\n const matches = s.matches\n const index = matches.findIndex((d) => d.id === matchId)\n return matches[index + 1]?.id\n },\n })\n\n const pendingElement = router.options.defaultPendingComponent ? (\n <router.options.defaultPendingComponent />\n ) : null\n\n if (parentGlobalNotFound) {\n return renderRouteNotFound(router, route, undefined)\n }\n\n if (!childMatchId) {\n return null\n }\n\n const nextMatch = <Match matchId={childMatchId} />\n\n if (matchId === rootRouteId) {\n return (\n <React.Suspense fallback={pendingElement}>{nextMatch}</React.Suspense>\n )\n }\n\n return nextMatch\n})\n"],"names":["_a","match","routeId","key"],"mappings":"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"}
|
|
@@ -1,2 +1,2 @@
|
|
|
1
1
|
import { AsyncRouteComponent } from './route.js';
|
|
2
|
-
export declare function lazyRouteComponent<T extends Record<string, any>, TKey extends keyof T = 'default'>(importer: () => Promise<T>, exportName?: TKey
|
|
2
|
+
export declare function lazyRouteComponent<T extends Record<string, any>, TKey extends keyof T = 'default'>(importer: () => Promise<T>, exportName?: TKey): T[TKey] extends (props: infer TProps) => any ? AsyncRouteComponent<TProps> : never;
|
|
@@ -1,21 +1,11 @@
|
|
|
1
|
-
import { jsx } from "react/jsx-runtime";
|
|
2
1
|
import * as React from "react";
|
|
3
|
-
import {
|
|
4
|
-
|
|
5
|
-
function isModuleNotFoundError(error) {
|
|
6
|
-
if (typeof (error == null ? void 0 : error.message) !== "string") return false;
|
|
7
|
-
return error.message.startsWith("Failed to fetch dynamically imported module") || error.message.startsWith("error loading dynamically imported module") || error.message.startsWith("Importing a module script failed");
|
|
8
|
-
}
|
|
9
|
-
function lazyRouteComponent(importer, exportName, ssr) {
|
|
2
|
+
import { isModuleNotFoundError } from "@tanstack/router-core";
|
|
3
|
+
function lazyRouteComponent(importer, exportName) {
|
|
10
4
|
let loadPromise;
|
|
11
5
|
let comp;
|
|
12
6
|
let error;
|
|
13
7
|
let reload;
|
|
14
8
|
const load = () => {
|
|
15
|
-
if (typeof document === "undefined" && (ssr == null ? void 0 : ssr()) === false) {
|
|
16
|
-
comp = () => null;
|
|
17
|
-
return Promise.resolve();
|
|
18
|
-
}
|
|
19
9
|
if (!loadPromise) {
|
|
20
10
|
loadPromise = importer().then((res) => {
|
|
21
11
|
loadPromise = void 0;
|
|
@@ -47,9 +37,6 @@ function lazyRouteComponent(importer, exportName, ssr) {
|
|
|
47
37
|
if (!comp) {
|
|
48
38
|
throw load();
|
|
49
39
|
}
|
|
50
|
-
if ((ssr == null ? void 0 : ssr()) === false) {
|
|
51
|
-
return /* @__PURE__ */ jsx(ClientOnly, { fallback: /* @__PURE__ */ jsx(Outlet, {}), children: React.createElement(comp, props) });
|
|
52
|
-
}
|
|
53
40
|
return React.createElement(comp, props);
|
|
54
41
|
};
|
|
55
42
|
lazyComp.preload = load;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"lazyRouteComponent.js","sources":["../../src/lazyRouteComponent.tsx"],"sourcesContent":["import * as React from 'react'\nimport {
|
|
1
|
+
{"version":3,"file":"lazyRouteComponent.js","sources":["../../src/lazyRouteComponent.tsx"],"sourcesContent":["import * as React from 'react'\nimport { isModuleNotFoundError } from '@tanstack/router-core'\nimport type { AsyncRouteComponent } from './route'\n\nexport function lazyRouteComponent<\n T extends Record<string, any>,\n TKey extends keyof T = 'default',\n>(\n importer: () => Promise<T>,\n exportName?: TKey,\n): T[TKey] extends (props: infer TProps) => any\n ? AsyncRouteComponent<TProps>\n : never {\n let loadPromise: Promise<any> | undefined\n let comp: T[TKey] | T['default']\n let error: any\n let reload: boolean\n\n const load = () => {\n if (!loadPromise) {\n loadPromise = importer()\n .then((res) => {\n loadPromise = undefined\n comp = res[exportName ?? 'default']\n })\n .catch((err) => {\n // We don't want an error thrown from preload in this case, because\n // there's nothing we want to do about module not found during preload.\n // Record the error, the rest is handled during the render path.\n error = err\n // If the load fails due to module not found, it may mean a new version of\n // the build was deployed and the user's browser is still using an old version.\n // If this happens, the old version in the user's browser would have an outdated\n // URL to the lazy module.\n // In that case, we want to attempt one window refresh to get the latest.\n if (isModuleNotFoundError(error)) {\n if (\n error instanceof Error &&\n typeof window !== 'undefined' &&\n typeof sessionStorage !== 'undefined'\n ) {\n // Again, we want to reload one time on module not found error and not enter\n // a reload loop if there is some other issue besides an old deploy.\n // That's why we store our reload attempt in sessionStorage.\n // Use error.message as key because it contains the module path that failed.\n const storageKey = `tanstack_router_reload:${error.message}`\n if (!sessionStorage.getItem(storageKey)) {\n sessionStorage.setItem(storageKey, '1')\n reload = true\n }\n }\n }\n })\n }\n\n return loadPromise\n }\n\n const lazyComp = function Lazy(props: any) {\n // Now that we're out of preload and into actual render path,\n if (reload) {\n // If it was a module loading error,\n // throw eternal suspense while we wait for window to reload\n window.location.reload()\n throw new Promise(() => {})\n }\n if (error) {\n // Otherwise, just throw the error\n throw error\n }\n\n if (!comp) {\n throw load()\n }\n\n return React.createElement(comp, props)\n }\n\n ;(lazyComp as any).preload = load\n\n return lazyComp as any\n}\n"],"names":[],"mappings":";;AAIgB,SAAA,mBAId,UACA,YAGQ;AACJ,MAAA;AACA,MAAA;AACA,MAAA;AACA,MAAA;AAEJ,QAAM,OAAO,MAAM;AACjB,QAAI,CAAC,aAAa;AAChB,oBAAc,SAAS,EACpB,KAAK,CAAC,QAAQ;AACC,sBAAA;AACP,eAAA,IAAI,cAAc,SAAS;AAAA,MAAA,CACnC,EACA,MAAM,CAAC,QAAQ;AAIN,gBAAA;AAMJ,YAAA,sBAAsB,KAAK,GAAG;AAChC,cACE,iBAAiB,SACjB,OAAO,WAAW,eAClB,OAAO,mBAAmB,aAC1B;AAKM,kBAAA,aAAa,0BAA0B,MAAM,OAAO;AAC1D,gBAAI,CAAC,eAAe,QAAQ,UAAU,GAAG;AACxB,6BAAA,QAAQ,YAAY,GAAG;AAC7B,uBAAA;AAAA,YAAA;AAAA,UACX;AAAA,QACF;AAAA,MACF,CACD;AAAA,IAAA;AAGE,WAAA;AAAA,EACT;AAEM,QAAA,WAAW,SAAS,KAAK,OAAY;AAEzC,QAAI,QAAQ;AAGV,aAAO,SAAS,OAAO;AACjB,YAAA,IAAI,QAAQ,MAAM;AAAA,MAAA,CAAE;AAAA,IAAA;AAE5B,QAAI,OAAO;AAEH,YAAA;AAAA,IAAA;AAGR,QAAI,CAAC,MAAM;AACT,YAAM,KAAK;AAAA,IAAA;AAGN,WAAA,MAAM,cAAc,MAAM,KAAK;AAAA,EACxC;AAEE,WAAiB,UAAU;AAEtB,SAAA;AACT;"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"renderRouterToStream.js","sources":["../../../src/ssr/renderRouterToStream.tsx"],"sourcesContent":["import { PassThrough } from 'node:stream'\nimport ReactDOMServer from 'react-dom/server'\nimport { isbot } from 'isbot'\nimport {\n transformPipeableStreamWithRouter,\n transformReadableStreamWithRouter,\n} from '@tanstack/router-core/ssr/server'\nimport type {
|
|
1
|
+
{"version":3,"file":"renderRouterToStream.js","sources":["../../../src/ssr/renderRouterToStream.tsx"],"sourcesContent":["import { PassThrough } from 'node:stream'\nimport ReactDOMServer from 'react-dom/server'\nimport { isbot } from 'isbot'\nimport {\n transformPipeableStreamWithRouter,\n transformReadableStreamWithRouter,\n} from '@tanstack/router-core/ssr/server'\nimport type { AnyRouter } from '@tanstack/router-core'\nimport type { ReadableStream } from 'node:stream/web'\nimport type { ReactNode } from 'react'\n\nexport const renderRouterToStream = async ({\n request,\n router,\n responseHeaders,\n children,\n}: {\n request: Request\n router: AnyRouter\n responseHeaders: Headers\n children: ReactNode\n}) => {\n if (typeof ReactDOMServer.renderToReadableStream === 'function') {\n const stream = await ReactDOMServer.renderToReadableStream(children, {\n signal: request.signal,\n })\n\n if (isbot(request.headers.get('User-Agent'))) {\n await stream.allReady\n }\n\n const responseStream = transformReadableStreamWithRouter(\n router,\n stream as unknown as ReadableStream,\n )\n return new Response(responseStream as any, {\n status: router.state.statusCode,\n headers: responseHeaders,\n })\n }\n\n if (typeof ReactDOMServer.renderToPipeableStream === 'function') {\n const reactAppPassthrough = new PassThrough()\n\n try {\n const pipeable = ReactDOMServer.renderToPipeableStream(children, {\n ...(isbot(request.headers.get('User-Agent'))\n ? {\n onAllReady() {\n pipeable.pipe(reactAppPassthrough)\n },\n }\n : {\n onShellReady() {\n pipeable.pipe(reactAppPassthrough)\n },\n }),\n onError: (error, info) => {\n console.error('Error in renderToPipeableStream:', error, info)\n },\n })\n } catch (e) {\n console.error('Error in renderToPipeableStream:', e)\n }\n\n const responseStream = transformPipeableStreamWithRouter(\n router,\n reactAppPassthrough,\n )\n return new Response(responseStream as any, {\n status: router.state.statusCode,\n headers: responseHeaders,\n })\n }\n\n throw new Error(\n 'No renderToReadableStream or renderToPipeableStream found in react-dom/server. Ensure you are using a version of react-dom that supports streaming.',\n )\n}\n"],"names":[],"mappings":";;;;AAWO,MAAM,uBAAuB,OAAO;AAAA,EACzC;AAAA,EACA;AAAA,EACA;AAAA,EACA;AACF,MAKM;AACA,MAAA,OAAO,eAAe,2BAA2B,YAAY;AAC/D,UAAM,SAAS,MAAM,eAAe,uBAAuB,UAAU;AAAA,MACnE,QAAQ,QAAQ;AAAA,IAAA,CACjB;AAED,QAAI,MAAM,QAAQ,QAAQ,IAAI,YAAY,CAAC,GAAG;AAC5C,YAAM,OAAO;AAAA,IAAA;AAGf,UAAM,iBAAiB;AAAA,MACrB;AAAA,MACA;AAAA,IACF;AACO,WAAA,IAAI,SAAS,gBAAuB;AAAA,MACzC,QAAQ,OAAO,MAAM;AAAA,MACrB,SAAS;AAAA,IAAA,CACV;AAAA,EAAA;AAGC,MAAA,OAAO,eAAe,2BAA2B,YAAY;AACzD,UAAA,sBAAsB,IAAI,YAAY;AAExC,QAAA;AACI,YAAA,WAAW,eAAe,uBAAuB,UAAU;AAAA,QAC/D,GAAI,MAAM,QAAQ,QAAQ,IAAI,YAAY,CAAC,IACvC;AAAA,UACE,aAAa;AACX,qBAAS,KAAK,mBAAmB;AAAA,UAAA;AAAA,QACnC,IAEF;AAAA,UACE,eAAe;AACb,qBAAS,KAAK,mBAAmB;AAAA,UAAA;AAAA,QAErC;AAAA,QACJ,SAAS,CAAC,OAAO,SAAS;AAChB,kBAAA,MAAM,oCAAoC,OAAO,IAAI;AAAA,QAAA;AAAA,MAC/D,CACD;AAAA,aACM,GAAG;AACF,cAAA,MAAM,oCAAoC,CAAC;AAAA,IAAA;AAGrD,UAAM,iBAAiB;AAAA,MACrB;AAAA,MACA;AAAA,IACF;AACO,WAAA,IAAI,SAAS,gBAAuB;AAAA,MACzC,QAAQ,OAAO,MAAM;AAAA,MACrB,SAAS;AAAA,IAAA,CACV;AAAA,EAAA;AAGH,QAAM,IAAI;AAAA,IACR;AAAA,EACF;AACF;"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@tanstack/react-router",
|
|
3
|
-
"version": "1.
|
|
3
|
+
"version": "1.125.0",
|
|
4
4
|
"description": "Modern and scalable routing for React applications",
|
|
5
5
|
"author": "Tanner Linsley",
|
|
6
6
|
"license": "MIT",
|
|
@@ -81,7 +81,7 @@
|
|
|
81
81
|
"tiny-warning": "^1.0.3",
|
|
82
82
|
"isbot": "^5.1.22",
|
|
83
83
|
"@tanstack/history": "1.121.34",
|
|
84
|
-
"@tanstack/router-core": "1.
|
|
84
|
+
"@tanstack/router-core": "1.125.0"
|
|
85
85
|
},
|
|
86
86
|
"devDependencies": {
|
|
87
87
|
"@testing-library/jest-dom": "^6.6.3",
|
package/src/Match.tsx
CHANGED
|
@@ -17,6 +17,7 @@ import { matchContext } from './matchContext'
|
|
|
17
17
|
import { SafeFragment } from './SafeFragment'
|
|
18
18
|
import { renderRouteNotFound } from './renderRouteNotFound'
|
|
19
19
|
import { ScrollRestoration } from './scroll-restoration'
|
|
20
|
+
import { ClientOnly } from './ClientOnly'
|
|
20
21
|
import type {
|
|
21
22
|
AnyRoute,
|
|
22
23
|
ParsedLocation,
|
|
@@ -29,16 +30,19 @@ export const Match = React.memo(function MatchImpl({
|
|
|
29
30
|
matchId: string
|
|
30
31
|
}) {
|
|
31
32
|
const router = useRouter()
|
|
32
|
-
const
|
|
33
|
-
select: (s) =>
|
|
33
|
+
const matchState = useRouterState({
|
|
34
|
+
select: (s) => {
|
|
35
|
+
const match = s.matches.find((d) => d.id === matchId)
|
|
36
|
+
invariant(
|
|
37
|
+
match,
|
|
38
|
+
`Could not find match for matchId "${matchId}". Please file an issue!`,
|
|
39
|
+
)
|
|
40
|
+
return pick(match, ['routeId', 'ssr', '_displayPending'])
|
|
41
|
+
},
|
|
42
|
+
structuralSharing: true as any,
|
|
34
43
|
})
|
|
35
44
|
|
|
36
|
-
|
|
37
|
-
routeId,
|
|
38
|
-
`Could not find routeId for matchId "${matchId}". Please file an issue!`,
|
|
39
|
-
)
|
|
40
|
-
|
|
41
|
-
const route: AnyRoute = router.routesById[routeId]
|
|
45
|
+
const route: AnyRoute = router.routesById[matchState.routeId]
|
|
42
46
|
|
|
43
47
|
const PendingComponent =
|
|
44
48
|
route.options.pendingComponent ?? router.options.defaultPendingComponent
|
|
@@ -56,12 +60,14 @@ export const Match = React.memo(function MatchImpl({
|
|
|
56
60
|
router.options.notFoundRoute?.options.component)
|
|
57
61
|
: route.options.notFoundComponent
|
|
58
62
|
|
|
63
|
+
const resolvedNoSsr =
|
|
64
|
+
matchState.ssr === false || matchState.ssr === 'data-only'
|
|
59
65
|
const ResolvedSuspenseBoundary =
|
|
60
66
|
// If we're on the root route, allow forcefully wrapping in suspense
|
|
61
|
-
(!route.isRoot || route.options.wrapInSuspense) &&
|
|
67
|
+
(!route.isRoot || route.options.wrapInSuspense || resolvedNoSsr) &&
|
|
62
68
|
(route.options.wrapInSuspense ??
|
|
63
69
|
PendingComponent ??
|
|
64
|
-
(route.options.errorComponent as any)?.preload)
|
|
70
|
+
((route.options.errorComponent as any)?.preload || resolvedNoSsr))
|
|
65
71
|
? React.Suspense
|
|
66
72
|
: SafeFragment
|
|
67
73
|
|
|
@@ -107,7 +113,7 @@ export const Match = React.memo(function MatchImpl({
|
|
|
107
113
|
// route ID which doesn't match the current route, rethrow the error
|
|
108
114
|
if (
|
|
109
115
|
!routeNotFoundComponent ||
|
|
110
|
-
(error.routeId && error.routeId !== routeId) ||
|
|
116
|
+
(error.routeId && error.routeId !== matchState.routeId) ||
|
|
111
117
|
(!error.routeId && !route.isRoot)
|
|
112
118
|
)
|
|
113
119
|
throw error
|
|
@@ -115,7 +121,13 @@ export const Match = React.memo(function MatchImpl({
|
|
|
115
121
|
return React.createElement(routeNotFoundComponent, error as any)
|
|
116
122
|
}}
|
|
117
123
|
>
|
|
118
|
-
|
|
124
|
+
{resolvedNoSsr || router.isShell || matchState._displayPending ? (
|
|
125
|
+
<ClientOnly fallback={pendingElement}>
|
|
126
|
+
<MatchInner matchId={matchId} />
|
|
127
|
+
</ClientOnly>
|
|
128
|
+
) : (
|
|
129
|
+
<MatchInner matchId={matchId} />
|
|
130
|
+
)}
|
|
119
131
|
</ResolvedNotFoundBoundary>
|
|
120
132
|
</ResolvedCatchBoundary>
|
|
121
133
|
</ResolvedSuspenseBoundary>
|
|
@@ -192,7 +204,13 @@ export const MatchInner = React.memo(function MatchInnerImpl({
|
|
|
192
204
|
return {
|
|
193
205
|
key,
|
|
194
206
|
routeId,
|
|
195
|
-
match: pick(match, [
|
|
207
|
+
match: pick(match, [
|
|
208
|
+
'id',
|
|
209
|
+
'status',
|
|
210
|
+
'error',
|
|
211
|
+
'_forcePending',
|
|
212
|
+
'_displayPending',
|
|
213
|
+
]),
|
|
196
214
|
}
|
|
197
215
|
},
|
|
198
216
|
structuralSharing: true as any,
|
|
@@ -208,9 +226,41 @@ export const MatchInner = React.memo(function MatchInnerImpl({
|
|
|
208
226
|
return <Outlet />
|
|
209
227
|
}, [key, route.options.component, router.options.defaultComponent])
|
|
210
228
|
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
229
|
+
if (match._displayPending) {
|
|
230
|
+
throw router.getMatch(match.id)?.displayPendingPromise
|
|
231
|
+
}
|
|
232
|
+
|
|
233
|
+
// see also triggerOnReady() in packages/router-core/src/router.ts
|
|
234
|
+
if (match.status === 'pending' || match._forcePending) {
|
|
235
|
+
// We're pending, and if we have a minPendingMs, we need to wait for it
|
|
236
|
+
const pendingMinMs =
|
|
237
|
+
route.options.pendingMinMs ?? router.options.defaultPendingMinMs
|
|
238
|
+
|
|
239
|
+
if (pendingMinMs && !router.getMatch(match.id)?.minPendingPromise) {
|
|
240
|
+
// Create a promise that will resolve after the minPendingMs
|
|
241
|
+
if (!router.isServer) {
|
|
242
|
+
const minPendingPromise = createControlledPromise<void>()
|
|
243
|
+
|
|
244
|
+
Promise.resolve().then(() => {
|
|
245
|
+
router.updateMatch(match.id, (prev) => ({
|
|
246
|
+
...prev,
|
|
247
|
+
minPendingPromise,
|
|
248
|
+
}))
|
|
249
|
+
})
|
|
250
|
+
|
|
251
|
+
setTimeout(() => {
|
|
252
|
+
minPendingPromise.resolve()
|
|
253
|
+
|
|
254
|
+
// We've handled the minPendingPromise, so we can delete it
|
|
255
|
+
router.updateMatch(match.id, (prev) => ({
|
|
256
|
+
...prev,
|
|
257
|
+
minPendingPromise: undefined,
|
|
258
|
+
}))
|
|
259
|
+
}, pendingMinMs)
|
|
260
|
+
}
|
|
261
|
+
}
|
|
262
|
+
throw router.getMatch(match.id)?.loadPromise
|
|
263
|
+
}
|
|
214
264
|
|
|
215
265
|
if (match.status === 'notFound') {
|
|
216
266
|
invariant(isNotFound(match.error), 'Expected a notFound error')
|
|
@@ -236,6 +286,10 @@ export const MatchInner = React.memo(function MatchInnerImpl({
|
|
|
236
286
|
// renderToPipeableStream to not hang indefinitely.
|
|
237
287
|
// We'll serialize the error and rethrow it on the client.
|
|
238
288
|
if (router.isServer) {
|
|
289
|
+
const RouteErrorComponent =
|
|
290
|
+
(route.options.errorComponent ??
|
|
291
|
+
router.options.defaultErrorComponent) ||
|
|
292
|
+
ErrorComponent
|
|
239
293
|
return (
|
|
240
294
|
<RouteErrorComponent
|
|
241
295
|
error={match.error as any}
|
|
@@ -250,37 +304,6 @@ export const MatchInner = React.memo(function MatchInnerImpl({
|
|
|
250
304
|
throw match.error
|
|
251
305
|
}
|
|
252
306
|
|
|
253
|
-
if (match.status === 'pending') {
|
|
254
|
-
// We're pending, and if we have a minPendingMs, we need to wait for it
|
|
255
|
-
const pendingMinMs =
|
|
256
|
-
route.options.pendingMinMs ?? router.options.defaultPendingMinMs
|
|
257
|
-
|
|
258
|
-
if (pendingMinMs && !router.getMatch(match.id)?.minPendingPromise) {
|
|
259
|
-
// Create a promise that will resolve after the minPendingMs
|
|
260
|
-
if (!router.isServer) {
|
|
261
|
-
const minPendingPromise = createControlledPromise<void>()
|
|
262
|
-
|
|
263
|
-
Promise.resolve().then(() => {
|
|
264
|
-
router.updateMatch(match.id, (prev) => ({
|
|
265
|
-
...prev,
|
|
266
|
-
minPendingPromise,
|
|
267
|
-
}))
|
|
268
|
-
})
|
|
269
|
-
|
|
270
|
-
setTimeout(() => {
|
|
271
|
-
minPendingPromise.resolve()
|
|
272
|
-
|
|
273
|
-
// We've handled the minPendingPromise, so we can delete it
|
|
274
|
-
router.updateMatch(match.id, (prev) => ({
|
|
275
|
-
...prev,
|
|
276
|
-
minPendingPromise: undefined,
|
|
277
|
-
}))
|
|
278
|
-
}, pendingMinMs)
|
|
279
|
-
}
|
|
280
|
-
}
|
|
281
|
-
throw router.getMatch(match.id)?.loadPromise
|
|
282
|
-
}
|
|
283
|
-
|
|
284
307
|
return out
|
|
285
308
|
})
|
|
286
309
|
|
|
@@ -317,13 +340,6 @@ export const Outlet = React.memo(function OutletImpl() {
|
|
|
317
340
|
<router.options.defaultPendingComponent />
|
|
318
341
|
) : null
|
|
319
342
|
|
|
320
|
-
if (router.isShell)
|
|
321
|
-
return (
|
|
322
|
-
<React.Suspense fallback={pendingElement}>
|
|
323
|
-
<ShellInner />
|
|
324
|
-
</React.Suspense>
|
|
325
|
-
)
|
|
326
|
-
|
|
327
343
|
if (parentGlobalNotFound) {
|
|
328
344
|
return renderRouteNotFound(router, route, undefined)
|
|
329
345
|
}
|
|
@@ -342,7 +358,3 @@ export const Outlet = React.memo(function OutletImpl() {
|
|
|
342
358
|
|
|
343
359
|
return nextMatch
|
|
344
360
|
})
|
|
345
|
-
|
|
346
|
-
function ShellInner(): React.ReactElement {
|
|
347
|
-
throw new Error('ShellBoundaryError')
|
|
348
|
-
}
|
|
@@ -1,32 +1,13 @@
|
|
|
1
1
|
import * as React from 'react'
|
|
2
|
-
import {
|
|
3
|
-
import { ClientOnly } from './ClientOnly'
|
|
2
|
+
import { isModuleNotFoundError } from '@tanstack/router-core'
|
|
4
3
|
import type { AsyncRouteComponent } from './route'
|
|
5
4
|
|
|
6
|
-
// If the load fails due to module not found, it may mean a new version of
|
|
7
|
-
// the build was deployed and the user's browser is still using an old version.
|
|
8
|
-
// If this happens, the old version in the user's browser would have an outdated
|
|
9
|
-
// URL to the lazy module.
|
|
10
|
-
// In that case, we want to attempt one window refresh to get the latest.
|
|
11
|
-
function isModuleNotFoundError(error: any): boolean {
|
|
12
|
-
// chrome: "Failed to fetch dynamically imported module: http://localhost:5173/src/routes/posts.index.tsx?tsr-split"
|
|
13
|
-
// firefox: "error loading dynamically imported module: http://localhost:5173/src/routes/posts.index.tsx?tsr-split"
|
|
14
|
-
// safari: "Importing a module script failed."
|
|
15
|
-
if (typeof error?.message !== 'string') return false
|
|
16
|
-
return (
|
|
17
|
-
error.message.startsWith('Failed to fetch dynamically imported module') ||
|
|
18
|
-
error.message.startsWith('error loading dynamically imported module') ||
|
|
19
|
-
error.message.startsWith('Importing a module script failed')
|
|
20
|
-
)
|
|
21
|
-
}
|
|
22
|
-
|
|
23
5
|
export function lazyRouteComponent<
|
|
24
6
|
T extends Record<string, any>,
|
|
25
7
|
TKey extends keyof T = 'default',
|
|
26
8
|
>(
|
|
27
9
|
importer: () => Promise<T>,
|
|
28
10
|
exportName?: TKey,
|
|
29
|
-
ssr?: () => boolean,
|
|
30
11
|
): T[TKey] extends (props: infer TProps) => any
|
|
31
12
|
? AsyncRouteComponent<TProps>
|
|
32
13
|
: never {
|
|
@@ -36,10 +17,6 @@ export function lazyRouteComponent<
|
|
|
36
17
|
let reload: boolean
|
|
37
18
|
|
|
38
19
|
const load = () => {
|
|
39
|
-
if (typeof document === 'undefined' && ssr?.() === false) {
|
|
40
|
-
comp = (() => null) as any
|
|
41
|
-
return Promise.resolve()
|
|
42
|
-
}
|
|
43
20
|
if (!loadPromise) {
|
|
44
21
|
loadPromise = importer()
|
|
45
22
|
.then((res) => {
|
|
@@ -51,6 +28,11 @@ export function lazyRouteComponent<
|
|
|
51
28
|
// there's nothing we want to do about module not found during preload.
|
|
52
29
|
// Record the error, the rest is handled during the render path.
|
|
53
30
|
error = err
|
|
31
|
+
// If the load fails due to module not found, it may mean a new version of
|
|
32
|
+
// the build was deployed and the user's browser is still using an old version.
|
|
33
|
+
// If this happens, the old version in the user's browser would have an outdated
|
|
34
|
+
// URL to the lazy module.
|
|
35
|
+
// In that case, we want to attempt one window refresh to get the latest.
|
|
54
36
|
if (isModuleNotFoundError(error)) {
|
|
55
37
|
if (
|
|
56
38
|
error instanceof Error &&
|
|
@@ -91,13 +73,6 @@ export function lazyRouteComponent<
|
|
|
91
73
|
throw load()
|
|
92
74
|
}
|
|
93
75
|
|
|
94
|
-
if (ssr?.() === false) {
|
|
95
|
-
return (
|
|
96
|
-
<ClientOnly fallback={<Outlet />}>
|
|
97
|
-
{React.createElement(comp, props)}
|
|
98
|
-
</ClientOnly>
|
|
99
|
-
)
|
|
100
|
-
}
|
|
101
76
|
return React.createElement(comp, props)
|
|
102
77
|
}
|
|
103
78
|
|
|
@@ -5,8 +5,8 @@ import {
|
|
|
5
5
|
transformPipeableStreamWithRouter,
|
|
6
6
|
transformReadableStreamWithRouter,
|
|
7
7
|
} from '@tanstack/router-core/ssr/server'
|
|
8
|
-
import type { ReadableStream } from 'node:stream/web'
|
|
9
8
|
import type { AnyRouter } from '@tanstack/router-core'
|
|
9
|
+
import type { ReadableStream } from 'node:stream/web'
|
|
10
10
|
import type { ReactNode } from 'react'
|
|
11
11
|
|
|
12
12
|
export const renderRouterToStream = async ({
|
|
@@ -56,8 +56,6 @@ export const renderRouterToStream = async ({
|
|
|
56
56
|
},
|
|
57
57
|
}),
|
|
58
58
|
onError: (error, info) => {
|
|
59
|
-
if (error instanceof Error && error.message === 'ShellBoundaryError')
|
|
60
|
-
return
|
|
61
59
|
console.error('Error in renderToPipeableStream:', error, info)
|
|
62
60
|
},
|
|
63
61
|
})
|