diff --git a/packages/nextjs/src/config/types.ts b/packages/nextjs/src/config/types.ts index 3ac3698789b0..c635aa88c21a 100644 --- a/packages/nextjs/src/config/types.ts +++ b/packages/nextjs/src/config/types.ts @@ -467,6 +467,24 @@ export type SentryBuildOptions = { */ suppressOnRouterTransitionStartWarning?: boolean; + /** + * Disables automatic injection of the route manifest into the client bundle. + * + * The route manifest is a build-time generated mapping of your Next.js App Router + * routes that enables Sentry to group transactions by parameterized route names + * (e.g., `/users/:id` instead of `/users/123`, `/users/456`, etc.). + * + * **Disable this option if:** + * - You want to minimize client bundle size + * - You're experiencing build issues related to route scanning + * - You're using custom routing that the scanner can't detect + * - You prefer raw URLs in transaction names + * - You're only using Pages Router (this feature is only supported in the App Router) + * + * @default false + */ + disableManifestInjection?: boolean; + /** * Contains a set of experimental flags that might change in future releases. These flags enable * features that are still in development and may be modified, renamed, or removed without notice. diff --git a/packages/nextjs/src/config/webpack.ts b/packages/nextjs/src/config/webpack.ts index e0faf2bd285d..77db5120cda3 100644 --- a/packages/nextjs/src/config/webpack.ts +++ b/packages/nextjs/src/config/webpack.ts @@ -7,6 +7,7 @@ import * as fs from 'fs'; import * as path from 'path'; import { sync as resolveSync } from 'resolve'; import type { VercelCronsConfig } from '../common/types'; +import type { RouteManifest } from './manifest/types'; // Note: If you need to import a type from Webpack, do it in `types.ts` and export it from there. Otherwise, our // circular dependency check thinks this file is importing from itself. See https://github.com/pahen/madge/issues/306. import type { @@ -43,6 +44,7 @@ export function constructWebpackConfigFunction( userNextConfig: NextConfigObject = {}, userSentryOptions: SentryBuildOptions = {}, releaseName: string | undefined, + routeManifest: RouteManifest | undefined, ): WebpackConfigFunction { // Will be called by nextjs and passed its default webpack configuration and context data about the build (whether // we're building server or client, whether we're in dev, what version of webpack we're using, etc). Note that @@ -88,7 +90,7 @@ export function constructWebpackConfigFunction( const newConfig = setUpModuleRules(rawNewConfig); // Add a loader which will inject code that sets global values - addValueInjectionLoader(newConfig, userNextConfig, userSentryOptions, buildContext, releaseName); + addValueInjectionLoader(newConfig, userNextConfig, userSentryOptions, buildContext, releaseName, routeManifest); addOtelWarningIgnoreRule(newConfig); @@ -686,6 +688,7 @@ function addValueInjectionLoader( userSentryOptions: SentryBuildOptions, buildContext: BuildContext, releaseName: string | undefined, + routeManifest: RouteManifest | undefined, ): void { const assetPrefix = userNextConfig.assetPrefix || userNextConfig.basePath || ''; @@ -727,6 +730,7 @@ function addValueInjectionLoader( _sentryExperimentalThirdPartyOriginStackFrames: userSentryOptions._experimental?.thirdPartyOriginStackFrames ? 'true' : undefined, + _sentryRouteManifest: JSON.stringify(routeManifest), }; if (buildContext.isServer) { diff --git a/packages/nextjs/src/config/withSentryConfig.ts b/packages/nextjs/src/config/withSentryConfig.ts index 84bd0a01cb5e..4e231a3227d6 100644 --- a/packages/nextjs/src/config/withSentryConfig.ts +++ b/packages/nextjs/src/config/withSentryConfig.ts @@ -5,6 +5,8 @@ import { getSentryRelease } from '@sentry/node'; import * as childProcess from 'child_process'; import * as fs from 'fs'; import * as path from 'path'; +import { createRouteManifest } from './manifest/createRouteManifest'; +import type { RouteManifest } from './manifest/types'; import type { ExportedNextConfig as NextConfig, NextConfigFunction, @@ -141,6 +143,11 @@ function getFinalConfigObject( } } + let routeManifest: RouteManifest | undefined; + if (!userSentryOptions.disableManifestInjection) { + routeManifest = createRouteManifest(); + } + setUpBuildTimeVariables(incomingUserNextConfigObject, userSentryOptions, releaseName); const nextJsVersion = getNextjsVersion(); @@ -300,7 +307,12 @@ function getFinalConfigObject( ], }, }), - webpack: constructWebpackConfigFunction(incomingUserNextConfigObject, userSentryOptions, releaseName), + webpack: constructWebpackConfigFunction( + incomingUserNextConfigObject, + userSentryOptions, + releaseName, + routeManifest, + ), }; }