Skip to content

Commit af59909

Browse files
committed
feat(nextjs): Register a route provider from the build-time route manifest
The App Router already resolves URLs to parameterized routes via the manifest it injects at build time, so the provider is a thin wrapper over it.
1 parent fd024db commit af59909

3 files changed

Lines changed: 38 additions & 9 deletions

File tree

‎packages/nextjs/src/client/browserTracingIntegration.ts‎

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,7 @@
11
import type { Integration } from '@sentry/core';
2+
import { createUrlRouteProvider, setRouteProvider } from '@sentry/core/browser';
23
import { browserTracingIntegration as originalBrowserTracingIntegration, isBotUserAgent } from '@sentry/react';
4+
import { maybeParameterizeRoute, stripTrailingSlash, withBasePath } from './routing/parameterization';
35
import { 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;

‎packages/nextjs/src/client/routing/appRouterRoutingInstrumentation.ts‎

Lines changed: 1 addition & 9 deletions
Original file line numberDiff line numberDiff 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';
1818
import { 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-
2820
function setNavigationSpanUrlAttributes(span: Span, urlPath: string, urlOrPath: string): void {
2921
span.setAttributes({
3022
[URL_PATH]: urlPath,

‎packages/nextjs/src/client/routing/parameterization.ts‎

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,30 @@ let cachedManifestString: string | undefined = undefined;
1212
const compiledRegexCache: Map<string, RegExp> = new Map();
1313
const 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.

0 commit comments

Comments
 (0)