Skip to content

Commit e06b502

Browse files
authored
feat(nextjs): Add options to disable webpack plugin (getsentry#3771)
Despite our strong encouragement, not everyone wants to use the `SentryWebpackPlugin` to upload sourcemaps. This PR introduces two new options, `disableServerWebpackPlugin` and `disableClientWebpackPlugin`, which can be used in `next.config.js` like this: ``` const { withSentryConfig } = require("@sentry/nextjs"); const moduleExports = { sentry: { disableServerWebpackPlugin: true, disableClientWebpackPlugin: true, }, }; // unnecessary if the webpack plugin is disabled for both server and client (in that case, can also safely // be omitted from the `withSentryConfig` call below) const SentryWebpackPluginOptions = { // ... }; module.exports = withSentryConfig(moduleExports, SentryWebpackPluginOptions); ``` Setting either of these options does two things in the relevant (server or client) config: - prevents the SDK from forcing `webpack.devtool` to be `source-map` in production, and - prevents the SDK from adding an instance of `SentryWebpackPlugin` to the webpack config. These changes are documented in getsentry/sentry-docs#3826. Fixes getsentry#3674
1 parent 2ee6fa8 commit e06b502

File tree

3 files changed

+73
-23
lines changed

3 files changed

+73
-23
lines changed

packages/nextjs/src/config/types.ts

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,10 @@ export type ExportedNextConfig = NextConfigObject | NextConfigFunction;
99
export type NextConfigObject = {
1010
// custom webpack options
1111
webpack?: WebpackConfigFunction;
12+
sentry?: {
13+
disableServerWebpackPlugin?: boolean;
14+
disableClientWebpackPlugin?: boolean;
15+
};
1216
} & {
1317
// other `next.config.js` options
1418
[key: string]: unknown;

packages/nextjs/src/config/webpack.ts

Lines changed: 30 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -69,16 +69,6 @@ export function constructWebpackConfigFunction(
6969
newConfig = userNextConfig.webpack(newConfig, options);
7070
}
7171

72-
// Ensure quality source maps in production. (Source maps aren't uploaded in dev, and besides, Next doesn't let you
73-
// change this is dev even if you want to - see
74-
// https://github.com/vercel/next.js/blob/master/errors/improper-devtool.md.)
75-
if (!options.dev) {
76-
// TODO Handle possibility that user is using `SourceMapDevToolPlugin` (see
77-
// https://webpack.js.org/plugins/source-map-dev-tool-plugin/)
78-
// TODO Give user option to use `hidden-source-map` ?
79-
newConfig.devtool = 'source-map';
80-
}
81-
8272
// Tell webpack to inject user config files (containing the two `Sentry.init()` calls) into the appropriate output
8373
// bundles. Store a separate reference to the original `entry` value to avoid an infinite loop. (If we don't do
8474
// this, we'll have a statement of the form `x.y = () => f(x.y)`, where one of the things `f` does is call `x.y`.
@@ -90,19 +80,36 @@ export function constructWebpackConfigFunction(
9080
const origEntryProperty = newConfig.entry;
9181
newConfig.entry = async () => addSentryToEntryProperty(origEntryProperty, options.isServer);
9282

93-
// Add the Sentry plugin, which uploads source maps to Sentry when not in dev
94-
checkWebpackPluginOverrides(userSentryWebpackPluginOptions);
95-
newConfig.plugins = newConfig.plugins || [];
96-
newConfig.plugins.push(
97-
// @ts-ignore Our types for the plugin are messed up somehow - TS wants this to be `SentryWebpackPlugin.default`,
98-
// but that's not actually a thing
99-
new SentryWebpackPlugin({
100-
dryRun: options.dev,
101-
release: getSentryRelease(options.buildId),
102-
...defaultSentryWebpackPluginOptions,
103-
...userSentryWebpackPluginOptions,
104-
}),
105-
);
83+
// Enable the Sentry plugin (which uploads source maps to Sentry when not in dev) by default
84+
const enableWebpackPlugin = options.isServer
85+
? !userNextConfig.sentry?.disableServerWebpackPlugin
86+
: !userNextConfig.sentry?.disableClientWebpackPlugin;
87+
88+
if (enableWebpackPlugin) {
89+
// TODO Handle possibility that user is using `SourceMapDevToolPlugin` (see
90+
// https://webpack.js.org/plugins/source-map-dev-tool-plugin/)
91+
// TODO Give user option to use `hidden-source-map` ?
92+
93+
// Next doesn't let you change this is dev even if you want to - see
94+
// https://github.com/vercel/next.js/blob/master/errors/improper-devtool.md
95+
if (!options.dev) {
96+
newConfig.devtool = 'source-map';
97+
}
98+
99+
checkWebpackPluginOverrides(userSentryWebpackPluginOptions);
100+
101+
newConfig.plugins = newConfig.plugins || [];
102+
newConfig.plugins.push(
103+
// @ts-ignore Our types for the plugin are messed up somehow - TS wants this to be `SentryWebpackPlugin.default`,
104+
// but that's not actually a thing
105+
new SentryWebpackPlugin({
106+
dryRun: options.dev,
107+
release: getSentryRelease(options.buildId),
108+
...defaultSentryWebpackPluginOptions,
109+
...userSentryWebpackPluginOptions,
110+
}),
111+
);
112+
}
106113

107114
return newConfig;
108115
};

packages/nextjs/test/config.test.ts

Lines changed: 39 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -275,4 +275,43 @@ describe('Sentry webpack plugin config', () => {
275275
it("merges default include and ignore/ignoreFile options with user's values", () => {
276276
// do we even want to do this?
277277
});
278+
279+
it('allows SentryWebpackPlugin to be turned off for client code (independent of server code)', () => {
280+
const clientFinalNextConfig = materializeFinalNextConfig({
281+
...userNextConfig,
282+
sentry: { disableClientWebpackPlugin: true },
283+
});
284+
const clientFinalWebpackConfig = clientFinalNextConfig.webpack?.(clientWebpackConfig, clientBuildContext);
285+
286+
const serverFinalNextConfig = materializeFinalNextConfig(userNextConfig, userSentryWebpackPluginConfig);
287+
const serverFinalWebpackConfig = serverFinalNextConfig.webpack?.(serverWebpackConfig, serverBuildContext);
288+
289+
expect(clientFinalWebpackConfig?.plugins).not.toEqual(expect.arrayContaining([expect.any(SentryWebpackPlugin)]));
290+
expect(serverFinalWebpackConfig?.plugins).toEqual(expect.arrayContaining([expect.any(SentryWebpackPlugin)]));
291+
});
292+
293+
it('allows SentryWebpackPlugin to be turned off for server code (independent of client code)', () => {
294+
const serverFinalNextConfig = materializeFinalNextConfig({
295+
...userNextConfig,
296+
sentry: { disableServerWebpackPlugin: true },
297+
});
298+
const serverFinalWebpackConfig = serverFinalNextConfig.webpack?.(serverWebpackConfig, serverBuildContext);
299+
300+
const clientFinalNextConfig = materializeFinalNextConfig(userNextConfig, userSentryWebpackPluginConfig);
301+
const clientFinalWebpackConfig = clientFinalNextConfig.webpack?.(clientWebpackConfig, clientBuildContext);
302+
303+
expect(serverFinalWebpackConfig?.plugins).not.toEqual(expect.arrayContaining([expect.any(SentryWebpackPlugin)]));
304+
expect(clientFinalWebpackConfig?.plugins).toEqual(expect.arrayContaining([expect.any(SentryWebpackPlugin)]));
305+
});
306+
307+
it("doesn't set devtool if webpack plugin is disabled", () => {
308+
const finalNextConfig = materializeFinalNextConfig({
309+
...userNextConfig,
310+
webpack: () => ({ devtool: 'something-besides-source-map' } as any),
311+
sentry: { disableServerWebpackPlugin: true },
312+
});
313+
const finalWebpackConfig = finalNextConfig.webpack?.(serverWebpackConfig, serverBuildContext);
314+
315+
expect(finalWebpackConfig?.devtool).not.toEqual('source-map');
316+
});
278317
});

0 commit comments

Comments
 (0)