11import { hasTracingEnabled } from '@sentry/core' ;
2- import { RewriteFrames } from '@sentry/integrations' ;
32import type { BrowserOptions } from '@sentry/react' ;
4- import {
5- BrowserTracing ,
6- Integrations ,
7- defaultRequestInstrumentationOptions ,
8- getCurrentScope ,
9- init as reactInit ,
10- } from '@sentry/react' ;
11- import type { EventProcessor } from '@sentry/types' ;
12- import { addOrUpdateIntegration } from '@sentry/utils' ;
3+ import { defaultIntegrations } from '@sentry/react' ;
4+ import { Integrations as OriginalIntegrations , getCurrentScope , init as reactInit } from '@sentry/react' ;
5+ import type { EventProcessor , Integration } from '@sentry/types' ;
136
147import { devErrorSymbolicationEventProcessor } from '../common/devErrorSymbolicationEventProcessor' ;
158import { getVercelEnv } from '../common/getVercelEnv' ;
169import { buildMetadata } from '../common/metadata' ;
17- import { nextRouterInstrumentation } from './routing/nextRoutingInstrumentation' ;
10+ import { BrowserTracing } from './browserTracingIntegration' ;
11+ import { rewriteFramesIntegration } from './rewriteFramesIntegration' ;
1812import { applyTunnelRouteOption } from './tunnelRoute' ;
1913
2014export * from '@sentry/react' ;
2115export { nextRouterInstrumentation } from './routing/nextRoutingInstrumentation' ;
2216export { captureUnderscoreErrorException } from '../common/_error' ;
2317
24- export { Integrations } ;
18+ export const Integrations = {
19+ ...OriginalIntegrations ,
20+ BrowserTracing,
21+ } ;
2522
2623// Previously we expected users to import `BrowserTracing` like this:
2724//
@@ -33,27 +30,24 @@ export { Integrations };
3330//
3431// import { BrowserTracing } from '@sentry/nextjs';
3532// const instance = new BrowserTracing();
36- export { BrowserTracing } ;
33+ export { BrowserTracing , rewriteFramesIntegration } ;
3734
3835// Treeshakable guard to remove all code related to tracing
3936declare const __SENTRY_TRACING__ : boolean ;
4037
41- const globalWithInjectedValues = global as typeof global & {
42- __rewriteFramesAssetPrefixPath__ : string ;
43- } ;
44-
4538/** Inits the Sentry NextJS SDK on the browser with the React SDK. */
4639export function init ( options : BrowserOptions ) : void {
4740 const opts = {
4841 environment : getVercelEnv ( true ) || process . env . NODE_ENV ,
42+ defaultIntegrations : getDefaultIntegrations ( options ) ,
4943 ...options ,
5044 } ;
5145
46+ fixBrowserTracingIntegration ( opts ) ;
47+
5248 applyTunnelRouteOption ( opts ) ;
5349 buildMetadata ( opts , [ 'nextjs' , 'react' ] ) ;
5450
55- addClientIntegrations ( opts ) ;
56-
5751 reactInit ( opts ) ;
5852
5953 const scope = getCurrentScope ( ) ;
@@ -68,72 +62,53 @@ export function init(options: BrowserOptions): void {
6862 }
6963}
7064
71- function addClientIntegrations ( options : BrowserOptions ) : void {
72- let integrations = options . integrations || [ ] ;
73-
74- // This value is injected at build time, based on the output directory specified in the build config. Though a default
75- // is set there, we set it here as well, just in case something has gone wrong with the injection.
76- const assetPrefixPath = globalWithInjectedValues . __rewriteFramesAssetPrefixPath__ || '' ;
77-
78- // eslint-disable-next-line deprecation/deprecation
79- const defaultRewriteFramesIntegration = new RewriteFrames ( {
80- // Turn `<origin>/<path>/_next/static/...` into `app:///_next/static/...`
81- iteratee : frame => {
82- try {
83- const { origin } = new URL ( frame . filename as string ) ;
84- frame . filename = frame . filename ?. replace ( origin , 'app://' ) . replace ( assetPrefixPath , '' ) ;
85- } catch ( err ) {
86- // Filename wasn't a properly formed URL, so there's nothing we can do
87- }
88-
89- // We need to URI-decode the filename because Next.js has wildcard routes like "/users/[id].js" which show up as "/users/%5id%5.js" in Error stacktraces.
90- // The corresponding sources that Next.js generates have proper brackets so we also need proper brackets in the frame so that source map resolving works.
91- if ( frame . filename && frame . filename . startsWith ( 'app:///_next' ) ) {
92- frame . filename = decodeURI ( frame . filename ) ;
93- }
94-
95- if (
96- frame . filename &&
97- frame . filename . match (
98- / ^ a p p : \/ \/ \/ _ n e x t \/ s t a t i c \/ c h u n k s \/ ( m a i n - | m a i n - a p p - | p o l y f i l l s - | w e b p a c k - | f r a m e w o r k - | f r a m e w o r k \. ) [ 0 - 9 a - f ] + \. j s $ / ,
99- )
100- ) {
101- // We don't care about these frames. It's Next.js internal code.
102- frame . in_app = false ;
103- }
104-
105- return frame ;
106- } ,
107- } ) ;
108- integrations = addOrUpdateIntegration ( defaultRewriteFramesIntegration , integrations ) ;
65+ // TODO v8: Remove this again
66+ // We need to handle BrowserTracing passed to `integrations` that comes from `@sentry/tracing`, not `@sentry/sveltekit` :(
67+ function fixBrowserTracingIntegration ( options : BrowserOptions ) : void {
68+ const { integrations } = options ;
69+ if ( ! integrations ) {
70+ return ;
71+ }
72+
73+ if ( Array . isArray ( integrations ) ) {
74+ options . integrations = maybeUpdateBrowserTracingIntegration ( integrations ) ;
75+ } else {
76+ options . integrations = defaultIntegrations => {
77+ const userFinalIntegrations = integrations ( defaultIntegrations ) ;
78+
79+ return maybeUpdateBrowserTracingIntegration ( userFinalIntegrations ) ;
80+ } ;
81+ }
82+ }
83+
84+ function maybeUpdateBrowserTracingIntegration ( integrations : Integration [ ] ) : Integration [ ] {
85+ const browserTracing = integrations . find ( integration => integration . name === 'BrowserTracing' ) ;
86+ // If BrowserTracing was added, but it is not our forked version,
87+ // replace it with our forked version with the same options
88+ if ( browserTracing && ! ( browserTracing instanceof BrowserTracing ) ) {
89+ const options : ConstructorParameters < typeof BrowserTracing > [ 0 ] = ( browserTracing as BrowserTracing ) . options ;
90+ // These two options are overwritten by the custom integration
91+ delete options . routingInstrumentation ;
92+ // eslint-disable-next-line deprecation/deprecation
93+ delete options . tracingOrigins ;
94+ integrations [ integrations . indexOf ( browserTracing ) ] = new BrowserTracing ( options ) ;
95+ }
96+
97+ return integrations ;
98+ }
99+
100+ function getDefaultIntegrations ( options : BrowserOptions ) : Integration [ ] {
101+ const customDefaultIntegrations = defaultIntegrations . slice ( ) . concat ( [ rewriteFramesIntegration ( ) ] ) ;
109102
110103 // This evaluates to true unless __SENTRY_TRACING__ is text-replaced with "false", in which case everything inside
111104 // will get treeshaken away
112105 if ( typeof __SENTRY_TRACING__ === 'undefined' || __SENTRY_TRACING__ ) {
113106 if ( hasTracingEnabled ( options ) ) {
114- const defaultBrowserTracingIntegration = new BrowserTracing ( {
115- // eslint-disable-next-line deprecation/deprecation
116- tracingOrigins :
117- process . env . NODE_ENV === 'development'
118- ? [
119- // Will match any URL that contains "localhost" but not "webpack.hot-update.json" - The webpack dev-server
120- // has cors and it doesn't like extra headers when it's accessed from a different URL.
121- // TODO(v8): Ideally we rework our tracePropagationTargets logic so this hack won't be necessary anymore (see issue #9764)
122- / ^ (? = .* l o c a l h o s t ) (? ! .* w e b p a c k \. h o t - u p d a t e \. j s o n ) .* / ,
123- / ^ \/ (? ! \/ ) / ,
124- ]
125- : // eslint-disable-next-line deprecation/deprecation
126- [ ...defaultRequestInstrumentationOptions . tracingOrigins , / ^ ( a p i \/ ) / ] ,
127- routingInstrumentation : nextRouterInstrumentation ,
128- } ) ;
129-
130- integrations = addOrUpdateIntegration ( defaultBrowserTracingIntegration , integrations , {
131- 'options.routingInstrumentation' : nextRouterInstrumentation ,
132- } ) ;
107+ customDefaultIntegrations . push ( new BrowserTracing ( ) ) ;
133108 }
134109 }
135110
136- options . integrations = integrations ;
111+ return customDefaultIntegrations ;
137112}
138113
139114/**
0 commit comments