Skip to content

Commit ee647ed

Browse files
chargomemsonnb
authored andcommitted
feat(nextjs): Inject manifest into client for webpack builds (#16857)
1 parent d9b707f commit ee647ed

File tree

3 files changed

+36
-2
lines changed

3 files changed

+36
-2
lines changed

packages/nextjs/src/config/types.ts

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -467,6 +467,24 @@ export type SentryBuildOptions = {
467467
*/
468468
suppressOnRouterTransitionStartWarning?: boolean;
469469

470+
/**
471+
* Disables automatic injection of the route manifest into the client bundle.
472+
*
473+
* The route manifest is a build-time generated mapping of your Next.js App Router
474+
* routes that enables Sentry to group transactions by parameterized route names
475+
* (e.g., `/users/:id` instead of `/users/123`, `/users/456`, etc.).
476+
*
477+
* **Disable this option if:**
478+
* - You want to minimize client bundle size
479+
* - You're experiencing build issues related to route scanning
480+
* - You're using custom routing that the scanner can't detect
481+
* - You prefer raw URLs in transaction names
482+
* - You're only using Pages Router (this feature is only supported in the App Router)
483+
*
484+
* @default false
485+
*/
486+
disableManifestInjection?: boolean;
487+
470488
/**
471489
* Contains a set of experimental flags that might change in future releases. These flags enable
472490
* features that are still in development and may be modified, renamed, or removed without notice.

packages/nextjs/src/config/webpack.ts

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@ import * as fs from 'fs';
77
import * as path from 'path';
88
import { sync as resolveSync } from 'resolve';
99
import type { VercelCronsConfig } from '../common/types';
10+
import type { RouteManifest } from './manifest/types';
1011
// Note: If you need to import a type from Webpack, do it in `types.ts` and export it from there. Otherwise, our
1112
// circular dependency check thinks this file is importing from itself. See https://github.com/pahen/madge/issues/306.
1213
import type {
@@ -43,6 +44,7 @@ export function constructWebpackConfigFunction(
4344
userNextConfig: NextConfigObject = {},
4445
userSentryOptions: SentryBuildOptions = {},
4546
releaseName: string | undefined,
47+
routeManifest: RouteManifest | undefined,
4648
): WebpackConfigFunction {
4749
// Will be called by nextjs and passed its default webpack configuration and context data about the build (whether
4850
// 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(
8890
const newConfig = setUpModuleRules(rawNewConfig);
8991

9092
// Add a loader which will inject code that sets global values
91-
addValueInjectionLoader(newConfig, userNextConfig, userSentryOptions, buildContext, releaseName);
93+
addValueInjectionLoader(newConfig, userNextConfig, userSentryOptions, buildContext, releaseName, routeManifest);
9294

9395
addOtelWarningIgnoreRule(newConfig);
9496

@@ -686,6 +688,7 @@ function addValueInjectionLoader(
686688
userSentryOptions: SentryBuildOptions,
687689
buildContext: BuildContext,
688690
releaseName: string | undefined,
691+
routeManifest: RouteManifest | undefined,
689692
): void {
690693
const assetPrefix = userNextConfig.assetPrefix || userNextConfig.basePath || '';
691694

@@ -727,6 +730,7 @@ function addValueInjectionLoader(
727730
_sentryExperimentalThirdPartyOriginStackFrames: userSentryOptions._experimental?.thirdPartyOriginStackFrames
728731
? 'true'
729732
: undefined,
733+
_sentryRouteManifest: JSON.stringify(routeManifest),
730734
};
731735

732736
if (buildContext.isServer) {

packages/nextjs/src/config/withSentryConfig.ts

Lines changed: 13 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,8 @@ import { getSentryRelease } from '@sentry/node';
55
import * as childProcess from 'child_process';
66
import * as fs from 'fs';
77
import * as path from 'path';
8+
import { createRouteManifest } from './manifest/createRouteManifest';
9+
import type { RouteManifest } from './manifest/types';
810
import type {
911
ExportedNextConfig as NextConfig,
1012
NextConfigFunction,
@@ -141,6 +143,11 @@ function getFinalConfigObject(
141143
}
142144
}
143145

146+
let routeManifest: RouteManifest | undefined;
147+
if (!userSentryOptions.disableManifestInjection) {
148+
routeManifest = createRouteManifest();
149+
}
150+
144151
setUpBuildTimeVariables(incomingUserNextConfigObject, userSentryOptions, releaseName);
145152

146153
const nextJsVersion = getNextjsVersion();
@@ -300,7 +307,12 @@ function getFinalConfigObject(
300307
],
301308
},
302309
}),
303-
webpack: constructWebpackConfigFunction(incomingUserNextConfigObject, userSentryOptions, releaseName),
310+
webpack: constructWebpackConfigFunction(
311+
incomingUserNextConfigObject,
312+
userSentryOptions,
313+
releaseName,
314+
routeManifest,
315+
),
304316
};
305317
}
306318

0 commit comments

Comments
 (0)