From 2e32c30ced05108492536e4d95fa97674cd34751 Mon Sep 17 00:00:00 2001 From: Katie Byers Date: Mon, 24 Jan 2022 07:30:04 -0800 Subject: [PATCH] feat(nextjs): Add option to use `hidden-source-map` as webpack `devtool` value (#4436) We currently force the value of the webpack option `devtool` to be `source-map`, in order to guarantee that the correct sourcemaps are generated during build. There is another `devtool` value[1], `hidden-source-map`, which produces the same maps (so just as good for our purposes), but without adding `sourceMappingURL` comments at the bottom of the resulting JS files. (Some users prefer this as a way not to have the browser complain when it tries to follow the `sourceMappingURL` link and comes up empty.) This PR adds an option that users can pass in their nextjs config, under the key `sentry.hideSourceMaps`. When this is set to true, the SDK will use `hidden-source-map` as the `devtool` value instead of `source-map`. Note that since this is a front-end-only problem, the option only applies to client-side builds. The new option is documented in https://github.com/getsentry/sentry-docs/pull/4627. Fixes https://github.com/getsentry/sentry-javascript/issues/3549. [1] https://webpack.js.org/configuration/devtool/ --- packages/nextjs/src/config/types.ts | 1 + packages/nextjs/src/config/webpack.ts | 11 ++++++++--- packages/nextjs/test/config.test.ts | 20 ++++++++++++++++++++ 3 files changed, 29 insertions(+), 3 deletions(-) diff --git a/packages/nextjs/src/config/types.ts b/packages/nextjs/src/config/types.ts index 77b7316ed0ca..9b45595c0c5f 100644 --- a/packages/nextjs/src/config/types.ts +++ b/packages/nextjs/src/config/types.ts @@ -20,6 +20,7 @@ export type NextConfigObject = { sentry?: { disableServerWebpackPlugin?: boolean; disableClientWebpackPlugin?: boolean; + hideSourceMaps?: boolean; }; } & { // other `next.config.js` options diff --git a/packages/nextjs/src/config/webpack.ts b/packages/nextjs/src/config/webpack.ts index 180cc1476325..3893aea9293f 100644 --- a/packages/nextjs/src/config/webpack.ts +++ b/packages/nextjs/src/config/webpack.ts @@ -77,12 +77,17 @@ export function constructWebpackConfigFunction( if (enableWebpackPlugin) { // TODO Handle possibility that user is using `SourceMapDevToolPlugin` (see // https://webpack.js.org/plugins/source-map-dev-tool-plugin/) - // TODO Give user option to use `hidden-source-map` ? - // Next doesn't let you change this is dev even if you want to - see + // Next doesn't let you change `devtool` in dev even if you want to, so don't bother trying - see // https://github.com/vercel/next.js/blob/master/errors/improper-devtool.md if (!buildContext.dev) { - newConfig.devtool = 'source-map'; + // `hidden-source-map` produces the same sourcemaps as `source-map`, but doesn't include the `sourceMappingURL` + // comment at the bottom. For folks who aren't publicly hosting their sourcemaps, this is helpful because then + // the browser won't look for them and throw errors into the console when it can't find them. Because this is a + // front-end-only problem, and because `sentry-cli` handles sourcemaps more reliably with the comment than + // without, the option to use `hidden-source-map` only applies to the client-side build. + newConfig.devtool = + userNextConfig.sentry?.hideSourceMaps && !buildContext.isServer ? 'hidden-source-map' : 'source-map'; } newConfig.plugins = newConfig.plugins || []; diff --git a/packages/nextjs/test/config.test.ts b/packages/nextjs/test/config.test.ts index c53143c59a0e..aee2bfddacfc 100644 --- a/packages/nextjs/test/config.test.ts +++ b/packages/nextjs/test/config.test.ts @@ -300,6 +300,26 @@ describe('webpack config', () => { expect(finalWebpackConfig).toEqual(expect.objectContaining(materializedUserWebpackConfig)); }); + it('allows for the use of `hidden-source-map` as `devtool` value for client-side builds', async () => { + const userNextConfigHiddenSourceMaps = { ...userNextConfig, sentry: { ...userNextConfig.sentry } }; + userNextConfigHiddenSourceMaps.sentry.hideSourceMaps = true; + + const finalClientWebpackConfig = await materializeFinalWebpackConfig({ + userNextConfig: userNextConfigHiddenSourceMaps, + incomingWebpackConfig: clientWebpackConfig, + incomingWebpackBuildContext: clientBuildContext, + }); + + const finalServerWebpackConfig = await materializeFinalWebpackConfig({ + userNextConfig: userNextConfigHiddenSourceMaps, + incomingWebpackConfig: serverWebpackConfig, + incomingWebpackBuildContext: serverBuildContext, + }); + + expect(finalClientWebpackConfig.devtool).toEqual('hidden-source-map'); + expect(finalServerWebpackConfig.devtool).toEqual('source-map'); + }); + describe('webpack `entry` property config', () => { const serverConfigFilePath = `./${SERVER_SDK_CONFIG_FILE}`; const clientConfigFilePath = `./${CLIENT_SDK_CONFIG_FILE}`;