File tree Expand file tree Collapse file tree
packages/nextjs/src/client Expand file tree Collapse file tree Original file line number Diff line number Diff line change 11import type { Integration } from '@sentry/core' ;
2+ import { createUrlRouteProvider , setRouteProvider } from '@sentry/core/browser' ;
23import { browserTracingIntegration as originalBrowserTracingIntegration , isBotUserAgent } from '@sentry/react' ;
4+ import { maybeParameterizeRoute , stripTrailingSlash , withBasePath } from './routing/parameterization' ;
35import { nextRouterInstrumentNavigation , nextRouterInstrumentPageLoad } from './routing/nextRoutingInstrumentation' ;
46
57/**
@@ -28,6 +30,17 @@ export function browserTracingIntegration(
2830
2931 return {
3032 ...browserTracingIntegrationInstance ,
33+ setup ( client ) {
34+ // Registered here rather than in `afterAllSetup` so it is in place before the pageload span is
35+ // named. The build-time route manifest is already on the global object at this point, so nothing
36+ // has to wait for the router itself.
37+ setRouteProvider (
38+ createUrlRouteProvider ( url => maybeParameterizeRoute ( stripTrailingSlash ( withBasePath ( url . pathname ) ) ) ) ,
39+ client ,
40+ ) ;
41+
42+ browserTracingIntegrationInstance . setup ?.( client ) ;
43+ } ,
3144 afterAllSetup ( client ) {
3245 if ( isBotUserAgent ( ) ) {
3346 return ;
Original file line number Diff line number Diff line change @@ -14,17 +14,9 @@ import {
1414 WINDOW ,
1515 getAbsoluteUrl ,
1616} from '@sentry/react' ;
17- import { maybeParameterizeRoute } from './parameterization' ;
17+ import { maybeParameterizeRoute , stripTrailingSlash } from './parameterization' ;
1818import { URL_FULL , URL_PATH , URL_TEMPLATE } from '@sentry/conventions/attributes' ;
1919
20- /**
21- * Strips trailing slash from a pathname, unless it's the root path.
22- * This normalizes paths like '/about/' to '/about' to handle Next.js `trailingSlash: true` config.
23- */
24- function stripTrailingSlash ( pathname : string ) : string {
25- return pathname . length > 1 && pathname . endsWith ( '/' ) ? pathname . slice ( 0 , - 1 ) : pathname ;
26- }
27-
2820function setNavigationSpanUrlAttributes ( span : Span , urlPath : string , urlOrPath : string ) : void {
2921 span . setAttributes ( {
3022 [ URL_PATH ] : urlPath ,
Original file line number Diff line number Diff line change @@ -12,6 +12,30 @@ let cachedManifestString: string | undefined = undefined;
1212const compiledRegexCache : Map < string , RegExp > = new Map ( ) ;
1313const routeResultCache : Map < string , string | undefined > = new Map ( ) ;
1414
15+ const globalWithInjectedBasePath = GLOBAL_OBJ as typeof GLOBAL_OBJ & {
16+ _sentryBasePath : string | undefined ;
17+ } ;
18+
19+ /**
20+ * Strips trailing slash from a pathname, unless it's the root path.
21+ * This normalizes paths like '/about/' to '/about' to handle Next.js `trailingSlash: true` config.
22+ */
23+ export function stripTrailingSlash ( pathname : string ) : string {
24+ return pathname . length > 1 && pathname . endsWith ( '/' ) ? pathname . slice ( 0 , - 1 ) : pathname ;
25+ }
26+
27+ /**
28+ * Prefixes a pathname with the configured `basePath` when it is missing.
29+ *
30+ * The build-time manifest is generated with `basePath` baked into every route, so a pathname that
31+ * lacks it matches nothing.
32+ */
33+ export function withBasePath ( pathname : string ) : string {
34+ const basePath = process . env . _sentryBasePath ?? globalWithInjectedBasePath . _sentryBasePath ;
35+
36+ return basePath && ! pathname . startsWith ( basePath ) ? `${ basePath } ${ pathname } ` : pathname ;
37+ }
38+
1539/**
1640 * Calculate the specificity score for a route path.
1741 * Lower scores indicate more specific routes.
You can’t perform that action at this time.
0 commit comments