diff --git a/dev-packages/e2e-tests/test-applications/nextjs-15-t3/next.config.js b/dev-packages/e2e-tests/test-applications/nextjs-15-t3/next.config.js index b22141b67893..a1ec081d7e72 100644 --- a/dev-packages/e2e-tests/test-applications/nextjs-15-t3/next.config.js +++ b/dev-packages/e2e-tests/test-applications/nextjs-15-t3/next.config.js @@ -6,6 +6,10 @@ const config = {}; import { withSentryConfig } from '@sentry/nextjs'; export default withSentryConfig(config, { - disableLogger: true, + webpack: { + treeshake: { + removeDebugLogging: true, + }, + }, silent: true, }); diff --git a/dev-packages/e2e-tests/test-applications/nextjs-16-bun/next.config.ts b/dev-packages/e2e-tests/test-applications/nextjs-16-bun/next.config.ts index 79929c9e969e..3e7a140e801b 100644 --- a/dev-packages/e2e-tests/test-applications/nextjs-16-bun/next.config.ts +++ b/dev-packages/e2e-tests/test-applications/nextjs-16-bun/next.config.ts @@ -5,7 +5,5 @@ const nextConfig: NextConfig = {}; export default withSentryConfig(nextConfig, { silent: true, - _experimental: { - turbopackApplicationKey: 'nextjs-16-bun-e2e', - }, + applicationKey: 'nextjs-16-bun-e2e', }); diff --git a/dev-packages/e2e-tests/test-applications/nextjs-16-streaming/next.config.ts b/dev-packages/e2e-tests/test-applications/nextjs-16-streaming/next.config.ts index 6067696c7d16..825aba6ec5fd 100644 --- a/dev-packages/e2e-tests/test-applications/nextjs-16-streaming/next.config.ts +++ b/dev-packages/e2e-tests/test-applications/nextjs-16-streaming/next.config.ts @@ -8,9 +8,9 @@ const nextConfig: NextConfig = {}; export default withSentryConfig(nextConfig, { silent: true, + applicationKey: 'nextjs-16-streaming-e2e', _experimental: { vercelCronsMonitoring: true, - turbopackApplicationKey: 'nextjs-16-streaming-e2e', turbopackReactComponentAnnotation: { enabled: true, }, diff --git a/dev-packages/e2e-tests/test-applications/nextjs-16/next.config.ts b/dev-packages/e2e-tests/test-applications/nextjs-16/next.config.ts index ee93730e8d1d..389448fc29f8 100644 --- a/dev-packages/e2e-tests/test-applications/nextjs-16/next.config.ts +++ b/dev-packages/e2e-tests/test-applications/nextjs-16/next.config.ts @@ -14,9 +14,9 @@ const nextConfig: NextConfig = { export default withSentryConfig(nextConfig, { silent: true, + applicationKey: 'nextjs-16-e2e', _experimental: { vercelCronsMonitoring: true, - turbopackApplicationKey: 'nextjs-16-e2e', turbopackReactComponentAnnotation: { enabled: true, }, diff --git a/dev-packages/e2e-tests/test-applications/nextjs-orpc/next.config.js b/dev-packages/e2e-tests/test-applications/nextjs-orpc/next.config.js index ade813b1cde3..54723b889027 100644 --- a/dev-packages/e2e-tests/test-applications/nextjs-orpc/next.config.js +++ b/dev-packages/e2e-tests/test-applications/nextjs-orpc/next.config.js @@ -4,5 +4,9 @@ const config = {}; import { withSentryConfig } from '@sentry/nextjs'; export default withSentryConfig(config, { - disableLogger: true, + webpack: { + treeshake: { + removeDebugLogging: true, + }, + }, }); diff --git a/dev-packages/e2e-tests/test-applications/supabase-nextjs/next.config.js b/dev-packages/e2e-tests/test-applications/supabase-nextjs/next.config.js index 8c9ca1eb52c6..61672affb524 100644 --- a/dev-packages/e2e-tests/test-applications/supabase-nextjs/next.config.js +++ b/dev-packages/e2e-tests/test-applications/supabase-nextjs/next.config.js @@ -25,23 +25,27 @@ module.exports = withSentryConfig(module.exports, { // Upload a larger set of source maps for prettier stack traces (increases build time) widenClientFileUpload: true, - // Automatically annotate React components to show their full name in breadcrumbs and session replay - reactComponentAnnotation: { - enabled: true, - }, - // Route browser requests to Sentry through a Next.js rewrite to circumvent ad-blockers. // This can increase your server load as well as your hosting bill. // Note: Check that the configured route will not match with your Next.js middleware, otherwise reporting of client- // side errors will fail. tunnelRoute: '/monitoring', - // Automatically tree-shake Sentry logger statements to reduce bundle size - disableLogger: false, - - // Enables automatic instrumentation of Vercel Cron Monitors. (Does not yet work with App Router route handlers.) - // See the following for more information: - // https://docs.sentry.io/product/crons/ - // https://vercel.com/docs/cron-jobs - automaticVercelMonitors: true, + webpack: { + // Automatically annotate React components to show their full name in breadcrumbs and session replay + reactComponentAnnotation: { + enabled: true, + }, + + // Automatically tree-shake Sentry logger statements to reduce bundle size + treeshake: { + removeDebugLogging: false, + }, + + // Enables automatic instrumentation of Vercel Cron Monitors. (Does not yet work with App Router route handlers.) + // See the following for more information: + // https://docs.sentry.io/product/crons/ + // https://vercel.com/docs/cron-jobs + automaticVercelMonitors: true, + }, }); diff --git a/docs/migration/v11-end-state.md b/docs/migration/v11-end-state.md index 2611cb5d9970..74c4c6464a88 100644 --- a/docs/migration/v11-end-state.md +++ b/docs/migration/v11-end-state.md @@ -860,19 +860,22 @@ Sentry.init({ ### `@sentry/nextjs` -The following long-deprecated options in `withSentryConfig` / the `sentry` config were removed: - -- `unstable_sentryWebpackPluginOptions` -- `autoInstrumentServerFunctions` -- `autoInstrumentMiddleware` -- `autoInstrumentAppDirectory` -- `disableLogger` -- `automaticVercelMonitors` -- `disableManifestInjection` -- `disableSentryWebpackConfig` -- `turbopackApplicationKey` - -Remove these options from your `next.config.js` / `next.config.ts`. +The following long-deprecated top-level options in `withSentryConfig` / the `sentry` config were removed. Most of them +moved under the `webpack` option in v10; use the replacement listed below instead: + +| Removed option | Replacement | +| --------------------------------------- | -------------------------------------------------------------- | +| `autoInstrumentServerFunctions` | `webpack.autoInstrumentServerFunctions` | +| `autoInstrumentMiddleware` | `webpack.autoInstrumentMiddleware` | +| `autoInstrumentAppDirectory` | `webpack.autoInstrumentAppDirectory` | +| `automaticVercelMonitors` | `webpack.automaticVercelMonitors` | +| `excludeServerRoutes` | `webpack.excludeServerRoutes` | +| `reactComponentAnnotation` | `webpack.reactComponentAnnotation` | +| `unstable_sentryWebpackPluginOptions` | `webpack.unstable_sentryWebpackPluginOptions` | +| `disableSentryWebpackConfig` | `webpack.disableSentryConfig` | +| `disableLogger` | `webpack.treeshake.removeDebugLogging` | +| `disableManifestInjection` | `routeManifestInjection: false` | +| `_experimental.turbopackApplicationKey` | `applicationKey` (works for both webpack and Turbopack builds) | ### Meta-framework build options diff --git a/packages/nextjs/src/client/index.ts b/packages/nextjs/src/client/index.ts index b7f9c482b816..5c557c4cc66b 100644 --- a/packages/nextjs/src/client/index.ts +++ b/packages/nextjs/src/client/index.ts @@ -53,7 +53,7 @@ export function init(options: BrowserOptions): Client | undefined { consoleSandbox(() => { // eslint-disable-next-line no-console console.warn( - '[@sentry/nextjs] You have enabled `debug: true`, but Sentry debug logging was removed from your bundle (likely via `withSentryConfig({ disableLogger: true })` / `webpack.treeshake.removeDebugLogging: true`). Set that option to `false` to see Sentry debug output.', + '[@sentry/nextjs] You have enabled `debug: true`, but Sentry debug logging was removed from your bundle (likely via `webpack.treeshake.removeDebugLogging: true`). Set that option to `false` to see Sentry debug output.', ); }); } diff --git a/packages/nextjs/src/config/turbopack/constructTurbopackConfig.ts b/packages/nextjs/src/config/turbopack/constructTurbopackConfig.ts index fd58c4e95216..bed34b3875ec 100644 --- a/packages/nextjs/src/config/turbopack/constructTurbopackConfig.ts +++ b/packages/nextjs/src/config/turbopack/constructTurbopackConfig.ts @@ -78,8 +78,7 @@ export function constructTurbopackConfig({ // so it is safe even for node_modules with strict initialization order. // We only exclude Next.js build polyfills which contain non-standard syntax that causes // parse errors when any code is prepended (Turbopack re-parses the loader output). - // eslint-disable-next-line typescript/no-deprecated - const applicationKey = userSentryOptions?.applicationKey ?? userSentryOptions?._experimental?.turbopackApplicationKey; + const applicationKey = userSentryOptions?.applicationKey; if (applicationKey && nextJsVersion && supportsTurbopackRuleCondition(nextJsVersion)) { newConfig.rules = safelyAddTurbopackRule(newConfig.rules, { matcher: '*.{ts,tsx,js,jsx,mjs,cjs}', diff --git a/packages/nextjs/src/config/types.ts b/packages/nextjs/src/config/types.ts index a82b663c562c..60231fd0f958 100644 --- a/packages/nextjs/src/config/types.ts +++ b/packages/nextjs/src/config/types.ts @@ -531,36 +531,6 @@ export type SentryBuildOptions = { excludeReplayWorker?: boolean; }; - /** - * Options related to react component name annotations. - * Disabled by default, unless a value is set for this option. - * When enabled, your app's DOM will automatically be annotated during build-time with their respective component names. - * This will unlock the capability to search for Replays in Sentry by component name, as well as see component names in breadcrumbs and performance monitoring. - * Please note that this feature is not currently supported by the esbuild bundler plugins, and will only annotate React components - * - * @deprecated Use `webpack.reactComponentAnnotation` instead. - */ - reactComponentAnnotation?: { - /** - * Whether the component name annotate plugin should be enabled or not. - */ - enabled?: boolean; - - /** - * A list of strings representing the names of components to ignore. The plugin will not apply `data-sentry` annotations on the DOM element for these components. - */ - ignoredComponents?: string[]; - }; // TODO(v11): remove this option - - /** - * Options to be passed directly to the Sentry Webpack Plugin (`@sentry/bundler-plugins/webpack`) that ships with the Sentry Next.js SDK. - * You can use this option to override any options the SDK passes to the webpack plugin. - * - * Please note that this option is unstable and may change in a breaking way in any release. - * @deprecated Use `webpack.unstable_sentryWebpackPluginOptions` instead. - */ - unstable_sentryWebpackPluginOptions?: SentryWebpackPluginOptions; // TODO(v11): remove this option - /** * Include Next.js-internal code and code from dependencies when uploading source maps. * @@ -576,40 +546,6 @@ export type SentryBuildOptions = { // TODO: Add an alias to this function called "uploadSourceMapsForDependencies" widenClientFileUpload?: boolean; - /** - * Automatically instrument Next.js data fetching methods and Next.js API routes with error and performance monitoring. - * Defaults to `true`. - * @deprecated Use `webpack.autoInstrumentServerFunctions` instead. - */ - autoInstrumentServerFunctions?: boolean; // TODO(v11): remove this option - - /** - * Automatically instrument Next.js middleware with error and performance monitoring. Defaults to `true`. - * @deprecated Use `webpack.autoInstrumentMiddleware` instead. - */ - autoInstrumentMiddleware?: boolean; // TODO(v11): remove this option - - /** - * Automatically instrument components in the `app` directory with error monitoring. Defaults to `true`. - * @deprecated Use `webpack.autoInstrumentAppDirectory` instead. - */ - autoInstrumentAppDirectory?: boolean; // TODO(v11): remove this option - - /** - * Exclude certain serverside API routes or pages from being instrumented with Sentry during build-time. This option - * takes an array of strings or regular expressions. This options also affects pages in the `app` directory. - * - * NOTE: Pages should be specified as routes (`/animals` or `/api/animals/[animalType]/habitat`), not filepaths - * (`pages/animals/index.js` or `.\src\pages\api\animals\[animalType]\habitat.tsx`), and strings must be be a full, - * exact match. - * - * Notice: If you build Next.js with turbopack, the Sentry SDK will no longer apply build-time instrumentation and - * purely rely on Next.js telemetry features, meaning that this option will effectively no-op. - * - * @deprecated Use `webpack.excludeServerRoutes` instead. - */ - excludeServerRoutes?: Array; - /** * Tunnel Sentry requests through this route on the Next.js server, to circumvent ad-blockers blocking Sentry events * from being sent. This option should be a path (for example: '/error-monitoring'). @@ -621,22 +557,6 @@ export type SentryBuildOptions = { */ tunnelRoute?: string | boolean; - /** - * Tree shakes Sentry SDK logger statements from the bundle. - * - * @deprecated Use `webpack.treeshake.removeDebugLogging` instead. - */ - disableLogger?: boolean; // TODO(v11): remove this option - - /** - * Automatically create cron monitors in Sentry for your Vercel Cron Jobs if configured via `vercel.json`. - * - * Defaults to `false`. - * - * @deprecated Use `webpack.automaticVercelMonitors` instead. - */ - automaticVercelMonitors?: boolean; // TODO(v11): remove this option - /** * When an error occurs during release creation or sourcemaps upload, the plugin will call this function. * @@ -659,15 +579,6 @@ export type SentryBuildOptions = { */ suppressOnRouterTransitionStartWarning?: boolean; - /** - * Disables automatic injection of the route manifest into the client bundle. - * - * @deprecated Use `routeManifestInjection: false` instead. - * - * @default false - */ - disableManifestInjection?: boolean; // TODO(v11): remove this option - /** * Options for the route manifest injection feature. * @@ -716,20 +627,6 @@ export type SentryBuildOptions = { exclude?: Array | ((route: string) => boolean); }; - /** - * Disables automatic injection of Sentry's Webpack configuration. - * - * By default, the Sentry Next.js SDK injects its own Webpack configuration to enable features such as - * source map upload and automatic instrumentation. Set this option to `true` if you want to prevent - * the SDK from modifying your Webpack config (for example, if you want to handle Sentry integration manually - * or if you are on an older version of Next.js while using Turbopack). - * - * @deprecated Use `webpack.disableSentryConfig` instead. - * - * @default false - */ - disableSentryWebpackConfig?: boolean; // TODO(v11): remove this option - /** * When true (and Next.js >= 15), use the runAfterProductionCompile hook to consolidate sourcemap uploads * into a single operation after builds complete, reducing build time. @@ -753,19 +650,6 @@ export type SentryBuildOptions = { * Requires cron jobs to be configured in `vercel.json`. */ vercelCronsMonitoring?: boolean; - /** - * Application key used by `thirdPartyErrorFilterIntegration` to distinguish - * first-party code from third-party code in Turbopack builds. - * - * When set, a Turbopack loader injects `_sentryModuleMetadata` into every - * first-party module, mirroring what `@sentry/bundler-plugins/webpack` does for - * webpack builds via its `moduleMetadata` / `applicationKey` option. - * - * Requires Next.js 16+ - * - * @deprecated Use the top-level `applicationKey` option instead, which works for both webpack and Turbopack builds. - */ - turbopackApplicationKey?: string; // TODO(v11): remove this option /** * Options for React component name annotation in Turbopack builds. * When enabled, JSX elements are annotated with `data-sentry-component`, diff --git a/packages/nextjs/src/config/withSentryConfig/deprecatedWebpackOptions.ts b/packages/nextjs/src/config/withSentryConfig/deprecatedWebpackOptions.ts deleted file mode 100644 index b1903799cc58..000000000000 --- a/packages/nextjs/src/config/withSentryConfig/deprecatedWebpackOptions.ts +++ /dev/null @@ -1,97 +0,0 @@ -import type { SentryBuildOptions } from '../types'; -import { detectActiveBundler } from '../util'; - -/** - * Migrates deprecated top-level webpack options to the new `webpack.*` path for backward compatibility. - * The new path takes precedence over deprecated options. This mutates the userSentryOptions object. - */ -export function migrateDeprecatedWebpackOptions(userSentryOptions: SentryBuildOptions): void { - // Initialize webpack options if not present - userSentryOptions.webpack = userSentryOptions.webpack || {}; - - const webpack = userSentryOptions.webpack; - - const withDeprecatedFallback = ( - newValue: T | undefined, - deprecatedValue: T | undefined, - message: string, - ): T | undefined => { - if (deprecatedValue !== undefined) { - // eslint-disable-next-line no-console - console.warn(message); - } - - return newValue ?? deprecatedValue; - }; - - const deprecatedMessage = (deprecatedPath: string, newPath: string): string => { - const message = `[@sentry/nextjs] DEPRECATION WARNING: ${deprecatedPath} is deprecated and will be removed in a future version. Use ${newPath} instead.`; - - // In Turbopack builds, webpack configuration is not applied, so webpack-scoped options won't have any effect. - if (detectActiveBundler() === 'turbopack' && newPath.startsWith('webpack.')) { - return `${message} (Not supported with Turbopack.)`; - } - - return message; - }; - - /* eslint-disable typescript/no-deprecated */ - // Migrate each deprecated option to the new path, but only if the new path isn't already set - webpack.autoInstrumentServerFunctions = withDeprecatedFallback( - webpack.autoInstrumentServerFunctions, - userSentryOptions.autoInstrumentServerFunctions, - deprecatedMessage('autoInstrumentServerFunctions', 'webpack.autoInstrumentServerFunctions'), - ); - - webpack.autoInstrumentMiddleware = withDeprecatedFallback( - webpack.autoInstrumentMiddleware, - userSentryOptions.autoInstrumentMiddleware, - deprecatedMessage('autoInstrumentMiddleware', 'webpack.autoInstrumentMiddleware'), - ); - - webpack.autoInstrumentAppDirectory = withDeprecatedFallback( - webpack.autoInstrumentAppDirectory, - userSentryOptions.autoInstrumentAppDirectory, - deprecatedMessage('autoInstrumentAppDirectory', 'webpack.autoInstrumentAppDirectory'), - ); - - webpack.excludeServerRoutes = withDeprecatedFallback( - webpack.excludeServerRoutes, - userSentryOptions.excludeServerRoutes, - deprecatedMessage('excludeServerRoutes', 'webpack.excludeServerRoutes'), - ); - - webpack.unstable_sentryWebpackPluginOptions = withDeprecatedFallback( - webpack.unstable_sentryWebpackPluginOptions, - userSentryOptions.unstable_sentryWebpackPluginOptions, - deprecatedMessage('unstable_sentryWebpackPluginOptions', 'webpack.unstable_sentryWebpackPluginOptions'), - ); - - webpack.disableSentryConfig = withDeprecatedFallback( - webpack.disableSentryConfig, - userSentryOptions.disableSentryWebpackConfig, - deprecatedMessage('disableSentryWebpackConfig', 'webpack.disableSentryConfig'), - ); - - // Handle treeshake.removeDebugLogging specially since it's nested - if (userSentryOptions.disableLogger !== undefined) { - webpack.treeshake = webpack.treeshake || {}; - webpack.treeshake.removeDebugLogging = withDeprecatedFallback( - webpack.treeshake.removeDebugLogging, - userSentryOptions.disableLogger, - deprecatedMessage('disableLogger', 'webpack.treeshake.removeDebugLogging'), - ); - } - - webpack.automaticVercelMonitors = withDeprecatedFallback( - webpack.automaticVercelMonitors, - userSentryOptions.automaticVercelMonitors, - deprecatedMessage('automaticVercelMonitors', 'webpack.automaticVercelMonitors'), - ); - - webpack.reactComponentAnnotation = withDeprecatedFallback( - webpack.reactComponentAnnotation, - userSentryOptions.reactComponentAnnotation, - deprecatedMessage('reactComponentAnnotation', 'webpack.reactComponentAnnotation'), - ); -} diff --git a/packages/nextjs/src/config/withSentryConfig/getFinalConfigObject.ts b/packages/nextjs/src/config/withSentryConfig/getFinalConfigObject.ts index ee88fea9c3ea..42ca76586619 100644 --- a/packages/nextjs/src/config/withSentryConfig/getFinalConfigObject.ts +++ b/packages/nextjs/src/config/withSentryConfig/getFinalConfigObject.ts @@ -1,7 +1,6 @@ import type { NextConfigObject, SentryBuildOptions } from '../types'; import { getNextjsVersion } from '../util'; import { setUpBuildTimeVariables } from './buildTime'; -import { migrateDeprecatedWebpackOptions } from './deprecatedWebpackOptions'; import { getBundlerInfo, getServerExternalPackagesPatch, @@ -30,13 +29,12 @@ import { /** * Materializes the final Next.js config object with Sentry's build-time integrations applied. * - * Note: this mutates both `incomingUserNextConfigObject` and `userSentryOptions` (to apply defaults/migrations). + * Note: this mutates both `incomingUserNextConfigObject` and `userSentryOptions` (to apply defaults). */ export function getFinalConfigObject( incomingUserNextConfigObject: NextConfigObject, userSentryOptions: SentryBuildOptions, ): NextConfigObject { - migrateDeprecatedWebpackOptions(userSentryOptions); const releaseName = resolveReleaseName(userSentryOptions); maybeSetUpTunnelRouteRewriteRules(incomingUserNextConfigObject, userSentryOptions); diff --git a/packages/nextjs/src/config/withSentryConfig/getFinalConfigObjectUtils.ts b/packages/nextjs/src/config/withSentryConfig/getFinalConfigObjectUtils.ts index 2e6f76377d41..a4620beb3db1 100644 --- a/packages/nextjs/src/config/withSentryConfig/getFinalConfigObjectUtils.ts +++ b/packages/nextjs/src/config/withSentryConfig/getFinalConfigObjectUtils.ts @@ -92,26 +92,10 @@ export function maybeCreateRouteManifest( incomingUserNextConfigObject: NextConfigObject, userSentryOptions: SentryBuildOptions, ): RouteManifest | undefined { - // Handle deprecated option with warning - // eslint-disable-next-line typescript/no-deprecated - if (userSentryOptions.disableManifestInjection) { - // eslint-disable-next-line no-console - console.warn( - '[@sentry/nextjs] The `disableManifestInjection` option is deprecated. Use `routeManifestInjection: false` instead.', - ); - } - - // If explicitly disabled, skip if (userSentryOptions.routeManifestInjection === false) { return undefined; } - // Still check the deprecated option if the new option is not set - // eslint-disable-next-line typescript/no-deprecated - if (userSentryOptions.routeManifestInjection === undefined && userSentryOptions.disableManifestInjection) { - return undefined; - } - const manifest = createRouteManifest({ basePath: incomingUserNextConfigObject.basePath, }); @@ -305,7 +289,7 @@ export type VercelCronsConfigResult = { * information about which instrumentation approach to use. * * - `_experimental.vercelCronsMonitoring`: New span-based approach (works for both App Router and Pages Router) - * - `automaticVercelMonitors`: Old wrapper-based approach (Pages Router only) + * - `webpack.automaticVercelMonitors`: Old wrapper-based approach (Pages Router only) * * If both are enabled, the new approach is preferred and a warning is logged. */ @@ -344,7 +328,7 @@ export function maybeGetVercelCronsConfig(userSentryOptions: SentryBuildOptions) result.strategy = 'spans'; } else { debug.log( - "[@sentry/nextjs] Creating Sentry cron monitors for your Vercel Cron Jobs. You can disable this feature by setting the 'automaticVercelMonitors' option to false in your Next.js config.", + "[@sentry/nextjs] Creating Sentry cron monitors for your Vercel Cron Jobs. You can disable this feature by setting the 'webpack.automaticVercelMonitors' option to false in your Next.js config.", ); result.strategy = 'wrapper'; } diff --git a/packages/nextjs/src/edge/index.ts b/packages/nextjs/src/edge/index.ts index 1495c2c1c709..97b7f96702be 100644 --- a/packages/nextjs/src/edge/index.ts +++ b/packages/nextjs/src/edge/index.ts @@ -63,7 +63,7 @@ export function init(options: VercelEdgeOptions = {}): void { if (!DEBUG_BUILD && options.debug) { // eslint-disable-next-line no-console console.warn( - '[@sentry/nextjs] You have enabled `debug: true`, but Sentry debug logging was removed from your bundle (likely via `withSentryConfig({ disableLogger: true })` / `webpack.treeshake.removeDebugLogging: true`). Set that option to `false` to see Sentry debug output.', + '[@sentry/nextjs] You have enabled `debug: true`, but Sentry debug logging was removed from your bundle (likely via `webpack.treeshake.removeDebugLogging: true`). Set that option to `false` to see Sentry debug output.', ); } diff --git a/packages/nextjs/src/server/index.ts b/packages/nextjs/src/server/index.ts index 2e0c313ac11c..76d13524708c 100644 --- a/packages/nextjs/src/server/index.ts +++ b/packages/nextjs/src/server/index.ts @@ -112,7 +112,7 @@ export function init(options: NodeOptions): NodeClient | undefined { if (!DEBUG_BUILD && options.debug) { // eslint-disable-next-line no-console console.warn( - '[@sentry/nextjs] You have enabled `debug: true`, but Sentry debug logging was removed from your bundle (likely via `withSentryConfig({ disableLogger: true })` / `webpack.treeshake.removeDebugLogging: true`). Set that option to `false` to see Sentry debug output.', + '[@sentry/nextjs] You have enabled `debug: true`, but Sentry debug logging was removed from your bundle (likely via `webpack.treeshake.removeDebugLogging: true`). Set that option to `false` to see Sentry debug output.', ); } diff --git a/packages/nextjs/test/config/getBuildPluginOptions.test.ts b/packages/nextjs/test/config/getBuildPluginOptions.test.ts index b0934f5ff4c9..0b01bf02973b 100644 --- a/packages/nextjs/test/config/getBuildPluginOptions.test.ts +++ b/packages/nextjs/test/config/getBuildPluginOptions.test.ts @@ -880,8 +880,10 @@ describe('getBuildPluginOptions', () => { const sentryBuildOptions: SentryBuildOptions = { org: 'test-org', project: 'test-project', - reactComponentAnnotation: { - enabled: true, + webpack: { + reactComponentAnnotation: { + enabled: true, + }, }, }; @@ -973,27 +975,6 @@ describe('getBuildPluginOptions', () => { }); }); - describe('applicationKey is not forwarded to webpack plugin', () => { - it('does not include turbopackApplicationKey in webpack plugin options', () => { - const sentryBuildOptions: SentryBuildOptions = { - org: 'test-org', - project: 'test-project', - _experimental: { turbopackApplicationKey: 'my-app' }, - }; - - const result = getBuildPluginOptions({ - sentryBuildOptions, - releaseName: mockReleaseName, - distDirAbsPath: mockDistDirAbsPath, - buildTool: 'webpack-client', - }); - - // turbopackApplicationKey should only be used by the Turbopack loader, - // not forwarded to the webpack plugin - expect(result.applicationKey).toBeUndefined(); - }); - }); - describe('edge cases', () => { it('handles undefined release name gracefully', () => { const sentryBuildOptions: SentryBuildOptions = { diff --git a/packages/nextjs/test/config/turbopack/constructTurbopackConfig.test.ts b/packages/nextjs/test/config/turbopack/constructTurbopackConfig.test.ts index cdf496da0745..8937ba4988ff 100644 --- a/packages/nextjs/test/config/turbopack/constructTurbopackConfig.test.ts +++ b/packages/nextjs/test/config/turbopack/constructTurbopackConfig.test.ts @@ -960,7 +960,7 @@ describe('moduleMetadataInjection with applicationKey', () => { const result = constructTurbopackConfig({ userNextConfig, - userSentryOptions: { _experimental: { turbopackApplicationKey: 'my-app' } }, + userSentryOptions: { applicationKey: 'my-app' }, nextJsVersion: '16.0.0', }); @@ -992,30 +992,12 @@ describe('moduleMetadataInjection with applicationKey', () => { expect(rule.loaders[0]!.options.applicationKey).toBe('my-top-level-key'); }); - it('should prefer top-level applicationKey over deprecated _experimental.turbopackApplicationKey', () => { - const userNextConfig: NextConfigObject = {}; - - const result = constructTurbopackConfig({ - userNextConfig, - userSentryOptions: { - applicationKey: 'top-level-key', - _experimental: { turbopackApplicationKey: 'deprecated-key' }, - }, - nextJsVersion: '16.0.0', - }); - - const rule = result.rules!['*.{ts,tsx,js,jsx,mjs,cjs}'] as { - loaders: Array<{ loader: string; options: { applicationKey: string } }>; - }; - expect(rule.loaders[0]!.options.applicationKey).toBe('top-level-key'); - }); - it('should only exclude Next.js polyfills, not all foreign modules', () => { const userNextConfig: NextConfigObject = {}; const result = constructTurbopackConfig({ userNextConfig, - userSentryOptions: { _experimental: { turbopackApplicationKey: 'my-app' } }, + userSentryOptions: { applicationKey: 'my-app' }, nextJsVersion: '16.0.0', }); @@ -1031,7 +1013,7 @@ describe('moduleMetadataInjection with applicationKey', () => { const result = constructTurbopackConfig({ userNextConfig, - userSentryOptions: { _experimental: { turbopackApplicationKey: 'my-app' } }, + userSentryOptions: { applicationKey: 'my-app' }, nextJsVersion: '15.4.1', }); @@ -1055,7 +1037,7 @@ describe('moduleMetadataInjection with applicationKey', () => { const result = constructTurbopackConfig({ userNextConfig, - userSentryOptions: { _experimental: { turbopackApplicationKey: 'my-app' } }, + userSentryOptions: { applicationKey: 'my-app' }, nextJsVersion: undefined, }); @@ -1067,7 +1049,7 @@ describe('moduleMetadataInjection with applicationKey', () => { const result = constructTurbopackConfig({ userNextConfig, - userSentryOptions: { _experimental: { turbopackApplicationKey: 'custom-key-123' } }, + userSentryOptions: { applicationKey: 'custom-key-123' }, nextJsVersion: '16.0.0', }); @@ -1087,7 +1069,7 @@ describe('moduleMetadataInjection with applicationKey', () => { const result = constructTurbopackConfig({ userNextConfig, - userSentryOptions: { _experimental: { turbopackApplicationKey: 'my-app' } }, + userSentryOptions: { applicationKey: 'my-app' }, routeManifest: mockRouteManifest, nextJsVersion: '16.0.0', }); @@ -1113,7 +1095,7 @@ describe('moduleMetadataInjection with applicationKey', () => { const result = constructTurbopackConfig({ userNextConfig, - userSentryOptions: { _experimental: { turbopackApplicationKey: 'my-app' } }, + userSentryOptions: { applicationKey: 'my-app' }, nextJsVersion: '17.0.0', }); @@ -1288,8 +1270,8 @@ describe('componentAnnotation with turbopackReactComponentAnnotation', () => { const result = constructTurbopackConfig({ userNextConfig, userSentryOptions: { + applicationKey: 'my-app', _experimental: { - turbopackApplicationKey: 'my-app', turbopackReactComponentAnnotation: { enabled: true }, }, }, diff --git a/packages/nextjs/test/config/withSentryConfig.test.ts b/packages/nextjs/test/config/withSentryConfig.test.ts index 5a128716c5b5..717ad9a2e48f 100644 --- a/packages/nextjs/test/config/withSentryConfig.test.ts +++ b/packages/nextjs/test/config/withSentryConfig.test.ts @@ -146,7 +146,7 @@ describe('withSentryConfig', () => { process.env.TURBOPACK = originalTurbopack; }); - it('uses constructed webpack function when Turbopack is disabled and disableSentryWebpackConfig is false/undefined', () => { + it('uses constructed webpack function when Turbopack is disabled and webpack.disableSentryConfig is false/undefined', () => { delete process.env.TURBOPACK; // default behavior @@ -154,13 +154,13 @@ describe('withSentryConfig', () => { expect(finalConfigUndefined.webpack).toBeInstanceOf(Function); const sentryOptions = { - disableSentryWebpackConfig: false, + webpack: { disableSentryConfig: false }, }; const finalConfigFalse = materializeFinalNextConfig(exportedNextConfig, undefined, sentryOptions); expect(finalConfigFalse.webpack).toBeInstanceOf(Function); }); - it('preserves original webpack config when disableSentryWebpackConfig is true (regardless of Turbopack)', () => { + it('preserves original webpack config when webpack.disableSentryConfig is true (regardless of Turbopack)', () => { const originalWebpackFunction = vi.fn(); const configWithWebpack = { ...exportedNextConfig, @@ -168,7 +168,7 @@ describe('withSentryConfig', () => { }; const sentryOptions = { - disableSentryWebpackConfig: true, + webpack: { disableSentryConfig: true }, }; delete process.env.TURBOPACK; @@ -181,7 +181,7 @@ describe('withSentryConfig', () => { expect(finalConfigWithTurbopack.webpack).toBe(originalWebpackFunction); }); - it('preserves original webpack config when Turbopack is enabled (ignores disableSentryWebpackConfig flag)', () => { + it('preserves original webpack config when Turbopack is enabled (ignores webpack.disableSentryConfig flag)', () => { process.env.TURBOPACK = '1'; vi.spyOn(util, 'getNextjsVersion').mockReturnValue('15.4.1'); @@ -192,7 +192,7 @@ describe('withSentryConfig', () => { }; const sentryOptionsWithFalse = { - disableSentryWebpackConfig: false, + webpack: { disableSentryConfig: false }, }; const finalConfigWithFalse = materializeFinalNextConfig(configWithWebpack, undefined, sentryOptionsWithFalse); expect(finalConfigWithFalse.webpack).toBe(originalWebpackFunction); @@ -201,18 +201,18 @@ describe('withSentryConfig', () => { expect(finalConfigWithUndefined.webpack).toBe(originalWebpackFunction); const sentryOptionsWithTrue = { - disableSentryWebpackConfig: true, + webpack: { disableSentryConfig: true }, }; const finalConfigWithTrue = materializeFinalNextConfig(configWithWebpack, undefined, sentryOptionsWithTrue); expect(finalConfigWithTrue.webpack).toBe(originalWebpackFunction); }); - it('preserves original webpack config when Turbopack is enabled and disableSentryWebpackConfig is true', () => { + it('preserves original webpack config when Turbopack is enabled and webpack.disableSentryConfig is true', () => { process.env.TURBOPACK = '1'; vi.spyOn(util, 'getNextjsVersion').mockReturnValue('15.4.1'); const sentryOptions = { - disableSentryWebpackConfig: true, + webpack: { disableSentryConfig: true }, }; const originalWebpackFunction = vi.fn(); @@ -226,12 +226,12 @@ describe('withSentryConfig', () => { expect(finalConfig.webpack).toBe(originalWebpackFunction); }); - it('preserves undefined webpack when Turbopack is enabled, disableSentryWebpackConfig is true, and no original webpack config exists', () => { + it('preserves undefined webpack when Turbopack is enabled, webpack.disableSentryConfig is true, and no original webpack config exists', () => { process.env.TURBOPACK = '1'; vi.spyOn(util, 'getNextjsVersion').mockReturnValue('15.4.1'); const sentryOptions = { - disableSentryWebpackConfig: true, + webpack: { disableSentryConfig: true }, }; const configWithoutWebpack = { @@ -285,178 +285,6 @@ describe('withSentryConfig', () => { const finalConfig = materializeFinalNextConfig(configWithWebpack, undefined, sentryOptions); expect(finalConfig.webpack).toBe(originalWebpackFunction); }); - - it('new webpack path takes precedence over deprecated top-level options', () => { - delete process.env.TURBOPACK; - - const originalWebpackFunction = vi.fn(); - const configWithWebpack = { - ...exportedNextConfig, - webpack: originalWebpackFunction, - }; - - // Both old and new paths set, new should win - const sentryOptions = { - disableSentryWebpackConfig: false, // deprecated - says enable - webpack: { - disableSentryConfig: true, // new - says disable - }, - }; - - const finalConfig = materializeFinalNextConfig(configWithWebpack, undefined, sentryOptions); - // Should preserve original webpack because new path disables it - expect(finalConfig.webpack).toBe(originalWebpackFunction); - }); - - it('falls back to deprecated option when new path is not set', () => { - delete process.env.TURBOPACK; - - const originalWebpackFunction = vi.fn(); - const configWithWebpack = { - ...exportedNextConfig, - webpack: originalWebpackFunction, - }; - - // Only deprecated path set - const sentryOptions = { - disableSentryWebpackConfig: true, - }; - - const finalConfig = materializeFinalNextConfig(configWithWebpack, undefined, sentryOptions); - // Should preserve original webpack because deprecated option disables it - expect(finalConfig.webpack).toBe(originalWebpackFunction); - }); - - it('merges webpack.treeshake.removeDebugLogging with deprecated disableLogger', () => { - delete process.env.TURBOPACK; - - // New webpack.treeshake.removeDebugLogging should map to disableLogger internally - const sentryOptionsNew = { - webpack: { - treeshake: { - removeDebugLogging: true, - }, - }, - }; - - const sentryOptionsOld = { - disableLogger: true, - }; - - // Both should work the same way internally (though we can't easily test the actual effect here) - const finalConfigNew = materializeFinalNextConfig(exportedNextConfig, undefined, sentryOptionsNew); - const finalConfigOld = materializeFinalNextConfig(exportedNextConfig, undefined, sentryOptionsOld); - - // Both should have webpack functions (not disabled) - expect(finalConfigNew.webpack).toBeInstanceOf(Function); - expect(finalConfigOld.webpack).toBeInstanceOf(Function); - }); - }); - - describe('deprecation warnings', () => { - let consoleWarnSpy: ReturnType; - - beforeEach(() => { - consoleWarnSpy = vi.spyOn(console, 'warn').mockImplementation(() => {}); - }); - - afterEach(() => { - consoleWarnSpy.mockRestore(); - delete process.env.TURBOPACK; - vi.restoreAllMocks(); - }); - - it('warns when using deprecated top-level options', () => { - delete process.env.TURBOPACK; - - const sentryOptions = { - disableLogger: true, - }; - - materializeFinalNextConfig(exportedNextConfig, undefined, sentryOptions); - - expect(consoleWarnSpy).toHaveBeenCalledWith( - expect.stringContaining('[@sentry/nextjs] DEPRECATION WARNING: disableLogger is deprecated'), - ); - expect(consoleWarnSpy).toHaveBeenCalledWith( - expect.stringContaining('Use webpack.treeshake.removeDebugLogging instead'), - ); - }); - - it('adds a turbopack note when the deprecated option only applies to webpack', () => { - process.env.TURBOPACK = '1'; - vi.spyOn(util, 'getNextjsVersion').mockReturnValue('16.0.0'); - - const sentryOptions = { - disableLogger: true, - }; - - materializeFinalNextConfig(exportedNextConfig, undefined, sentryOptions); - - expect(consoleWarnSpy).toHaveBeenCalledWith( - expect.stringContaining('Use webpack.treeshake.removeDebugLogging instead. (Not supported with Turbopack.)'), - ); - }); - - it('does not warn when using new webpack path', () => { - delete process.env.TURBOPACK; - - const sentryOptions = { - webpack: { - treeshake: { - removeDebugLogging: true, - }, - }, - }; - - materializeFinalNextConfig(exportedNextConfig, undefined, sentryOptions); - - expect(consoleWarnSpy).not.toHaveBeenCalled(); - }); - - it('warns even when new path is also set', () => { - delete process.env.TURBOPACK; - - const sentryOptions = { - disableLogger: true, // deprecated - webpack: { - treeshake: { - removeDebugLogging: false, // new path takes precedence - }, - }, - }; - - materializeFinalNextConfig(exportedNextConfig, undefined, sentryOptions); - - // Should warn because deprecated value is present - expect(consoleWarnSpy).toHaveBeenCalledWith( - expect.stringContaining('[@sentry/nextjs] DEPRECATION WARNING: disableLogger is deprecated'), - ); - }); - - it('warns for multiple deprecated options at once', () => { - delete process.env.TURBOPACK; - - const sentryOptions = { - disableLogger: true, - automaticVercelMonitors: false, - excludeServerRoutes: ['/api/test'], - }; - - materializeFinalNextConfig(exportedNextConfig, undefined, sentryOptions); - - // Should warn for all three deprecated options - expect(consoleWarnSpy).toHaveBeenCalledWith( - expect.stringContaining('[@sentry/nextjs] DEPRECATION WARNING: disableLogger is deprecated'), - ); - expect(consoleWarnSpy).toHaveBeenCalledWith( - expect.stringContaining('[@sentry/nextjs] DEPRECATION WARNING: automaticVercelMonitors is deprecated'), - ); - expect(consoleWarnSpy).toHaveBeenCalledWith( - expect.stringContaining('[@sentry/nextjs] DEPRECATION WARNING: excludeServerRoutes is deprecated'), - ); - expect(consoleWarnSpy).toHaveBeenCalledTimes(3); - }); }); });