Skip to content

Commit 6e539e0

Browse files
authored
feat(nextjs): Deprecate Webpack top-level options (getsentry#18343)
This PR deprecates the webpack-only configurations via the `@deprecated` JSDoc annotation and introduces a new `webpack` config namespace for them. Under the hood the logic was changed to read from the new values, with a compatibility layer that sets them from the deprecated top-level options while warning for each option if used. This should set us up for a v11/v12 deletion of those options. I might have missed a few options that only affect webpack, so I appreciate a good look at this. At any case this isn't breaking so even if missed a few, users won't experience disruptions.
1 parent fdf22a3 commit 6e539e0

File tree

6 files changed

+414
-29
lines changed

6 files changed

+414
-29
lines changed

packages/nextjs/src/config/getBuildPluginOptions.ts

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -205,7 +205,7 @@ function createReleaseConfig(
205205
vcsRemote: sentryBuildOptions.release?.vcsRemote,
206206
setCommits: sentryBuildOptions.release?.setCommits,
207207
deploy: sentryBuildOptions.release?.deploy,
208-
...sentryBuildOptions.unstable_sentryWebpackPluginOptions?.release,
208+
...sentryBuildOptions.webpack?.unstable_sentryWebpackPluginOptions?.release,
209209
};
210210
}
211211

@@ -272,8 +272,8 @@ export function getBuildPluginOptions({
272272
reactComponentAnnotation: buildTool.startsWith('after-production-compile')
273273
? undefined
274274
: {
275-
...sentryBuildOptions.reactComponentAnnotation,
276-
...sentryBuildOptions.unstable_sentryWebpackPluginOptions?.reactComponentAnnotation,
275+
...sentryBuildOptions.webpack?.reactComponentAnnotation,
276+
...sentryBuildOptions.webpack?.unstable_sentryWebpackPluginOptions?.reactComponentAnnotation,
277277
},
278278
silent: sentryBuildOptions.silent,
279279
url: sentryBuildOptions.sentryUrl,
@@ -283,7 +283,7 @@ export function getBuildPluginOptions({
283283
assets: sentryBuildOptions.sourcemaps?.assets ?? sourcemapUploadAssets,
284284
ignore: sentryBuildOptions.sourcemaps?.ignore ?? sourcemapUploadIgnore,
285285
filesToDeleteAfterUpload,
286-
...sentryBuildOptions.unstable_sentryWebpackPluginOptions?.sourcemaps,
286+
...sentryBuildOptions.webpack?.unstable_sentryWebpackPluginOptions?.sourcemaps,
287287
},
288288
release: createReleaseConfig(releaseName, sentryBuildOptions),
289289
bundleSizeOptimizations: {
@@ -295,6 +295,6 @@ export function getBuildPluginOptions({
295295
metaFramework: 'nextjs',
296296
},
297297
},
298-
...sentryBuildOptions.unstable_sentryWebpackPluginOptions,
298+
...sentryBuildOptions.webpack?.unstable_sentryWebpackPluginOptions,
299299
};
300300
}

packages/nextjs/src/config/types.ts

Lines changed: 106 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -57,6 +57,91 @@ export type NextConfigObject = {
5757
};
5858
};
5959

60+
export type SentryBuildWebpackOptions = {
61+
/**
62+
* Automatically instrument Next.js data fetching methods and Next.js API routes with error and performance monitoring.
63+
* Defaults to `true`.
64+
*/
65+
autoInstrumentServerFunctions?: boolean;
66+
67+
/**
68+
* Automatically instrument Next.js middleware with error and performance monitoring. Defaults to `true`.
69+
*/
70+
autoInstrumentMiddleware?: boolean;
71+
72+
/**
73+
* Automatically instrument components in the `app` directory with error monitoring. Defaults to `true`.
74+
*/
75+
autoInstrumentAppDirectory?: boolean;
76+
77+
/**
78+
* Automatically create cron monitors in Sentry for your Vercel Cron Jobs if configured via `vercel.json`.
79+
*
80+
* Defaults to `false`.
81+
*/
82+
automaticVercelMonitors?: boolean;
83+
84+
/**
85+
* Exclude certain serverside API routes or pages from being instrumented with Sentry during build-time. This option
86+
* takes an array of strings or regular expressions. This options also affects pages in the `app` directory.
87+
*
88+
* NOTE: Pages should be specified as routes (`/animals` or `/api/animals/[animalType]/habitat`), not filepaths
89+
* (`pages/animals/index.js` or `.\src\pages\api\animals\[animalType]\habitat.tsx`), and strings must be be a full,
90+
* exact match.
91+
*
92+
* Notice: If you build Next.js with turbopack, the Sentry SDK will no longer apply build-time instrumentation and
93+
* purely rely on Next.js telemetry features, meaning that this option will effectively no-op.
94+
*/
95+
excludeServerRoutes?: Array<RegExp | string>;
96+
97+
/**
98+
* Disables automatic injection of Sentry's Webpack configuration.
99+
*
100+
* By default, the Sentry Next.js SDK injects its own Webpack configuration to enable features such as
101+
* source map upload and automatic instrumentation. Set this option to `true` if you want to prevent
102+
* the SDK from modifying your Webpack config (for example, if you want to handle Sentry integration manually
103+
* or if you are on an older version of Next.js while using Turbopack).
104+
*/
105+
disableSentryConfig?: boolean;
106+
107+
/**
108+
* Tree-shaking options to help reduce the size of the Sentry SDK bundle.
109+
*/
110+
treeshake?: {
111+
/**
112+
* Removes Sentry SDK logger statements from the bundle. Note that this doesn't affect Sentry Logs.
113+
*/
114+
removeDebugLogging?: boolean;
115+
};
116+
117+
/**
118+
* Options to be passed directly to the Sentry Webpack Plugin (`@sentry/webpack-plugin`) that ships with the Sentry SDK.
119+
* You can use this option to override any options the SDK passes to the Webpack plugin.
120+
*
121+
* Please note that this option is unstable and may change in a breaking way in any release.
122+
*/
123+
unstable_sentryWebpackPluginOptions?: SentryWebpackPluginOptions;
124+
125+
/**
126+
* Options related to react component name annotations.
127+
* Disabled by default, unless a value is set for this option.
128+
* When enabled, your app's DOM will automatically be annotated during build-time with their respective component names.
129+
* This will unlock the capability to search for Replays in Sentry by component name, as well as see component names in breadcrumbs and performance monitoring.
130+
* Please note that this feature is not currently supported by the esbuild bundler plugins, and will only annotate React components
131+
*/
132+
reactComponentAnnotation?: {
133+
/**
134+
* Whether the component name annotate plugin should be enabled or not.
135+
*/
136+
enabled?: boolean;
137+
138+
/**
139+
* A list of strings representing the names of components to ignore. The plugin will not apply `data-sentry` annotations on the DOM element for these components.
140+
*/
141+
ignoredComponents?: string[];
142+
};
143+
};
144+
60145
export type SentryBuildOptions = {
61146
/**
62147
* The slug of the Sentry organization associated with the app.
@@ -363,6 +448,8 @@ export type SentryBuildOptions = {
363448
* When enabled, your app's DOM will automatically be annotated during build-time with their respective component names.
364449
* This will unlock the capability to search for Replays in Sentry by component name, as well as see component names in breadcrumbs and performance monitoring.
365450
* Please note that this feature is not currently supported by the esbuild bundler plugins, and will only annotate React components
451+
*
452+
* @deprecated Use `webpack.reactComponentAnnotation` instead.
366453
*/
367454
reactComponentAnnotation?: {
368455
/**
@@ -381,6 +468,7 @@ export type SentryBuildOptions = {
381468
* You can use this option to override any options the SDK passes to the webpack plugin.
382469
*
383470
* Please note that this option is unstable and may change in a breaking way in any release.
471+
* @deprecated Use `webpack.unstable_sentryWebpackPluginOptions` instead.
384472
*/
385473
unstable_sentryWebpackPluginOptions?: SentryWebpackPluginOptions;
386474

@@ -391,6 +479,8 @@ export type SentryBuildOptions = {
391479
* Disabling this option will leave you without readable stacktraces for dependencies and Next.js-internal code.
392480
*
393481
* Defaults to `false`.
482+
*
483+
* This option applies to both webpack and turbopack builds.
394484
*/
395485
// Enabling this option may upload a lot of source maps and since the sourcemap upload endpoint in Sentry is super
396486
// slow we don't enable it by default so that we don't opaquely increase build times for users.
@@ -400,16 +490,19 @@ export type SentryBuildOptions = {
400490
/**
401491
* Automatically instrument Next.js data fetching methods and Next.js API routes with error and performance monitoring.
402492
* Defaults to `true`.
493+
* @deprecated Use `webpack.autoInstrumentServerFunctions` instead.
403494
*/
404495
autoInstrumentServerFunctions?: boolean;
405496

406497
/**
407498
* Automatically instrument Next.js middleware with error and performance monitoring. Defaults to `true`.
499+
* @deprecated Use `webpack.autoInstrumentMiddleware` instead.
408500
*/
409501
autoInstrumentMiddleware?: boolean;
410502

411503
/**
412504
* Automatically instrument components in the `app` directory with error monitoring. Defaults to `true`.
505+
* @deprecated Use `webpack.autoInstrumentAppDirectory` instead.
413506
*/
414507
autoInstrumentAppDirectory?: boolean;
415508

@@ -423,6 +516,8 @@ export type SentryBuildOptions = {
423516
*
424517
* Notice: If you build Next.js with turbopack, the Sentry SDK will no longer apply build-time instrumentation and
425518
* purely rely on Next.js telemetry features, meaning that this option will effectively no-op.
519+
*
520+
* @deprecated Use `webpack.excludeServerRoutes` instead.
426521
*/
427522
excludeServerRoutes?: Array<RegExp | string>;
428523

@@ -439,13 +534,17 @@ export type SentryBuildOptions = {
439534

440535
/**
441536
* Tree shakes Sentry SDK logger statements from the bundle.
537+
*
538+
* @deprecated Use `webpack.treeshake.removeDebugLogging` instead.
442539
*/
443540
disableLogger?: boolean;
444541

445542
/**
446543
* Automatically create cron monitors in Sentry for your Vercel Cron Jobs if configured via `vercel.json`.
447544
*
448545
* Defaults to `false`.
546+
*
547+
* @deprecated Use `webpack.automaticVercelMonitors` instead.
449548
*/
450549
automaticVercelMonitors?: boolean;
451550

@@ -497,6 +596,8 @@ export type SentryBuildOptions = {
497596
* the SDK from modifying your Webpack config (for example, if you want to handle Sentry integration manually
498597
* or if you are on an older version of Next.js while using Turbopack).
499598
*
599+
* @deprecated Use `webpack.disableSentryConfig` instead.
600+
*
500601
* @default false
501602
*/
502603
disableSentryWebpackConfig?: boolean;
@@ -519,6 +620,11 @@ export type SentryBuildOptions = {
519620
_experimental?: Partial<{
520621
thirdPartyOriginStackFrames?: boolean;
521622
}>;
623+
624+
/**
625+
* Options related to webpack builds, has no effect if you are using Turbopack.
626+
*/
627+
webpack?: SentryBuildWebpackOptions;
522628
};
523629

524630
export type NextConfigFunction = (

packages/nextjs/src/config/webpack.ts

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -145,7 +145,7 @@ export function constructWebpackConfigFunction({
145145
appDir: appDirPath,
146146
pagesDir: pagesDirPath,
147147
pageExtensionRegex,
148-
excludeServerRoutes: userSentryOptions.excludeServerRoutes,
148+
excludeServerRoutes: userSentryOptions.webpack?.excludeServerRoutes,
149149
nextjsRequestAsyncStorageModulePath: getRequestAsyncStorageModuleLocation(
150150
projectDir,
151151
rawNewConfig.resolve?.modules,
@@ -220,7 +220,7 @@ export function constructWebpackConfigFunction({
220220
);
221221
};
222222

223-
if (isServer && userSentryOptions.autoInstrumentServerFunctions !== false) {
223+
if (isServer && userSentryOptions.webpack?.autoInstrumentServerFunctions !== false) {
224224
// It is very important that we insert our loaders at the beginning of the array because we expect any sort of transformations/transpilations (e.g. TS -> JS) to already have happened.
225225

226226
// Wrap pages
@@ -239,7 +239,7 @@ export function constructWebpackConfigFunction({
239239

240240
let vercelCronsConfig: VercelCronsConfig = undefined;
241241
try {
242-
if (process.env.VERCEL && userSentryOptions.automaticVercelMonitors) {
242+
if (process.env.VERCEL && userSentryOptions.webpack?.automaticVercelMonitors) {
243243
// eslint-disable-next-line @typescript-eslint/no-unsafe-member-access
244244
vercelCronsConfig = JSON.parse(fs.readFileSync(path.join(process.cwd(), 'vercel.json'), 'utf8')).crons;
245245
if (vercelCronsConfig) {
@@ -277,7 +277,7 @@ export function constructWebpackConfigFunction({
277277

278278
// Wrap middleware
279279
const canWrapStandaloneMiddleware = userNextConfig.output !== 'standalone' || !major || major < 16;
280-
if ((userSentryOptions.autoInstrumentMiddleware ?? true) && canWrapStandaloneMiddleware) {
280+
if ((userSentryOptions.webpack?.autoInstrumentMiddleware ?? true) && canWrapStandaloneMiddleware) {
281281
newConfig.module.rules.unshift({
282282
test: isMiddlewareResource,
283283
use: [
@@ -293,7 +293,7 @@ export function constructWebpackConfigFunction({
293293
}
294294
}
295295

296-
if (isServer && userSentryOptions.autoInstrumentAppDirectory !== false) {
296+
if (isServer && userSentryOptions.webpack?.autoInstrumentAppDirectory !== false) {
297297
// Wrap server components
298298
newConfig.module.rules.unshift({
299299
test: isServerComponentResource,
@@ -428,7 +428,7 @@ export function constructWebpackConfigFunction({
428428
}
429429
}
430430

431-
if (userSentryOptions.disableLogger) {
431+
if (userSentryOptions.webpack?.treeshake?.removeDebugLogging) {
432432
newConfig.plugins = newConfig.plugins || [];
433433
newConfig.plugins.push(
434434
new buildContext.webpack.DefinePlugin({

packages/nextjs/src/config/withSentryConfig.ts

Lines changed: 91 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -98,12 +98,102 @@ function generateRandomTunnelRoute(): string {
9898
return `/${randomString}`;
9999
}
100100

101+
/**
102+
* Migrates deprecated top-level webpack options to the new `webpack.*` path for backward compatibility.
103+
* The new path takes precedence over deprecated options. This mutates the userSentryOptions object.
104+
*/
105+
function migrateDeprecatedWebpackOptions(userSentryOptions: SentryBuildOptions): void {
106+
// Initialize webpack options if not present
107+
userSentryOptions.webpack = userSentryOptions.webpack || {};
108+
109+
const webpack = userSentryOptions.webpack;
110+
111+
const withDeprecatedFallback = <T>(
112+
newValue: T | undefined,
113+
deprecatedValue: T | undefined,
114+
message: string,
115+
): T | undefined => {
116+
if (deprecatedValue !== undefined) {
117+
// eslint-disable-next-line no-console
118+
console.warn(message);
119+
}
120+
121+
return newValue ?? deprecatedValue;
122+
};
123+
124+
const deprecatedMessage = (deprecatedPath: string, newPath: string): string =>
125+
`[@sentry/nextjs] DEPRECATION WARNING: ${deprecatedPath} is deprecated and will be removed in a future version. Use ${newPath} instead.`;
126+
127+
/* eslint-disable deprecation/deprecation */
128+
// Migrate each deprecated option to the new path, but only if the new path isn't already set
129+
webpack.autoInstrumentServerFunctions = withDeprecatedFallback(
130+
webpack.autoInstrumentServerFunctions,
131+
userSentryOptions.autoInstrumentServerFunctions,
132+
deprecatedMessage('autoInstrumentServerFunctions', 'webpack.autoInstrumentServerFunctions'),
133+
);
134+
135+
webpack.autoInstrumentMiddleware = withDeprecatedFallback(
136+
webpack.autoInstrumentMiddleware,
137+
userSentryOptions.autoInstrumentMiddleware,
138+
deprecatedMessage('autoInstrumentMiddleware', 'webpack.autoInstrumentMiddleware'),
139+
);
140+
141+
webpack.autoInstrumentAppDirectory = withDeprecatedFallback(
142+
webpack.autoInstrumentAppDirectory,
143+
userSentryOptions.autoInstrumentAppDirectory,
144+
deprecatedMessage('autoInstrumentAppDirectory', 'webpack.autoInstrumentAppDirectory'),
145+
);
146+
147+
webpack.excludeServerRoutes = withDeprecatedFallback(
148+
webpack.excludeServerRoutes,
149+
userSentryOptions.excludeServerRoutes,
150+
deprecatedMessage('excludeServerRoutes', 'webpack.excludeServerRoutes'),
151+
);
152+
153+
webpack.unstable_sentryWebpackPluginOptions = withDeprecatedFallback(
154+
webpack.unstable_sentryWebpackPluginOptions,
155+
userSentryOptions.unstable_sentryWebpackPluginOptions,
156+
deprecatedMessage('unstable_sentryWebpackPluginOptions', 'webpack.unstable_sentryWebpackPluginOptions'),
157+
);
158+
159+
webpack.disableSentryConfig = withDeprecatedFallback(
160+
webpack.disableSentryConfig,
161+
userSentryOptions.disableSentryWebpackConfig,
162+
deprecatedMessage('disableSentryWebpackConfig', 'webpack.disableSentryConfig'),
163+
);
164+
165+
// Handle treeshake.removeDebugLogging specially since it's nested
166+
if (userSentryOptions.disableLogger !== undefined) {
167+
webpack.treeshake = webpack.treeshake || {};
168+
webpack.treeshake.removeDebugLogging = withDeprecatedFallback(
169+
webpack.treeshake.removeDebugLogging,
170+
userSentryOptions.disableLogger,
171+
deprecatedMessage('disableLogger', 'webpack.treeshake.removeDebugLogging'),
172+
);
173+
}
174+
175+
webpack.automaticVercelMonitors = withDeprecatedFallback(
176+
webpack.automaticVercelMonitors,
177+
userSentryOptions.automaticVercelMonitors,
178+
deprecatedMessage('automaticVercelMonitors', 'webpack.automaticVercelMonitors'),
179+
);
180+
181+
webpack.reactComponentAnnotation = withDeprecatedFallback(
182+
webpack.reactComponentAnnotation,
183+
userSentryOptions.reactComponentAnnotation,
184+
deprecatedMessage('reactComponentAnnotation', 'webpack.reactComponentAnnotation'),
185+
);
186+
}
187+
101188
// Modify the materialized object form of the user's next config by deleting the `sentry` property and wrapping the
102189
// `webpack` property
103190
function getFinalConfigObject(
104191
incomingUserNextConfigObject: NextConfigObject,
105192
userSentryOptions: SentryBuildOptions,
106193
): NextConfigObject {
194+
// Migrate deprecated webpack options to new webpack path for backward compatibility
195+
migrateDeprecatedWebpackOptions(userSentryOptions);
196+
107197
// Only determine a release name if release creation is not explicitly disabled
108198
// This prevents injection of Git commit hashes that break build determinism
109199
const shouldCreateRelease = userSentryOptions.release?.create !== false;
@@ -363,7 +453,7 @@ function getFinalConfigObject(
363453
],
364454
},
365455
}),
366-
...(isWebpack && !userSentryOptions.disableSentryWebpackConfig
456+
...(isWebpack && !userSentryOptions.webpack?.disableSentryConfig
367457
? {
368458
webpack: constructWebpackConfigFunction({
369459
userNextConfig: incomingUserNextConfigObject,

0 commit comments

Comments
 (0)