diff --git a/packages/nextjs/src/config/types.ts b/packages/nextjs/src/config/types.ts index 6324b35fa36e..2eaf026a8d66 100644 --- a/packages/nextjs/src/config/types.ts +++ b/packages/nextjs/src/config/types.ts @@ -59,6 +59,14 @@ export type UserSentryOptions = { // Automatically instrument Next.js data fetching methods and Next.js API routes autoInstrumentServerFunctions?: boolean; + + // Override the distDir which is helpful if the if you're using a monorepo, such as Nx. + // Ultimately, directs the Sentry CLI to the correct directory. + // Monorepo example: + // App Directory: `apps/my-next-app` + // NextJS `distDir` is set to`../../dist/apps/my-next-app/.next`. + // Sentry `distDirOverride` should be set to `dist/apps/my-next-app/.next`, as the CLI is run from the monorepo root. + distDirOverride?: string; }; export type NextConfigFunction = (phase: string, defaults: { defaultConfig: NextConfigObject }) => NextConfigObject; diff --git a/packages/nextjs/src/config/webpack.ts b/packages/nextjs/src/config/webpack.ts index 52a48e8d04f9..8e4e1621930c 100644 --- a/packages/nextjs/src/config/webpack.ts +++ b/packages/nextjs/src/config/webpack.ts @@ -403,7 +403,7 @@ export function getWebpackPluginOptions( const { buildId, isServer, webpack, config, dev: isDev, dir: projectDir } = buildContext; const userNextConfig = config as NextConfigObject; - const distDir = userNextConfig.distDir ?? '.next'; // `.next` is the default directory + const distDir = userSentryOptions.distDirOverride ?? userNextConfig.distDir ?? '.next'; // `.next` is the default directory const isWebpack5 = webpack.version.startsWith('5'); const isServerless = userNextConfig.target === 'experimental-serverless-trace'; diff --git a/packages/nextjs/test/config/webpack/sentryWebpackPlugin.test.ts b/packages/nextjs/test/config/webpack/sentryWebpackPlugin.test.ts index c08736a7b2d9..afb544cf6264 100644 --- a/packages/nextjs/test/config/webpack/sentryWebpackPlugin.test.ts +++ b/packages/nextjs/test/config/webpack/sentryWebpackPlugin.test.ts @@ -99,6 +99,27 @@ describe('Sentry webpack plugin config', () => { ]); }); + it('has the correct value when building client bundles using `distDirOverride` option', async () => { + const exportedNextConfigWithDistDirOverride = { + ...exportedNextConfig, + sentry: { distDirOverride: 'dist/.next' }, + }; + const finalWebpackConfig = await materializeFinalWebpackConfig({ + exportedNextConfig: exportedNextConfigWithDistDirOverride, + incomingWebpackConfig: clientWebpackConfig, + incomingWebpackBuildContext: getBuildContext('client', exportedNextConfigWithDistDirOverride), + }); + + const sentryWebpackPluginInstance = findWebpackPlugin( + finalWebpackConfig, + 'SentryCliPlugin', + ) as SentryWebpackPlugin; + + expect(sentryWebpackPluginInstance.options.include).toEqual([ + { paths: ['dist/.next/static/chunks/pages'], urlPrefix: '~/_next/static/chunks/pages' }, + ]); + }); + it('has the correct value when building serverless server bundles', async () => { const exportedNextConfigServerless = { ...exportedNextConfig, @@ -474,4 +495,52 @@ describe('Sentry webpack plugin config', () => { } }); }); + + describe('correct paths from `distDirOverride` in WebpackPluginOptions', () => { + const customDistDir = 'tmpDir'; + const defaultDistDir = '.next'; + const expectedDistDir = 'dist/.next'; + + it.each([ + getBuildContext('client', {}), + getBuildContext('server', { target: 'experimental-serverless-trace' }), // serverless + getBuildContext('server', {}, '4'), + getBuildContext('server', {}, '5'), + ])('`distDir` is not defined', (buildContext: BuildContext) => { + const includePaths = getWebpackPluginOptions( + buildContext, + {}, // userPluginOptions + { distDirOverride: expectedDistDir }, // userSentryOptions + ).include as { paths: [] }[]; + + expect(buildContext.config.distDir).toEqual(defaultDistDir); + + for (const pathDescriptor of includePaths) { + for (const path of pathDescriptor.paths) { + expect(path).toMatch(new RegExp(`^${expectedDistDir}.*`)); + } + } + }); + + it.each([ + getBuildContext('client', { distDir: customDistDir }), + getBuildContext('server', { distDir: customDistDir, target: 'experimental-serverless-trace' }), // serverless + getBuildContext('server', { distDir: customDistDir }, '4'), + getBuildContext('server', { distDir: customDistDir }, '5'), + ])('`distDir` is defined', (buildContext: BuildContext) => { + const includePaths = getWebpackPluginOptions( + buildContext, + {}, // userPluginOptions + { distDirOverride: expectedDistDir }, // userSentryOptions + ).include as { paths: [] }[]; + + expect(buildContext.config.distDir).toEqual(customDistDir); + + for (const pathDescriptor of includePaths) { + for (const path of pathDescriptor.paths) { + expect(path).toMatch(new RegExp(`^${expectedDistDir}.*`)); + } + } + }); + }); });