Skip to content

Commit 13c6462

Browse files
chargomelforst
andauthored
feat(nextjs)!: Respect user-provided source map generation settings (#14956)
- Enables `deleteSourceMapsAfterUpload` by default if unset - Modifies the webpack sourcemap config if no explicit value is set closes #14905 --------- Co-authored-by: Luca Forstner <luca.forstner@sentry.io>
1 parent 8e53415 commit 13c6462

File tree

3 files changed

+75
-15
lines changed

3 files changed

+75
-15
lines changed

docs/migration/v8-to-v9.md

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -100,6 +100,10 @@ In v9, an `undefined` value will be treated the same as if the value is not defi
100100

101101
This behavior was changed because the Next.js Build ID is non-deterministic and the release name is injected into client bundles, causing build artifacts to be non-deterministic. This caused issues for some users. Additionally, because it is uncertain whether it will be possible to rely on a Build ID when Turbopack becomes stable, we decided to pull the plug now instead of introducing confusing behavior in the future.
102102

103+
- Source maps are now automatically enabled for both client and server builds unless explicitly disabled via `sourcemaps.disable`. Client builds use `hidden-source-map` while server builds use `source-map` as their webpack `devtool` setting unless any other value than `false` or `undefined` has been assigned already.
104+
105+
- By default, source maps will now be automatically deleted after being uploaded to Sentry for client-side builds. You can opt out of this behavior by explicitly setting `sourcemaps.deleteSourcemapsAfterUpload` to `false` in your Sentry config.
106+
103107
### All Meta-Framework SDKs (`@sentry/astro`, `@sentry/nuxt`)
104108

105109
- Updated source map generation to respect the user-provided value of your build config, such as `vite.build.sourcemap`:

packages/nextjs/src/config/webpack.ts

Lines changed: 28 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -336,23 +336,36 @@ export function constructWebpackConfigFunction(
336336

337337
if (sentryWebpackPlugin) {
338338
if (!userSentryOptions.sourcemaps?.disable) {
339-
// TODO(v9): Remove this warning and print warning in case source map deletion is auto configured
340-
if (!isServer && !userSentryOptions.sourcemaps?.deleteSourcemapsAfterUpload) {
341-
// eslint-disable-next-line no-console
342-
console.warn(
343-
"[@sentry/nextjs] The Sentry SDK has enabled source map generation for your Next.js app. If you don't want to serve Source Maps to your users, either set the `sourcemaps.deleteSourcemapsAfterUpload` option to true, or manually delete the source maps after the build. In future Sentry SDK versions `sourcemaps.deleteSourcemapsAfterUpload` will default to `true`. If you do not want to generate and upload sourcemaps, set the `sourcemaps.disable` option in `withSentryConfig()`.",
344-
);
339+
// Source maps can be configured in 3 ways:
340+
// 1. (next config): productionBrowserSourceMaps
341+
// 2. (next config): experimental.serverSourceMaps
342+
// 3. custom webpack configuration
343+
//
344+
// We only update this if no explicit value is set
345+
// (Next.js defaults to `false`: https://github.com/vercel/next.js/blob/5f4f96c133bd6b10954812cc2fef6af085b82aa5/packages/next/src/build/webpack/config/blocks/base.ts#L61)
346+
if (!newConfig.devtool) {
347+
logger.info(`[@sentry/nextjs] Automatically enabling source map generation for ${runtime} build.`);
348+
// `hidden-source-map` produces the same sourcemaps as `source-map`, but doesn't include the `sourceMappingURL`
349+
// comment at the bottom. For folks who aren't publicly hosting their sourcemaps, this is helpful because then
350+
// the browser won't look for them and throw errors into the console when it can't find them. Because this is a
351+
// front-end-only problem, and because `sentry-cli` handles sourcemaps more reliably with the comment than
352+
// without, the option to use `hidden-source-map` only applies to the client-side build.
353+
if (isServer) {
354+
newConfig.devtool = 'source-map';
355+
} else {
356+
newConfig.devtool = 'hidden-source-map';
357+
}
345358
}
346359

347-
// `hidden-source-map` produces the same sourcemaps as `source-map`, but doesn't include the `sourceMappingURL`
348-
// comment at the bottom. For folks who aren't publicly hosting their sourcemaps, this is helpful because then
349-
// the browser won't look for them and throw errors into the console when it can't find them. Because this is a
350-
// front-end-only problem, and because `sentry-cli` handles sourcemaps more reliably with the comment than
351-
// without, the option to use `hidden-source-map` only applies to the client-side build.
352-
if (isServer || userNextConfig.productionBrowserSourceMaps) {
353-
newConfig.devtool = 'source-map';
354-
} else {
355-
newConfig.devtool = 'hidden-source-map';
360+
// enable source map deletion if not explicitly disabled
361+
if (!isServer && userSentryOptions.sourcemaps?.deleteSourcemapsAfterUpload === undefined) {
362+
logger.warn(
363+
'[@sentry/nextjs] Source maps will be automatically deleted after being uploaded to Sentry. If you want to keep the source maps, set the `sourcemaps.deleteSourcemapsAfterUpload` option to false in `withSentryConfig()`. If you do not want to generate and upload sourcemaps at all, set the `sourcemaps.disable` option to true.',
364+
);
365+
userSentryOptions.sourcemaps = {
366+
...userSentryOptions.sourcemaps,
367+
deleteSourcemapsAfterUpload: true,
368+
};
356369
}
357370
}
358371

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

Lines changed: 43 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
// mock helper functions not tested directly in this file
22
import '../mocks';
33

4+
import * as getWebpackPluginOptionsModule from '../../../src/config/webpackPluginOptions';
45
import {
56
CLIENT_SDK_CONFIG_FILE,
67
clientBuildContext,
@@ -29,6 +30,48 @@ describe('constructWebpackConfigFunction()', () => {
2930
);
3031
});
3132

33+
it('preserves existing devtool setting', async () => {
34+
const customDevtool = 'eval-source-map';
35+
const finalWebpackConfig = await materializeFinalWebpackConfig({
36+
exportedNextConfig,
37+
incomingWebpackConfig: {
38+
...serverWebpackConfig,
39+
devtool: customDevtool,
40+
},
41+
incomingWebpackBuildContext: serverBuildContext,
42+
sentryBuildTimeOptions: {},
43+
});
44+
45+
expect(finalWebpackConfig.devtool).toEqual(customDevtool);
46+
});
47+
48+
it('automatically enables deleteSourcemapsAfterUpload for client builds when not explicitly set', async () => {
49+
const getWebpackPluginOptionsSpy = jest.spyOn(getWebpackPluginOptionsModule, 'getWebpackPluginOptions');
50+
51+
await materializeFinalWebpackConfig({
52+
exportedNextConfig,
53+
incomingWebpackConfig: clientWebpackConfig,
54+
incomingWebpackBuildContext: clientBuildContext,
55+
sentryBuildTimeOptions: {
56+
sourcemaps: {},
57+
},
58+
});
59+
60+
expect(getWebpackPluginOptionsSpy).toHaveBeenCalledWith(
61+
expect.objectContaining({
62+
isServer: false,
63+
}),
64+
expect.objectContaining({
65+
sourcemaps: {
66+
deleteSourcemapsAfterUpload: true,
67+
},
68+
}),
69+
undefined,
70+
);
71+
72+
getWebpackPluginOptionsSpy.mockRestore();
73+
});
74+
3275
it('preserves unrelated webpack config options', async () => {
3376
const finalWebpackConfig = await materializeFinalWebpackConfig({
3477
exportedNextConfig,

0 commit comments

Comments
 (0)