Skip to content

Commit a818271

Browse files
authored
ref(nextjs): Remove sentry field in Next.js config as a means of configuration (#10839)
1 parent 8879fd5 commit a818271

9 files changed

+111
-93
lines changed

MIGRATION.md

Lines changed: 39 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -518,6 +518,45 @@ The following previously deprecated API has been removed from the `@sentry/nextj
518518
- `IS_BUILD`
519519
- `isBuild`
520520

521+
#### Removal of the `sentry` property in your Next.js options (next.config.js)
522+
523+
With version 8 of the Sentry Next.js SDK, the SDK will no longer support passing Next.js options with a `sentry`
524+
property to `withSentryConfig`. Please use the third argument of `withSentryConfig` to configure the SDK instead:
525+
526+
```ts
527+
// OLD
528+
const nextConfig = {
529+
// Your Next.js options...
530+
531+
sentry: {
532+
// Your Sentry SDK options...
533+
},
534+
};
535+
536+
module.exports = withSentryConfig(nextConfig, {
537+
// Your Sentry Webpack Plugin Options...
538+
});
539+
540+
// NEW
541+
const nextConfig = {
542+
// Your Next.js options...
543+
};
544+
545+
module.exports = withSentryConfig(
546+
nextConfig,
547+
{
548+
// Your Sentry Webpack Plugin Options...
549+
},
550+
{
551+
// Your Sentry SDK options...
552+
},
553+
);
554+
```
555+
556+
The reason for this change is to have one consistent way of defining the SDK options. We hope that this change will
557+
reduce confusion when setting up the SDK, with the upside that the explicit option is properly typed and will therefore
558+
have code completion.
559+
521560
### Astro SDK
522561

523562
#### Removal of `trackHeaders` option for Astro middleware

packages/nextjs/src/config/types.ts

Lines changed: 4 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -4,29 +4,15 @@ import type { DefinePlugin, WebpackPluginInstance } from 'webpack';
44

55
export type SentryWebpackPluginOptions = SentryCliPluginOptions;
66
export type SentryWebpackPlugin = WebpackPluginInstance & { options: SentryWebpackPluginOptions };
7+
78
// Export this from here because importing something from Webpack (the library) in `webpack.ts` confuses the heck out of
89
// madge, which we use for circular dependency checking. We've manually excluded this file from the check (which is
910
// safe, since it only includes types), so we can import it here without causing madge to fail. See
1011
// https://github.com/pahen/madge/issues/306.
1112
export type { WebpackPluginInstance };
1213

13-
/**
14-
* Overall Nextjs config
15-
*/
16-
17-
// The first argument to `withSentryConfig` (which is the user's next config) may contain a `sentry` key, which we'll
18-
// remove once we've captured it, in order to prevent nextjs from throwing warnings. Since it's only in there
19-
// temporarily, we don't include it in the main `NextConfigObject` or `NextConfigFunction` types.
20-
export type ExportedNextConfig = NextConfigObjectWithSentry | NextConfigFunctionWithSentry;
21-
22-
export type NextConfigObjectWithSentry = NextConfigObject & {
23-
sentry?: UserSentryOptions;
24-
};
25-
26-
export type NextConfigFunctionWithSentry = (
27-
phase: string,
28-
defaults: { defaultConfig: NextConfigObject },
29-
) => NextConfigObjectWithSentry | PromiseLike<NextConfigObjectWithSentry>;
14+
// The first argument to `withSentryConfig` (which is the user's next config).
15+
export type ExportedNextConfig = NextConfigObject | NextConfigFunction;
3016

3117
// Vendored from Next.js (this type is not complete - extend if necessary)
3218
type NextRewrite = {
@@ -62,7 +48,7 @@ export type NextConfigObject = {
6248
>;
6349
};
6450

65-
export type UserSentryOptions = {
51+
export type SentryBuildtimeOptions = {
6652
/**
6753
* Override the SDK's default decision about whether or not to enable to the Sentry webpack plugin for server files.
6854
* Note that `false` forces the plugin to be enabled, even in situations where it's not recommended.

packages/nextjs/src/config/webpack.ts

Lines changed: 7 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -17,8 +17,8 @@ import type {
1717
BuildContext,
1818
EntryPropertyObject,
1919
NextConfigObject,
20+
SentryBuildtimeOptions,
2021
SentryWebpackPluginOptions,
21-
UserSentryOptions,
2222
WebpackConfigFunction,
2323
WebpackConfigObject,
2424
WebpackConfigObjectWithModuleRules,
@@ -61,7 +61,7 @@ let showedMissingGlobalErrorWarningMsg = false;
6161
export function constructWebpackConfigFunction(
6262
userNextConfig: NextConfigObject = {},
6363
userSentryWebpackPluginOptions: Partial<SentryWebpackPluginOptions> = {},
64-
userSentryOptions: UserSentryOptions = {},
64+
userSentryOptions: SentryBuildtimeOptions = {},
6565
): WebpackConfigFunction {
6666
// Will be called by nextjs and passed its default webpack configuration and context data about the build (whether
6767
// we're building server or client, whether we're in dev, what version of webpack we're using, etc). Note that
@@ -511,7 +511,7 @@ function findTranspilationRules(rules: WebpackModuleRule[] | undefined, projectD
511511
async function addSentryToEntryProperty(
512512
currentEntryProperty: WebpackEntryProperty,
513513
buildContext: BuildContext,
514-
userSentryOptions: UserSentryOptions,
514+
userSentryOptions: SentryBuildtimeOptions,
515515
): Promise<EntryPropertyObject> {
516516
// The `entry` entry in a webpack config can be a string, array of strings, object, or function. By default, nextjs
517517
// sets it to an async function which returns the promise of an object of string arrays. Because we don't know whether
@@ -725,7 +725,7 @@ function shouldAddSentryToEntryPoint(entryPointName: string, runtime: 'node' | '
725725
export function getWebpackPluginOptions(
726726
buildContext: BuildContext,
727727
userPluginOptions: Partial<SentryWebpackPluginOptions>,
728-
userSentryOptions: UserSentryOptions,
728+
userSentryOptions: SentryBuildtimeOptions,
729729
): SentryWebpackPluginOptions {
730730
const { buildId, isServer, config, dir: projectDir } = buildContext;
731731
const userNextConfig = config as NextConfigObject;
@@ -884,7 +884,7 @@ export function getWebpackPluginOptions(
884884
}
885885

886886
/** Check various conditions to decide if we should run the plugin */
887-
function shouldEnableWebpackPlugin(buildContext: BuildContext, userSentryOptions: UserSentryOptions): boolean {
887+
function shouldEnableWebpackPlugin(buildContext: BuildContext, userSentryOptions: SentryBuildtimeOptions): boolean {
888888
const { isServer } = buildContext;
889889
const { disableServerWebpackPlugin, disableClientWebpackPlugin } = userSentryOptions;
890890

@@ -900,7 +900,7 @@ function shouldEnableWebpackPlugin(buildContext: BuildContext, userSentryOptions
900900
/** Handle warning messages about `hideSourceMaps` option. Can be removed in v9 or v10 (or whenever we consider that
901901
* enough people will have upgraded the SDK that the warning about the default in v8 - currently commented out - is
902902
* overkill). */
903-
function handleSourcemapHidingOptionWarning(userSentryOptions: UserSentryOptions, isServer: boolean): void {
903+
function handleSourcemapHidingOptionWarning(userSentryOptions: SentryBuildtimeOptions, isServer: boolean): void {
904904
// This is nextjs's own logging formatting, vendored since it's not exported. See
905905
// https://github.com/vercel/next.js/blob/c3ceeb03abb1b262032bd96457e224497d3bbcef/packages/next/build/output/log.ts#L3-L11
906906
// and
@@ -969,7 +969,7 @@ function setUpModuleRules(newConfig: WebpackConfigObject): WebpackConfigObjectWi
969969
function addValueInjectionLoader(
970970
newConfig: WebpackConfigObjectWithModuleRules,
971971
userNextConfig: NextConfigObject,
972-
userSentryOptions: UserSentryOptions,
972+
userSentryOptions: SentryBuildtimeOptions,
973973
buildContext: BuildContext,
974974
sentryWebpackPluginOptions: Partial<SentryWebpackPluginOptions>,
975975
): void {

packages/nextjs/src/config/withSentryConfig.ts

Lines changed: 27 additions & 29 deletions
Original file line numberDiff line numberDiff line change
@@ -1,64 +1,62 @@
11
import { isThenable } from '@sentry/utils';
22

33
import type {
4-
ExportedNextConfig,
4+
ExportedNextConfig as NextConfig,
55
NextConfigFunction,
66
NextConfigObject,
7-
NextConfigObjectWithSentry,
7+
SentryBuildtimeOptions,
88
SentryWebpackPluginOptions,
9-
UserSentryOptions,
109
} from './types';
1110
import { constructWebpackConfigFunction } from './webpack';
1211

1312
let showedExportModeTunnelWarning = false;
1413

1514
/**
16-
* Add Sentry options to the config to be exported from the user's `next.config.js` file.
15+
* Modifies the passed in Next.js configuration with automatic build-time instrumentation and source map upload.
1716
*
18-
* @param exportedUserNextConfig The existing config to be exported prior to adding Sentry
19-
* @param userSentryWebpackPluginOptions Configuration for SentryWebpackPlugin
20-
* @param sentryOptions Optional additional options to add as alternative to `sentry` property of config
17+
* @param nextConfig A Next.js configuration object, as usually exported in `next.config.js` or `next.config.mjs`.
18+
* @param sentryWebpackPluginOptions Options to configure the automatically included Sentry Webpack Plugin for source maps and release management in Sentry.
19+
* @param sentryBuildtimeOptions Additional options to configure instrumentation and
2120
* @returns The modified config to be exported
2221
*/
2322
export function withSentryConfig(
24-
exportedUserNextConfig: ExportedNextConfig = {},
25-
userSentryWebpackPluginOptions: Partial<SentryWebpackPluginOptions> = {},
26-
sentryOptions?: UserSentryOptions,
23+
nextConfig: NextConfig = {},
24+
sentryWebpackPluginOptions: Partial<SentryWebpackPluginOptions> = {},
25+
sentryBuildtimeOptions: SentryBuildtimeOptions = {},
2726
): NextConfigFunction | NextConfigObject {
28-
if (typeof exportedUserNextConfig === 'function') {
27+
if (typeof nextConfig === 'function') {
2928
return function (this: unknown, ...webpackConfigFunctionArgs: unknown[]): ReturnType<NextConfigFunction> {
30-
const maybeUserNextConfigObject: NextConfigObjectWithSentry = exportedUserNextConfig.apply(
31-
this,
32-
webpackConfigFunctionArgs,
33-
);
29+
const maybePromiseNextConfig: ReturnType<typeof nextConfig> = nextConfig.apply(this, webpackConfigFunctionArgs);
3430

35-
if (isThenable(maybeUserNextConfigObject)) {
36-
return maybeUserNextConfigObject.then(function (userNextConfigObject: NextConfigObjectWithSentry) {
37-
const userSentryOptions = { ...userNextConfigObject.sentry, ...sentryOptions };
38-
return getFinalConfigObject(userNextConfigObject, userSentryOptions, userSentryWebpackPluginOptions);
31+
if (isThenable(maybePromiseNextConfig)) {
32+
return maybePromiseNextConfig.then(promiseResultNextConfig => {
33+
return getFinalConfigObject(promiseResultNextConfig, sentryBuildtimeOptions, sentryWebpackPluginOptions);
3934
});
4035
}
4136

42-
// Reassign for naming-consistency sake.
43-
const userNextConfigObject = maybeUserNextConfigObject;
44-
const userSentryOptions = { ...userNextConfigObject.sentry, ...sentryOptions };
45-
return getFinalConfigObject(userNextConfigObject, userSentryOptions, userSentryWebpackPluginOptions);
37+
return getFinalConfigObject(maybePromiseNextConfig, sentryBuildtimeOptions, sentryWebpackPluginOptions);
4638
};
4739
} else {
48-
const userSentryOptions = { ...exportedUserNextConfig.sentry, ...sentryOptions };
49-
return getFinalConfigObject(exportedUserNextConfig, userSentryOptions, userSentryWebpackPluginOptions);
40+
return getFinalConfigObject(nextConfig, sentryBuildtimeOptions, sentryWebpackPluginOptions);
5041
}
5142
}
5243

5344
// Modify the materialized object form of the user's next config by deleting the `sentry` property and wrapping the
5445
// `webpack` property
5546
function getFinalConfigObject(
56-
incomingUserNextConfigObject: NextConfigObjectWithSentry,
57-
userSentryOptions: UserSentryOptions,
47+
incomingUserNextConfigObject: NextConfigObject,
48+
userSentryOptions: SentryBuildtimeOptions,
5849
userSentryWebpackPluginOptions: Partial<SentryWebpackPluginOptions>,
5950
): NextConfigObject {
60-
// Next 12.2.3+ warns about non-canonical properties on `userNextConfig`.
61-
delete incomingUserNextConfigObject.sentry;
51+
if ('sentry' in incomingUserNextConfigObject) {
52+
// eslint-disable-next-line no-console
53+
console.warn(
54+
'[@sentry/nextjs] Setting a `sentry` property on the Next.js config is no longer supported. Please use the `sentrySDKOptions` argument of `withSentryConfig` instead.',
55+
);
56+
57+
// Next 12.2.3+ warns about non-canonical properties on `userNextConfig`.
58+
delete incomingUserNextConfigObject.sentry;
59+
}
6260

6361
if (userSentryOptions?.tunnelRoute) {
6462
if (incomingUserNextConfigObject.output === 'export') {

packages/nextjs/test/config/fixtures.ts

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,6 @@ import type {
33
EntryPropertyFunction,
44
ExportedNextConfig,
55
NextConfigObject,
6-
NextConfigObjectWithSentry,
76
WebpackConfigObject,
87
} from '../../src/config/types';
98

@@ -26,7 +25,7 @@ export const userNextConfig: NextConfigObject = {
2625
};
2726

2827
/** Mocks of the arguments passed to `withSentryConfig` */
29-
export const exportedNextConfig = userNextConfig as NextConfigObjectWithSentry;
28+
export const exportedNextConfig = userNextConfig;
3029
export const userSentryWebpackPluginConfig = { org: 'squirrelChasers', project: 'simulator' };
3130
process.env.SENTRY_AUTH_TOKEN = 'dogsarebadatkeepingsecrets';
3231
process.env.SENTRY_RELEASE = 'doGsaREgReaT';

packages/nextjs/test/config/testUtils.ts

Lines changed: 5 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@ import type {
66
EntryPropertyFunction,
77
ExportedNextConfig,
88
NextConfigObject,
9+
SentryBuildtimeOptions,
910
SentryWebpackPluginOptions,
1011
WebpackConfigObject,
1112
WebpackConfigObjectWithModuleRules,
@@ -28,8 +29,9 @@ export function materializeFinalNextConfig(
2829
exportedNextConfig: ExportedNextConfig,
2930
userSentryWebpackPluginConfig?: Partial<SentryWebpackPluginOptions>,
3031
runtimePhase?: string,
32+
sentryBuildTimeOptions?: SentryBuildtimeOptions,
3133
): NextConfigObject {
32-
const sentrifiedConfig = withSentryConfig(exportedNextConfig, userSentryWebpackPluginConfig);
34+
const sentrifiedConfig = withSentryConfig(exportedNextConfig, userSentryWebpackPluginConfig, sentryBuildTimeOptions);
3335
let finalConfigValues = sentrifiedConfig;
3436

3537
if (typeof sentrifiedConfig === 'function') {
@@ -59,6 +61,7 @@ export async function materializeFinalWebpackConfig(options: {
5961
userSentryWebpackPluginConfig?: Partial<SentryWebpackPluginOptions>;
6062
incomingWebpackConfig: WebpackConfigObject;
6163
incomingWebpackBuildContext: BuildContext;
64+
sentryBuildTimeOptions?: SentryBuildtimeOptions;
6265
}): Promise<WebpackConfigObjectWithModuleRules> {
6366
const { exportedNextConfig, userSentryWebpackPluginConfig, incomingWebpackConfig, incomingWebpackBuildContext } =
6467
options;
@@ -69,15 +72,11 @@ export async function materializeFinalWebpackConfig(options: {
6972
? await exportedNextConfig('phase-production-build', defaultsObject)
7073
: exportedNextConfig;
7174

72-
// extract the `sentry` property as we do in `withSentryConfig`
73-
const { sentry: sentryConfig } = materializedUserNextConfig;
74-
delete materializedUserNextConfig.sentry;
75-
7675
// get the webpack config function we'd normally pass back to next
7776
const webpackConfigFunction = constructWebpackConfigFunction(
7877
materializedUserNextConfig,
7978
userSentryWebpackPluginConfig,
80-
sentryConfig,
79+
options.sentryBuildTimeOptions ?? {},
8180
);
8281

8382
// call it to get concrete values for comparison

packages/nextjs/test/config/webpack/constructWebpackConfig.test.ts

Lines changed: 18 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -48,36 +48,38 @@ describe('constructWebpackConfigFunction()', () => {
4848
});
4949

5050
it("doesn't set devtool if webpack plugin is disabled", () => {
51-
const finalNextConfig = materializeFinalNextConfig({
52-
...exportedNextConfig,
53-
webpack: () =>
54-
({
55-
...serverWebpackConfig,
56-
devtool: 'something-besides-source-map',
57-
}) as any,
58-
sentry: { disableServerWebpackPlugin: true },
59-
});
51+
const finalNextConfig = materializeFinalNextConfig(
52+
{
53+
...exportedNextConfig,
54+
webpack: () =>
55+
({
56+
...serverWebpackConfig,
57+
devtool: 'something-besides-source-map',
58+
}) as any,
59+
},
60+
undefined,
61+
undefined,
62+
{ disableServerWebpackPlugin: true },
63+
);
64+
6065
const finalWebpackConfig = finalNextConfig.webpack?.(serverWebpackConfig, serverBuildContext);
6166

6267
expect(finalWebpackConfig?.devtool).not.toEqual('source-map');
6368
});
6469

6570
it('allows for the use of `hidden-source-map` as `devtool` value for client-side builds', async () => {
66-
const exportedNextConfigHiddenSourceMaps = {
67-
...exportedNextConfig,
68-
sentry: { ...exportedNextConfig.sentry, hideSourceMaps: true },
69-
};
70-
7171
const finalClientWebpackConfig = await materializeFinalWebpackConfig({
72-
exportedNextConfig: exportedNextConfigHiddenSourceMaps,
72+
exportedNextConfig: exportedNextConfig,
7373
incomingWebpackConfig: clientWebpackConfig,
7474
incomingWebpackBuildContext: clientBuildContext,
75+
sentryBuildTimeOptions: { hideSourceMaps: true },
7576
});
7677

7778
const finalServerWebpackConfig = await materializeFinalWebpackConfig({
78-
exportedNextConfig: exportedNextConfigHiddenSourceMaps,
79+
exportedNextConfig: exportedNextConfig,
7980
incomingWebpackConfig: serverWebpackConfig,
8081
incomingWebpackBuildContext: serverBuildContext,
82+
sentryBuildTimeOptions: { hideSourceMaps: true },
8183
});
8284

8385
expect(finalClientWebpackConfig.devtool).toEqual('hidden-source-map');

0 commit comments

Comments
 (0)