@@ -6,6 +6,19 @@ import { logger, stripUrlQueryAndFragment, timestampWithMs } from '@sentry/utils
6
6
import { Observable , Subscription } from 'rxjs' ;
7
7
import { filter , tap } from 'rxjs/operators' ;
8
8
9
+ // That's the `global.Zone` exposed when the `zone.js` package is used.
10
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
11
+ declare const Zone : any ;
12
+
13
+ // There're 2 types of Angular applications:
14
+ // 1) zone-full (by default)
15
+ // 2) zone-less
16
+ // The developer can avoid importing the `zone.js` package and tells Angular that
17
+ // he is responsible for running the change detection by himself. This is done by
18
+ // "nooping" the zone through `CompilerOptions` when bootstrapping the root module.
19
+ // eslint-disable-next-line @typescript-eslint/no-unsafe-member-access
20
+ const isNgZoneEnabled = typeof Zone !== 'undefined' && ! ! Zone . current ;
21
+
9
22
let instrumentationInitialized : boolean ;
10
23
let stashedStartTransaction : ( context : TransactionContext ) => Transaction | undefined ;
11
24
let stashedStartTransactionOnLocationChange : boolean ;
@@ -93,13 +106,27 @@ export class TraceService implements OnDestroy {
93
106
filter ( event => event instanceof NavigationEnd ) ,
94
107
tap ( ( ) => {
95
108
if ( this . _routingSpan ) {
96
- this . _routingSpan . finish ( ) ;
97
- delete this . _routingSpan ;
109
+ if ( isNgZoneEnabled ) {
110
+ // The `Zone.root.run` basically will finish the transaction in the most parent zone.
111
+ // The Angular's zone is forked from the `Zone.root`. In this case, `zone.js` won't
112
+ // trigger change detection, and `ApplicationRef.tick()` will not be run.
113
+ // Caretaker note: we're using `Zone.root` except `NgZone.runOutsideAngular` since this
114
+ // will require injecting the `NgZone` facade. That will create a breaking change for
115
+ // projects already using the `TraceService`.
116
+ // eslint-disable-next-line @typescript-eslint/no-unsafe-member-access
117
+ Zone . root . run ( ( ) => {
118
+ // eslint-disable-next-line @typescript-eslint/no-non-null-assertion
119
+ this . _routingSpan ! . finish ( ) ;
120
+ } ) ;
121
+ } else {
122
+ this . _routingSpan . finish ( ) ;
123
+ }
124
+ this . _routingSpan = null ;
98
125
}
99
126
} ) ,
100
127
) ;
101
128
102
- private _routingSpan ? : Span ;
129
+ private _routingSpan : Span | null = null ;
103
130
private _subscription : Subscription = new Subscription ( ) ;
104
131
105
132
public constructor ( private readonly _router : Router ) {
0 commit comments