diff --git a/packages/react-router/src/vite/makeCustomSentryVitePlugins.ts b/packages/react-router/src/vite/makeCustomSentryVitePlugins.ts index 41580f4a7c7f..80e540c9760a 100644 --- a/packages/react-router/src/vite/makeCustomSentryVitePlugins.ts +++ b/packages/react-router/src/vite/makeCustomSentryVitePlugins.ts @@ -14,6 +14,7 @@ export async function makeCustomSentryVitePlugins(options: SentryReactRouterBuil org, project, telemetry, + reactComponentAnnotation, release, } = options; @@ -30,6 +31,11 @@ export async function makeCustomSentryVitePlugins(options: SentryReactRouterBuil }, ...unstable_sentryVitePluginOptions?._metaOptions, }, + reactComponentAnnotation: { + enabled: reactComponentAnnotation?.enabled ?? undefined, + ignoredComponents: reactComponentAnnotation?.ignoredComponents ?? undefined, + ...unstable_sentryVitePluginOptions?.reactComponentAnnotation, + }, release: { ...unstable_sentryVitePluginOptions?.release, ...release, @@ -45,7 +51,13 @@ export async function makeCustomSentryVitePlugins(options: SentryReactRouterBuil // only use a subset of the plugins as all upload and file deletion tasks will be handled in the buildEnd hook return [ ...sentryVitePlugins.filter(plugin => { - return ['sentry-telemetry-plugin', 'sentry-vite-release-injection-plugin'].includes(plugin.name); + return [ + 'sentry-telemetry-plugin', + 'sentry-vite-release-injection-plugin', + ...(reactComponentAnnotation?.enabled || unstable_sentryVitePluginOptions?.reactComponentAnnotation?.enabled + ? ['sentry-vite-component-name-annotate-plugin'] + : []), + ].includes(plugin.name); }), ]; } diff --git a/packages/react-router/src/vite/types.ts b/packages/react-router/src/vite/types.ts index de8175b0141c..fb488d2ca8bc 100644 --- a/packages/react-router/src/vite/types.ts +++ b/packages/react-router/src/vite/types.ts @@ -125,6 +125,25 @@ export type SentryReactRouterBuildOptions = { */ debug?: 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 + */ + 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[]; + }; + /** * Options for the Sentry Vite plugin to customize the source maps upload process. * diff --git a/packages/react-router/test/vite/makeCustomSentryVitePlugins.test.ts b/packages/react-router/test/vite/makeCustomSentryVitePlugins.test.ts index 04576076a561..b4db6d85d028 100644 --- a/packages/react-router/test/vite/makeCustomSentryVitePlugins.test.ts +++ b/packages/react-router/test/vite/makeCustomSentryVitePlugins.test.ts @@ -8,6 +8,7 @@ vi.mock('@sentry/vite-plugin', () => ({ .mockReturnValue([ { name: 'sentry-telemetry-plugin' }, { name: 'sentry-vite-release-injection-plugin' }, + { name: 'sentry-vite-component-name-annotate-plugin' }, { name: 'other-plugin' }, ]), })); @@ -60,4 +61,24 @@ describe('makeCustomSentryVitePlugins', () => { expect(plugins?.[0]?.name).toBe('sentry-telemetry-plugin'); expect(plugins?.[1]?.name).toBe('sentry-vite-release-injection-plugin'); }); + + it('should include component annotation plugin when reactComponentAnnotation.enabled is true', async () => { + const plugins = await makeCustomSentryVitePlugins({ reactComponentAnnotation: { enabled: true } }); + + expect(plugins).toHaveLength(3); + expect(plugins?.[0]?.name).toBe('sentry-telemetry-plugin'); + expect(plugins?.[1]?.name).toBe('sentry-vite-release-injection-plugin'); + expect(plugins?.[2]?.name).toBe('sentry-vite-component-name-annotate-plugin'); + }); + + it('should include component annotation plugin when unstable_sentryVitePluginOptions.reactComponentAnnotation.enabled is true', async () => { + const plugins = await makeCustomSentryVitePlugins({ + unstable_sentryVitePluginOptions: { reactComponentAnnotation: { enabled: true } }, + }); + + expect(plugins).toHaveLength(3); + expect(plugins?.[0]?.name).toBe('sentry-telemetry-plugin'); + expect(plugins?.[1]?.name).toBe('sentry-vite-release-injection-plugin'); + expect(plugins?.[2]?.name).toBe('sentry-vite-component-name-annotate-plugin'); + }); });