diff --git a/packages/core/src/build-time-plugins/buildTimeOptionsBase.ts b/packages/core/src/build-time-plugins/buildTimeOptionsBase.ts index 5c40d53174c1..e43160cc03ab 100644 --- a/packages/core/src/build-time-plugins/buildTimeOptionsBase.ts +++ b/packages/core/src/build-time-plugins/buildTimeOptionsBase.ts @@ -257,6 +257,13 @@ interface ReleaseOptions { */ name?: string; + /** + * Whether the plugin should inject release information into the build for the SDK to pick it up when sending events (recommended). + * + * @default true + */ + inject?: boolean; + /** * Whether to create a new release. * diff --git a/packages/sveltekit/src/vite/sentryVitePlugins.ts b/packages/sveltekit/src/vite/sentryVitePlugins.ts index 4444ba9a6ab7..ca41acba7801 100644 --- a/packages/sveltekit/src/vite/sentryVitePlugins.ts +++ b/packages/sveltekit/src/vite/sentryVitePlugins.ts @@ -73,31 +73,80 @@ export function generateVitePluginOptions( }; } + // todo(v11): remove deprecated options (Also from options type) + // Source Maps if (svelteKitPluginOptions.autoUploadSourceMaps && process.env.NODE_ENV !== 'development') { - const { unstable_sentryVitePluginOptions, ...sourceMapsUploadOptions } = - svelteKitPluginOptions.sourceMapsUploadOptions || {}; + const { + // eslint-disable-next-line deprecation/deprecation + unstable_sentryVitePluginOptions: deprecated_unstableSourceMapUploadOptions, + ...deprecatedSourceMapUploadOptions + // eslint-disable-next-line deprecation/deprecation + } = svelteKitPluginOptions.sourceMapsUploadOptions || {}; + + const { + // eslint-disable-next-line @typescript-eslint/no-unused-vars,deprecation/deprecation + sourceMapsUploadOptions: _filtered1, + // eslint-disable-next-line @typescript-eslint/no-unused-vars + unstable_sentryVitePluginOptions: _filtered2, + // eslint-disable-next-line @typescript-eslint/no-unused-vars + autoUploadSourceMaps: _filtered3, + // eslint-disable-next-line @typescript-eslint/no-unused-vars + autoInstrument: _filtered4, + sentryUrl, + ...newSvelteKitPluginOptions + } = svelteKitPluginOptions; + + const { unstable_sentryVitePluginOptions } = svelteKitPluginOptions; sentryVitePluginsOptions = { ...(sentryVitePluginsOptions ? sentryVitePluginsOptions : {}), - ...sourceMapsUploadOptions, + ...deprecatedSourceMapUploadOptions, + ...newSvelteKitPluginOptions, + + url: sentryUrl, + + ...deprecated_unstableSourceMapUploadOptions, ...unstable_sentryVitePluginOptions, + adapter: svelteKitPluginOptions.adapter, // override the plugin's debug flag with the one from the top-level options debug: svelteKitPluginOptions.debug, }; - if (sentryVitePluginsOptions.sourcemaps) { + // Handle sourcemaps options - merge deprecated and new, with new taking precedence + if ( + // eslint-disable-next-line deprecation/deprecation + deprecatedSourceMapUploadOptions.sourcemaps || + svelteKitPluginOptions.sourcemaps || + deprecated_unstableSourceMapUploadOptions?.sourcemaps || + unstable_sentryVitePluginOptions?.sourcemaps + ) { sentryVitePluginsOptions.sourcemaps = { - ...sourceMapsUploadOptions?.sourcemaps, + // eslint-disable-next-line deprecation/deprecation + ...deprecatedSourceMapUploadOptions.sourcemaps, + ...svelteKitPluginOptions.sourcemaps, + // Also handle nested deprecated options from unstable plugin options + ...deprecated_unstableSourceMapUploadOptions?.sourcemaps, ...unstable_sentryVitePluginOptions?.sourcemaps, }; } - if (sentryVitePluginsOptions.release) { + // Handle release options - merge deprecated and new, with new taking precedence + if ( + // eslint-disable-next-line deprecation/deprecation + deprecatedSourceMapUploadOptions.release || + svelteKitPluginOptions.release || + deprecated_unstableSourceMapUploadOptions?.release || + unstable_sentryVitePluginOptions?.release + ) { sentryVitePluginsOptions.release = { - ...sourceMapsUploadOptions?.release, + // eslint-disable-next-line deprecation/deprecation + ...deprecatedSourceMapUploadOptions.release, + ...svelteKitPluginOptions.release, + // Also handle nested deprecated options from unstable plugin options + ...deprecated_unstableSourceMapUploadOptions?.release, ...unstable_sentryVitePluginOptions?.release, }; } diff --git a/packages/sveltekit/src/vite/types.ts b/packages/sveltekit/src/vite/types.ts index 0f6717a2c7e9..5e792f3bb6df 100644 --- a/packages/sveltekit/src/vite/types.ts +++ b/packages/sveltekit/src/vite/types.ts @@ -1,3 +1,4 @@ +import type { BuildTimeOptionsBase, UnstableVitePluginOptions } from '@sentry/core'; import type { SentryVitePluginOptions } from '@sentry/vite-plugin'; import type { AutoInstrumentSelection } from './autoInstrument'; import type { SupportedSvelteKitAdapters } from './detectAdapter'; @@ -19,18 +20,24 @@ type SourceMapsUploadOptions = { * * To create an auth token, follow this guide: * @see https://docs.sentry.io/product/accounts/auth-tokens/#organization-auth-tokens + * + * @deprecated Use option `authToken` instead of `sourceMapsUploadOptions.authToken` */ authToken?: string; /** * The organization slug of your Sentry organization. * Instead of specifying this option, you can also set the `SENTRY_ORG` environment variable. + * + * @deprecated Use option `org` instead of `sourceMapsUploadOptions.org` */ org?: string; /** * The project slug of your Sentry project. * Instead of specifying this option, you can also set the `SENTRY_PROJECT` environment variable. + * + * @deprecated Use option `project` instead of `sourceMapsUploadOptions.project` */ project?: string; @@ -39,11 +46,13 @@ type SourceMapsUploadOptions = { * It will not collect any sensitive or user-specific data. * * @default true + * @deprecated Use option `telemetry` instead of `sourceMapsUploadOptions.telemetry` */ telemetry?: boolean; /** * Options related to sourcemaps + * @deprecated Use `sourcemaps` instead of `sourceMapsUploadOptions.sourcemaps` */ sourcemaps?: { /** @@ -55,6 +64,7 @@ type SourceMapsUploadOptions = { * * The globbing patterns must follow the implementation of the `glob` package. * @see https://www.npmjs.com/package/glob#glob-primer + * @deprecated Use `sourcemaps.assets` instead of `sourceMapsUploadOptions.sourcemaps.assets` */ assets?: string | Array; @@ -65,6 +75,8 @@ type SourceMapsUploadOptions = { * or the default value for `assets` are uploaded. * * The globbing patterns follow the implementation of the glob package. (https://www.npmjs.com/package/glob) + * + * @deprecated Use `sourcemaps.ignore` instead of `sourceMapsUploadOptions.sourcemaps.ignore` */ ignore?: string | Array; @@ -75,6 +87,8 @@ type SourceMapsUploadOptions = { * @default [] - By default no files are deleted. * * The globbing patterns follow the implementation of the glob package. (https://www.npmjs.com/package/glob) + * + * @deprecated Use `sourcemaps.filesToDeleteAfterUpload` instead of `sourceMapsUploadOptions.sourcemaps.filesToDeleteAfterUpload` */ filesToDeleteAfterUpload?: string | Array; }; @@ -83,6 +97,8 @@ type SourceMapsUploadOptions = { * Options related to managing the Sentry releases for a build. * * Note: Managing releases is optional and not required for uploading source maps. + * + * @deprecated Use `release` instead of `sourceMapsUploadOptions.release` */ release?: { /** @@ -94,6 +110,8 @@ type SourceMapsUploadOptions = { * access to git CLI and for the root directory to be a valid repository). * * If you didn't provide a value and the plugin can't automatically detect one, no release will be created. + * + * @deprecated Use `release.name` instead of `sourceMapsUploadOptions.release.name` */ name?: string; @@ -102,12 +120,16 @@ type SourceMapsUploadOptions = { * sending events. * * Defaults to `true`. + * + * @deprecated Use `release.inject` instead of `sourceMapsUploadOptions.release.inject` */ inject?: boolean; }; /** * The URL of the Sentry instance to upload the source maps to. + * + * @deprecated Use `sentryUrl` instead of `sourceMapsUploadOptions.url` */ url?: string; @@ -123,104 +145,54 @@ type SourceMapsUploadOptions = { * changes can occur at any time within a major SDK version. * * Furthermore, some options are untested with SvelteKit specifically. Use with caution. - */ - unstable_sentryVitePluginOptions?: Partial; -}; - -type BundleSizeOptimizationOptions = { - /** - * If set to `true`, the plugin will attempt to tree-shake (remove) any debugging code within the Sentry SDK. - * Note that the success of this depends on tree shaking being enabled in your build tooling. - * - * Setting this option to `true` will disable features like the SDK's `debug` option. - */ - excludeDebugStatements?: boolean; - - /** - * If set to true, the plugin will try to tree-shake tracing statements out. - * Note that the success of this depends on tree shaking generally being enabled in your build. - * Attention: DO NOT enable this when you're using any performance monitoring-related SDK features (e.g. Sentry.startSpan()). - */ - excludeTracing?: boolean; - - /** - * If set to `true`, the plugin will attempt to tree-shake (remove) code related to the Sentry SDK's Session Replay Shadow DOM recording functionality. - * Note that the success of this depends on tree shaking being enabled in your build tooling. * - * This option is safe to be used when you do not want to capture any Shadow DOM activity via Sentry Session Replay. + * @deprecated Use `unstable_sentryVitePluginOptions` instead of `sourceMapsUploadOptions.unstable_sentryVitePluginOptions` */ - excludeReplayShadowDom?: boolean; - - /** - * If set to `true`, the plugin will attempt to tree-shake (remove) code related to the Sentry SDK's Session Replay `iframe` recording functionality. - * Note that the success of this depends on tree shaking being enabled in your build tooling. - * - * You can safely do this when you do not want to capture any `iframe` activity via Sentry Session Replay. - */ - excludeReplayIframe?: boolean; - - /** - * If set to `true`, the plugin will attempt to tree-shake (remove) code related to the Sentry SDK's Session Replay's Compression Web Worker. - * Note that the success of this depends on tree shaking being enabled in your build tooling. - * - * **Notice:** You should only do use this option if you manually host a compression worker and configure it in your Sentry Session Replay integration config via the `workerUrl` option. - */ - excludeReplayWorker?: boolean; + unstable_sentryVitePluginOptions?: Partial; }; /** Options for the Sentry SvelteKit plugin */ -export type SentrySvelteKitPluginOptions = { - /** - * If this flag is `true`, the Sentry plugins will log some useful debug information. - * @default false. - */ - debug?: boolean; - - /** - * The Sentry plugin will automatically instrument certain parts of your SvelteKit application at build time. - * Set this option to `false` to disable this behavior or what is intrumented by passing an object. - * - * Auto instrumentation includes: - * - Universal `load` functions in `+page.(js|ts)` files - * - Server-only `load` functions in `+page.server.(js|ts)` files - * - * @default true (meaning, the plugin will instrument all of the above) - */ - autoInstrument?: boolean | AutoInstrumentSelection; - - /** - * Specify which SvelteKit adapter you're using. - * By default, the SDK will attempt auto-detect the used adapter at build time and apply the - * correct config for source maps upload or auto-instrumentation. - * - * Currently, the SDK supports the following adapters: - * - node (@sveltejs/adapter-node) - * - auto (@sveltejs/adapter-auto) only Vercel - * - vercel (@sveltejs/adapter-auto) only Serverless functions, no edge runtime - * - * Set this option, if the SDK detects the wrong adapter or you want to use an adapter - * that is not in this list. If you specify 'other', you'll most likely need to configure - * source maps upload yourself. - * - * @default {} the SDK attempts to auto-detect the used adapter at build time - */ - adapter?: SupportedSvelteKitAdapters; +export type SentrySvelteKitPluginOptions = BuildTimeOptionsBase & + UnstableVitePluginOptions> & { + /** + * The Sentry plugin will automatically instrument certain parts of your SvelteKit application at build time. + * Set this option to `false` to disable this behavior or what is intrumented by passing an object. + * + * Auto instrumentation includes: + * - Universal `load` functions in `+page.(js|ts)` files + * - Server-only `load` functions in `+page.server.(js|ts)` files + * + * @default true (meaning, the plugin will instrument all of the above) + */ + autoInstrument?: boolean | AutoInstrumentSelection; - /** - * Options for the Sentry Vite plugin to customize bundle size optimizations. - * - * These options are always read from the `sentryAstro` integration. - * Do not define them in the `sentry.client.config.(js|ts)` or `sentry.server.config.(js|ts)` files. - */ - bundleSizeOptimizations?: BundleSizeOptimizationOptions; + /** + * Specify which SvelteKit adapter you're using. + * By default, the SDK will attempt auto-detect the used adapter at build time and apply the + * correct config for source maps upload or auto-instrumentation. + * + * Currently, the SDK supports the following adapters: + * - node (@sveltejs/adapter-node) + * - auto (@sveltejs/adapter-auto) only Vercel + * - vercel (@sveltejs/adapter-auto) only Serverless functions, no edge runtime + * + * Set this option, if the SDK detects the wrong adapter or you want to use an adapter + * that is not in this list. If you specify 'other', you'll most likely need to configure + * source maps upload yourself. + * + * @default {} the SDK attempts to auto-detect the used adapter at build time + */ + adapter?: SupportedSvelteKitAdapters; - /** - * If this flag is `true`, the Sentry plugins will automatically upload source maps to Sentry. - * @default true`. - */ - autoUploadSourceMaps?: boolean; - /** - * Options related to source maps upload to Sentry - */ - sourceMapsUploadOptions?: SourceMapsUploadOptions; -}; + /** + * If this flag is `true`, the Sentry plugins will automatically upload source maps to Sentry. + * @default true`. + */ + autoUploadSourceMaps?: boolean; + /** + * Options related to source maps upload to Sentry + * + * @deprecated This option was deprecated as it adds unnecessary nesting. Put the options one level higher to the root-level of the Sentry Svelte plugin options. + */ + sourceMapsUploadOptions?: SourceMapsUploadOptions; + }; diff --git a/packages/sveltekit/test/vite/sentrySvelteKitPlugins.test.ts b/packages/sveltekit/test/vite/sentrySvelteKitPlugins.test.ts index d21bcf0d8d04..4aeff4a567bd 100644 --- a/packages/sveltekit/test/vite/sentrySvelteKitPlugins.test.ts +++ b/packages/sveltekit/test/vite/sentrySvelteKitPlugins.test.ts @@ -30,6 +30,7 @@ function getSentrySvelteKitPlugins(options?: Parameters[ authToken: 'token', org: 'org', project: 'project', + // eslint-disable-next-line deprecation/deprecation ...options?.sourceMapsUploadOptions, }, ...options, @@ -350,4 +351,263 @@ describe('generateVitePluginOptions', () => { const result = generateVitePluginOptions(options); expect(result).toEqual(expected); }); + + it.each([ + { + testName: 'org setting precedence', + options: { + autoUploadSourceMaps: true, + org: 'root-org', + sourceMapsUploadOptions: { + org: 'deprecated-org', + unstable_sentryVitePluginOptions: { + org: 'unstable-org', + }, + }, + unstable_sentryVitePluginOptions: { + org: 'new-unstable-org', + }, + }, + expectedOrg: 'new-unstable-org', + }, + { + testName: 'project setting precedence', + options: { + autoUploadSourceMaps: true, + project: 'root-project', + sourceMapsUploadOptions: { + project: 'deprecated-project', + unstable_sentryVitePluginOptions: { + project: 'unstable-project', + }, + }, + unstable_sentryVitePluginOptions: { + project: 'new-unstable-project', + }, + }, + expectedProject: 'new-unstable-project', + }, + { + testName: 'authToken setting precedence', + options: { + autoUploadSourceMaps: true, + authToken: 'root-token', + sourceMapsUploadOptions: { + authToken: 'deprecated-token', + unstable_sentryVitePluginOptions: { + authToken: 'unstable-token', + }, + }, + unstable_sentryVitePluginOptions: { + authToken: 'new-unstable-token', + }, + }, + expectedAuthToken: 'new-unstable-token', + }, + { + testName: 'telemetry setting precedence', + options: { + autoUploadSourceMaps: true, + telemetry: true, + sourceMapsUploadOptions: { + telemetry: false, + unstable_sentryVitePluginOptions: { + telemetry: true, + }, + }, + unstable_sentryVitePluginOptions: { + telemetry: false, + }, + }, + expectedTelemetry: false, + }, + { + testName: 'url setting precedence', + options: { + autoUploadSourceMaps: true, + sentryUrl: 'https://root.sentry.io', + sourceMapsUploadOptions: { + url: 'https://deprecated.sentry.io', + unstable_sentryVitePluginOptions: { + url: 'https://unstable.sentry.io', + }, + }, + unstable_sentryVitePluginOptions: { + url: 'https://new-unstable.sentry.io', + }, + }, + expectedUrl: 'https://new-unstable.sentry.io', + }, + ])( + 'should use correct $testName', + ({ options, expectedOrg, expectedProject, expectedAuthToken, expectedTelemetry, expectedUrl }) => { + const result = generateVitePluginOptions(options as SentrySvelteKitPluginOptions); + + if (expectedOrg !== undefined) { + expect(result?.org).toBe(expectedOrg); + } + if (expectedProject !== undefined) { + expect(result?.project).toBe(expectedProject); + } + if (expectedAuthToken !== undefined) { + expect(result?.authToken).toBe(expectedAuthToken); + } + if (expectedTelemetry !== undefined) { + expect(result?.telemetry).toBe(expectedTelemetry); + } + if (expectedUrl !== undefined) { + expect(result?.url).toBe(expectedUrl); + } + }, + ); + + it('should handle sourcemap settings with correct order of overrides', () => { + const options: SentrySvelteKitPluginOptions = { + autoUploadSourceMaps: true, + sourcemaps: { + assets: ['root/*.js'], + ignore: ['root/ignore/*.js'], + filesToDeleteAfterUpload: ['root/delete/*.js'], + }, + sourceMapsUploadOptions: { + sourcemaps: { + assets: ['deprecated/*.js'], + ignore: ['deprecated/ignore/*.js'], + filesToDeleteAfterUpload: ['deprecated/delete/*.js'], + }, + unstable_sentryVitePluginOptions: { + sourcemaps: { + assets: ['unstable/*.js'], + ignore: ['unstable/ignore/*.js'], + }, + }, + }, + unstable_sentryVitePluginOptions: { + sourcemaps: { + assets: ['new-unstable/*.js'], + filesToDeleteAfterUpload: ['new-unstable/delete/*.js'], + }, + }, + }; + + const result = generateVitePluginOptions(options); + + expect(result?.sourcemaps).toEqual({ + assets: ['new-unstable/*.js'], // new unstable takes precedence + ignore: ['unstable/ignore/*.js'], // from deprecated unstable (not overridden by new unstable) + filesToDeleteAfterUpload: ['new-unstable/delete/*.js'], // new unstable takes precedence + }); + }); + + it('should handle release settings with correct order of overrides', () => { + const newReleaseOptions = { + name: 'root-release', + inject: true, + }; + const newUnstableReleaseOptions = { + name: 'new-unstable-release', + deploy: { + env: 'production', + }, + }; + + const options: SentrySvelteKitPluginOptions = { + autoUploadSourceMaps: true, + release: newReleaseOptions, + sourceMapsUploadOptions: { + release: { + name: 'deprecated-release', + inject: false, + }, + unstable_sentryVitePluginOptions: { + release: { name: 'deprecated-unstable-release', setCommits: { auto: true } }, + }, + }, + unstable_sentryVitePluginOptions: { release: newUnstableReleaseOptions }, + }; + + const result = generateVitePluginOptions(options); + + expect(result?.release).toEqual({ + name: newUnstableReleaseOptions.name, + inject: newReleaseOptions.inject, + setCommits: { + auto: true, // from deprecated unstable (not overridden) + }, + deploy: { + env: 'production', // from new unstable + }, + }); + }); + + it('should handle complex override scenario with all settings', () => { + const options: SentrySvelteKitPluginOptions = { + autoUploadSourceMaps: true, + org: 'root-org', + project: 'root-project', + authToken: 'root-token', + telemetry: true, + sentryUrl: 'https://root.sentry.io', + debug: false, + sourcemaps: { + assets: ['root/*.js'], + }, + release: { + name: 'root-1.0.0', + }, + sourceMapsUploadOptions: { + org: 'deprecated-org', + project: 'deprecated-project', + authToken: 'deprecated-token', + telemetry: false, + url: 'https://deprecated.sentry.io', + sourcemaps: { + assets: ['deprecated/*.js'], + ignore: ['deprecated/ignore/*.js'], + }, + release: { + name: 'deprecated-1.0.0', + inject: false, + }, + unstable_sentryVitePluginOptions: { + org: 'old-unstable-org', + sourcemaps: { + assets: ['old-unstable/*.js'], + }, + }, + }, + unstable_sentryVitePluginOptions: { + org: 'new-unstable-org', + authToken: 'new-unstable-token', + sourcemaps: { + assets: ['new-unstable/*.js'], + filesToDeleteAfterUpload: ['new-unstable/delete/*.js'], + }, + release: { + name: 'new-unstable-1.0.0', + }, + }, + }; + + const result = generateVitePluginOptions(options); + + expect(result).toEqual({ + org: 'new-unstable-org', + project: 'root-project', + authToken: 'new-unstable-token', + telemetry: true, + url: 'https://root.sentry.io', + sourcemaps: { + assets: ['new-unstable/*.js'], + ignore: ['deprecated/ignore/*.js'], + filesToDeleteAfterUpload: ['new-unstable/delete/*.js'], + }, + release: { + name: 'new-unstable-1.0.0', + inject: false, + }, + adapter: undefined, + debug: false, + }); + }); });