@@ -7,68 +7,22 @@ import { getNumberOfUrlSegments, logger } from '@sentry/utils';
7
7
import hoistNonReactStatics from 'hoist-non-react-statics' ;
8
8
import React from 'react' ;
9
9
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' ;
72
26
73
27
let activeTransaction : Transaction | undefined ;
74
28
@@ -122,14 +76,12 @@ export function reactRouterV6Instrumentation(
122
76
function getNormalizedName (
123
77
routes : RouteObject [ ] ,
124
78
location : Location ,
125
- matchRoutes : MatchRoutes ,
79
+ branches : RouteMatch [ ] ,
126
80
) : [ string , TransactionSource ] {
127
- if ( ! routes || routes . length === 0 || ! matchRoutes ) {
81
+ if ( ! routes || routes . length === 0 ) {
128
82
return [ location . pathname , 'url' ] ;
129
83
}
130
84
131
- const branches = matchRoutes ( routes , location ) as unknown as RouteMatch [ ] ;
132
-
133
85
let pathBuilder = '' ;
134
86
if ( branches ) {
135
87
// eslint-disable-next-line @typescript-eslint/prefer-for-of
@@ -167,9 +119,11 @@ function getNormalizedName(
167
119
return [ location . pathname , 'url' ] ;
168
120
}
169
121
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 ) ) ;
173
127
}
174
128
}
175
129
@@ -178,6 +132,7 @@ function handleNavigation(
178
132
routes : RouteObject [ ] ,
179
133
navigationType : Action ,
180
134
isBaseLocation : boolean ,
135
+ matches ?: AgnosticDataRouteMatch ,
181
136
) : void {
182
137
if ( isBaseLocation ) {
183
138
if ( activeTransaction ) {
@@ -187,12 +142,14 @@ function handleNavigation(
187
142
return ;
188
143
}
189
144
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 ) {
191
148
if ( activeTransaction ) {
192
149
activeTransaction . finish ( ) ;
193
150
}
194
151
195
- const [ name , source ] = getNormalizedName ( routes , location , _matchRoutes ) ;
152
+ const [ name , source ] = getNormalizedName ( routes , location , branches ) ;
196
153
activeTransaction = _customStartTransaction ( {
197
154
name,
198
155
op : 'navigation' ,
@@ -294,3 +251,32 @@ export function wrapUseRoutes(origUseRoutes: UseRoutes): UseRoutes {
294
251
return < SentryRoutes /> ;
295
252
} ;
296
253
}
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