Skip to content

Commit 60a9d7c

Browse files
committed
Introduce isLikeLazyRouteContext
1 parent 453f5c6 commit 60a9d7c

File tree

3 files changed

+49
-13
lines changed

3 files changed

+49
-13
lines changed

packages/react/src/reactrouter-compat-utils/index.ts

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -16,15 +16,16 @@ export {
1616

1717
// Utility exports
1818
export {
19+
resolveRouteNameAndSource,
20+
getNormalizedName,
1921
initializeRouterUtils,
22+
isLikelyLazyRouteContext,
23+
locationIsInsideDescendantRoute,
2024
prefixWithSlash,
2125
rebuildRoutePathFromAllRoutes,
22-
locationIsInsideDescendantRoute,
23-
getNormalizedName,
24-
getNumberOfUrlSegments,
25-
resolveRouteNameAndSource,
2626
pathEndsWithWildcard,
2727
pathIsWildcardAndHasChildren,
28+
getNumberOfUrlSegments,
2829
} from './utils';
2930

3031
// Lazy route exports

packages/react/src/reactrouter-compat-utils/instrumentation.tsx

Lines changed: 12 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -44,6 +44,7 @@ import { checkRouteForAsyncHandler } from './lazy-routes';
4444
import {
4545
getNormalizedName,
4646
initializeRouterUtils,
47+
isLikelyLazyRouteContext,
4748
locationIsInsideDescendantRoute,
4849
prefixWithSlash,
4950
rebuildRoutePathFromAllRoutes,
@@ -114,7 +115,7 @@ const allRoutes = new Set<RouteObject>();
114115
export function processResolvedRoutes(
115116
resolvedRoutes: RouteObject[],
116117
parentRoute?: RouteObject,
117-
currentLocation?: Location,
118+
currentLocation: Location | null = null,
118119
): void {
119120
resolvedRoutes.forEach(child => {
120121
allRoutes.add(child);
@@ -538,7 +539,7 @@ function wrapPatchRoutesOnNavigation(
538539
key: 'default',
539540
},
540541
Array.from(allRoutes),
541-
true,
542+
true, // forceUpdate = true since we're loading lazy routes
542543
_matchRoutes,
543544
);
544545
}
@@ -552,9 +553,8 @@ function wrapPatchRoutesOnNavigation(
552553
// Update navigation span after routes are patched
553554
const activeRootSpan = getActiveRootSpan();
554555
if (activeRootSpan && (spanToJSON(activeRootSpan) as { op?: string }).op === 'navigation') {
555-
// For memory routers, we don't have a reliable way to get the current pathname
556-
// without accessing window.location, so we'll use targetPath for both cases
557-
const pathname = targetPath || (isMemoryRouter ? WINDOW.location?.pathname : undefined);
556+
// For memory routers, we should not access window.location; use targetPath only
557+
const pathname = isMemoryRouter ? targetPath : targetPath || WINDOW.location?.pathname;
558558
if (pathname) {
559559
updateNavigationSpan(
560560
activeRootSpan,
@@ -566,7 +566,7 @@ function wrapPatchRoutesOnNavigation(
566566
key: 'default',
567567
},
568568
Array.from(allRoutes),
569-
false,
569+
false, // forceUpdate = false since this is after lazy routes are loaded
570570
_matchRoutes,
571571
);
572572
}
@@ -603,15 +603,18 @@ export function handleNavigation(opts: {
603603
basename,
604604
);
605605

606+
// Check if this might be a lazy route context
607+
const isLazyRouteContext = isLikelyLazyRouteContext(allRoutes || routes, location);
608+
606609
const activeSpan = getActiveSpan();
607610
const spanJson = activeSpan && spanToJSON(activeSpan);
608611
const isAlreadyInNavigationSpan = spanJson?.op === 'navigation';
609612

610613
// Cross usage can result in multiple navigation spans being created without this check
611614
if (isAlreadyInNavigationSpan && activeSpan && spanJson) {
612-
handleExistingNavigationSpan(activeSpan, spanJson, name, source, false);
615+
handleExistingNavigationSpan(activeSpan, spanJson, name, source, isLazyRouteContext);
613616
} else {
614-
createNewNavigationSpan(client, name, source, version, false);
617+
createNewNavigationSpan(client, name, source, version, isLazyRouteContext);
615618
}
616619
}
617620
}
@@ -783,6 +786,7 @@ export function handleExistingNavigationSpan(
783786
}
784787
}
785788

789+
// Always set the source attribute to keep it consistent with the current route
786790
activeSpan?.setAttribute(SEMANTIC_ATTRIBUTE_SENTRY_SOURCE, source);
787791
}
788792

packages/react/src/reactrouter-compat-utils/utils.ts

Lines changed: 32 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,37 @@ export function initializeRouterUtils(matchRoutes: MatchRoutes, stripBasename: b
1414
_stripBasename = stripBasename;
1515
}
1616

17+
/**
18+
* Checks if the given routes or location context suggests this might be a lazy route scenario.
19+
* This helps determine if we should delay marking navigation spans as "named" to allow for updates
20+
* when lazy routes are loaded.
21+
*/
22+
export function isLikelyLazyRouteContext(routes: RouteObject[], location: Location): boolean {
23+
// Check if any route in the current match has lazy properties
24+
const hasLazyRoute = routes.some(route => {
25+
return (
26+
// React Router lazy() route
27+
route.lazy ||
28+
// Route with async handlers that might load child routes
29+
(route.handle &&
30+
typeof route.handle === 'object' &&
31+
Object.values(route.handle).some(handler => typeof handler === 'function'))
32+
);
33+
});
34+
35+
if (hasLazyRoute) {
36+
return true;
37+
}
38+
39+
// Check if current route is unmatched, which might indicate a lazy route that hasn't loaded yet
40+
const currentMatches = _matchRoutes(routes, location);
41+
if (!currentMatches || currentMatches.length === 0) {
42+
return true;
43+
}
44+
45+
return false;
46+
}
47+
1748
// Helper functions
1849
function pickPath(match: RouteMatch): string {
1950
return trimWildcard(match.route.path || '');
@@ -222,7 +253,7 @@ export function getNormalizedName(
222253

223254
const fallbackTransactionName = _stripBasename
224255
? stripBasenameFromPathname(location.pathname, basename)
225-
: location.pathname;
256+
: location.pathname || '';
226257

227258
return [fallbackTransactionName, 'url'];
228259
}

0 commit comments

Comments
 (0)