@@ -7,68 +7,22 @@ import { getNumberOfUrlSegments, logger } from '@sentry/utils';
77import hoistNonReactStatics from 'hoist-non-react-statics' ;
88import React from 'react' ;
99
10- import { Action , Location } from './types' ;
11-
12- interface NonIndexRouteObject {
13- caseSensitive ?: boolean ;
14- children ?: RouteObject [ ] ;
15- element ?: React . ReactNode | null ;
16- index ?: false ;
17- path ?: string ;
18- }
19-
20- interface IndexRouteObject {
21- caseSensitive ?: boolean ;
22- children ?: undefined ;
23- element ?: React . ReactNode | null ;
24- index ?: true ;
25- path ?: string ;
26- }
27-
28- // This type was originally just `type RouteObject = IndexRouteObject`, but this was changed
29- // in https://github.com/remix-run/react-router/pull/9366, which was released with `6.4.2`
30- // See https://github.com/remix-run/react-router/issues/9427 for a discussion on this.
31- type RouteObject = IndexRouteObject | NonIndexRouteObject ;
32-
33- type Params < Key extends string = string > = {
34- readonly [ key in Key ] : string | undefined ;
35- } ;
36-
37- type UseRoutes = ( routes : RouteObject [ ] , locationArg ?: Partial < Location > | string ) => React . ReactElement | null ;
38-
39- // https://github.com/remix-run/react-router/blob/9fa54d643134cd75a0335581a75db8100ed42828/packages/react-router/lib/router.ts#L114-L134
40- interface RouteMatch < ParamKey extends string = string > {
41- /**
42- * The names and values of dynamic parameters in the URL.
43- */
44- params : Params < ParamKey > ;
45- /**
46- * The portion of the URL pathname that was matched.
47- */
48- pathname : string ;
49- /**
50- * The portion of the URL pathname that was matched before child routes.
51- */
52- pathnameBase : string ;
53- /**
54- * The route object that was used to match.
55- */
56- route : RouteObject ;
57- }
58-
59- type UseEffect = ( cb : ( ) => void , deps : unknown [ ] ) => void ;
60- type UseLocation = ( ) => Location ;
61- type UseNavigationType = ( ) => Action ;
62-
63- // For both of these types, use `any` instead of `RouteObject[]` or `RouteMatch[]`.
64- // Have to do this so we maintain backwards compatability between
65- // react-router > 6.0.0 and >= 6.4.2.
66- // eslint-disable-next-line @typescript-eslint/no-explicit-any
67- type RouteObjectArrayAlias = any ;
68- // eslint-disable-next-line @typescript-eslint/no-explicit-any
69- type RouteMatchAlias = any ;
70- type CreateRoutesFromChildren = ( children : JSX . Element [ ] ) => RouteObjectArrayAlias ;
71- type MatchRoutes = ( routes : RouteObjectArrayAlias , location : Location ) => RouteMatchAlias [ ] | null ;
10+ import {
11+ Action ,
12+ AgnosticDataRouteMatch ,
13+ CreateRouterFunction ,
14+ CreateRoutesFromChildren ,
15+ Location ,
16+ MatchRoutes ,
17+ RouteMatch ,
18+ RouteObject ,
19+ Router ,
20+ RouterState ,
21+ UseEffect ,
22+ UseLocation ,
23+ UseNavigationType ,
24+ UseRoutes ,
25+ } from './types' ;
7226
7327let activeTransaction : Transaction | undefined ;
7428
@@ -122,14 +76,12 @@ export function reactRouterV6Instrumentation(
12276function getNormalizedName (
12377 routes : RouteObject [ ] ,
12478 location : Location ,
125- matchRoutes : MatchRoutes ,
79+ branches : RouteMatch [ ] ,
12680) : [ string , TransactionSource ] {
127- if ( ! routes || routes . length === 0 || ! matchRoutes ) {
81+ if ( ! routes || routes . length === 0 ) {
12882 return [ location . pathname , 'url' ] ;
12983 }
13084
131- const branches = matchRoutes ( routes , location ) as unknown as RouteMatch [ ] ;
132-
13385 let pathBuilder = '' ;
13486 if ( branches ) {
13587 // eslint-disable-next-line @typescript-eslint/prefer-for-of
@@ -167,9 +119,11 @@ function getNormalizedName(
167119 return [ location . pathname , 'url' ] ;
168120}
169121
170- function updatePageloadTransaction ( location : Location , routes : RouteObject [ ] ) : void {
171- if ( activeTransaction ) {
172- activeTransaction . setName ( ...getNormalizedName ( routes , location , _matchRoutes ) ) ;
122+ function updatePageloadTransaction ( location : Location , routes : RouteObject [ ] , matches ?: AgnosticDataRouteMatch ) : void {
123+ const branches = Array . isArray ( matches ) ? matches : ( _matchRoutes ( routes , location ) as unknown as RouteMatch [ ] ) ;
124+
125+ if ( activeTransaction && branches ) {
126+ activeTransaction . setName ( ...getNormalizedName ( routes , location , branches ) ) ;
173127 }
174128}
175129
@@ -178,6 +132,7 @@ function handleNavigation(
178132 routes : RouteObject [ ] ,
179133 navigationType : Action ,
180134 isBaseLocation : boolean ,
135+ matches ?: AgnosticDataRouteMatch ,
181136) : void {
182137 if ( isBaseLocation ) {
183138 if ( activeTransaction ) {
@@ -187,12 +142,14 @@ function handleNavigation(
187142 return ;
188143 }
189144
190- if ( _startTransactionOnLocationChange && ( navigationType === 'PUSH' || navigationType === 'POP' ) ) {
145+ const branches = Array . isArray ( matches ) ? matches : _matchRoutes ( routes , location ) ;
146+
147+ if ( _startTransactionOnLocationChange && ( navigationType === 'PUSH' || navigationType === 'POP' ) && branches ) {
191148 if ( activeTransaction ) {
192149 activeTransaction . finish ( ) ;
193150 }
194151
195- const [ name , source ] = getNormalizedName ( routes , location , _matchRoutes ) ;
152+ const [ name , source ] = getNormalizedName ( routes , location , branches ) ;
196153 activeTransaction = _customStartTransaction ( {
197154 name,
198155 op : 'navigation' ,
@@ -294,3 +251,32 @@ export function wrapUseRoutes(origUseRoutes: UseRoutes): UseRoutes {
294251 return < SentryRoutes /> ;
295252 } ;
296253}
254+
255+ export function wrapCreateBrowserRouter ( createRouterFunction : CreateRouterFunction ) : CreateRouterFunction {
256+ // `opts` for createBrowserHistory and createMemoryHistory are different, but also not relevant for us at the moment.
257+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
258+ return function ( routes : RouteObject [ ] , opts ?: any ) : Router {
259+ const router = createRouterFunction ( routes , opts ) ;
260+
261+ // The initial load ends when `createBrowserRouter` is called.
262+ // This is the earliest convenient time to update the transaction name.
263+ // Callbacks to `router.subscribe` are not called for the initial load.
264+ if ( router . state . historyAction === 'POP' && activeTransaction ) {
265+ updatePageloadTransaction ( router . state . location , routes ) ;
266+ }
267+
268+ router . subscribe ( ( state : RouterState ) => {
269+ const location = state . location ;
270+
271+ if (
272+ _startTransactionOnLocationChange &&
273+ ( state . historyAction === 'PUSH' || state . historyAction === 'POP' ) &&
274+ activeTransaction
275+ ) {
276+ handleNavigation ( location , routes , state . historyAction , false ) ;
277+ }
278+ } ) ;
279+
280+ return router ;
281+ } ;
282+ }
0 commit comments