diff --git a/packages/nextjs/src/config/types.ts b/packages/nextjs/src/config/types.ts index 5bab88555056..cd82a3290c1e 100644 --- a/packages/nextjs/src/config/types.ts +++ b/packages/nextjs/src/config/types.ts @@ -26,7 +26,7 @@ export type NextConfigObjectWithSentry = NextConfigObject & { export type NextConfigFunctionWithSentry = ( phase: string, defaults: { defaultConfig: NextConfigObject }, -) => NextConfigObjectWithSentry; +) => NextConfigObjectWithSentry | PromiseLike; // Vendored from Next.js (this type is not complete - extend if necessary) type NextRewrite = { @@ -144,7 +144,10 @@ export type UserSentryOptions = { automaticVercelMonitors?: boolean; }; -export type NextConfigFunction = (phase: string, defaults: { defaultConfig: NextConfigObject }) => NextConfigObject; +export type NextConfigFunction = ( + phase: string, + defaults: { defaultConfig: NextConfigObject }, +) => NextConfigObject | PromiseLike; /** * Webpack config diff --git a/packages/nextjs/src/config/withSentryConfig.ts b/packages/nextjs/src/config/withSentryConfig.ts index 86f8c5a67031..b58603d82056 100644 --- a/packages/nextjs/src/config/withSentryConfig.ts +++ b/packages/nextjs/src/config/withSentryConfig.ts @@ -1,3 +1,5 @@ +import { isThenable } from '@sentry/utils'; + import type { ExportedNextConfig, NextConfigFunction, @@ -24,12 +26,21 @@ export function withSentryConfig( sentryOptions?: UserSentryOptions, ): NextConfigFunction | NextConfigObject { if (typeof exportedUserNextConfig === 'function') { - return function (this: unknown, ...webpackConfigFunctionArgs: unknown[]): NextConfigObject { - const userNextConfigObject: NextConfigObjectWithSentry = exportedUserNextConfig.apply( + return function (this: unknown, ...webpackConfigFunctionArgs: unknown[]): ReturnType { + const maybeUserNextConfigObject: NextConfigObjectWithSentry = exportedUserNextConfig.apply( this, webpackConfigFunctionArgs, ); + if (isThenable(maybeUserNextConfigObject)) { + return maybeUserNextConfigObject.then(function (userNextConfigObject: NextConfigObjectWithSentry) { + const userSentryOptions = { ...userNextConfigObject.sentry, ...sentryOptions }; + return getFinalConfigObject(userNextConfigObject, userSentryOptions, userSentryWebpackPluginOptions); + }); + } + + // Reassign for naming-consistency sake. + const userNextConfigObject = maybeUserNextConfigObject; const userSentryOptions = { ...userNextConfigObject.sentry, ...sentryOptions }; return getFinalConfigObject(userNextConfigObject, userSentryOptions, userSentryWebpackPluginOptions); }; diff --git a/packages/nextjs/test/config/testUtils.ts b/packages/nextjs/test/config/testUtils.ts index be2175b005d6..c9bed5dbe358 100644 --- a/packages/nextjs/test/config/testUtils.ts +++ b/packages/nextjs/test/config/testUtils.ts @@ -35,7 +35,7 @@ export function materializeFinalNextConfig( if (typeof sentrifiedConfig === 'function') { // for some reason TS won't recognize that `finalConfigValues` is now a NextConfigObject, which is why the cast // below is necessary - finalConfigValues = sentrifiedConfig(runtimePhase ?? defaultRuntimePhase, defaultsObject); + finalConfigValues = sentrifiedConfig(runtimePhase ?? defaultRuntimePhase, defaultsObject) as NextConfigObject; } return finalConfigValues as NextConfigObject; @@ -66,7 +66,7 @@ export async function materializeFinalWebpackConfig(options: { // if the user's next config is a function, run it so we have access to the values const materializedUserNextConfig = typeof exportedNextConfig === 'function' - ? exportedNextConfig('phase-production-build', defaultsObject) + ? await exportedNextConfig('phase-production-build', defaultsObject) : exportedNextConfig; // extract the `sentry` property as we do in `withSentryConfig` diff --git a/packages/nextjs/test/integration/next12.config.template b/packages/nextjs/test/integration/next12.config.template index 061cfb6708b6..80b928629534 100644 --- a/packages/nextjs/test/integration/next12.config.template +++ b/packages/nextjs/test/integration/next12.config.template @@ -1,6 +1,6 @@ const { withSentryConfig } = require('@sentry/nextjs'); -const moduleExports = { +const moduleExports = async () => ({ eslint: { ignoreDuringBuilds: true, }, @@ -11,7 +11,7 @@ const moduleExports = { hideSourceMaps: false, excludeServerRoutes: ['/api/excludedEndpoints/excludedWithString', /\/api\/excludedEndpoints\/excludedWithRegExp/], }, -}; +}); const SentryWebpackPluginOptions = { dryRun: true,