From 958f8d8aebab1515c9aacf69fe32a7cf59b07c5f Mon Sep 17 00:00:00 2001 From: Antonis Lilis Date: Tue, 12 May 2026 15:27:09 +0200 Subject: [PATCH 1/3] feat(core): Enable autoInjectSentryLabel by default in Metro config Pass `autoInjectSentryLabel: true` to the babel-plugin-component-annotate plugin by default when `annotateReactComponents` is enabled. This enables automatic injection of `sentry-label` props from static text content at build time, improving touch breadcrumb and user interaction span labeling. Users can opt out by setting `autoInjectSentryLabel: false` in the `annotateReactComponents` config option. Closes #6109 Co-Authored-By: Claude Opus 4.6 --- packages/core/src/js/tools/metroconfig.ts | 12 ++++- .../js/tools/sentryBabelTransformerUtils.ts | 17 ++++--- .../test/tools/sentryBabelTransformer.test.ts | 47 ++++++++++++++++--- 3 files changed, 63 insertions(+), 13 deletions(-) diff --git a/packages/core/src/js/tools/metroconfig.ts b/packages/core/src/js/tools/metroconfig.ts index ac5cbb4606..c7d17a5ab3 100644 --- a/packages/core/src/js/tools/metroconfig.ts +++ b/packages/core/src/js/tools/metroconfig.ts @@ -33,6 +33,14 @@ export interface SentryMetroConfigOptions { | boolean | { ignoredComponents?: string[]; + /** + * Automatically inject `sentry-label` props from static text content. + * When enabled, the Babel plugin extracts text from children of touchable + * components and injects it as a `sentry-label` prop at build time. + * + * @default true when `annotateReactComponents` is enabled + */ + autoInjectSentryLabel?: boolean; }; /** * Adds the Sentry replay package for web. @@ -205,7 +213,9 @@ export function withSentryBabelTransformer( if (typeof annotateReactComponents === 'object') { setSentryBabelTransformerOptions({ - annotateReactComponents, + annotateReactComponents: { + ...annotateReactComponents, + }, }); } diff --git a/packages/core/src/js/tools/sentryBabelTransformerUtils.ts b/packages/core/src/js/tools/sentryBabelTransformerUtils.ts index e848e0c91b..0626a97185 100644 --- a/packages/core/src/js/tools/sentryBabelTransformerUtils.ts +++ b/packages/core/src/js/tools/sentryBabelTransformerUtils.ts @@ -4,7 +4,12 @@ import * as process from 'process'; import type { BabelTransformer, BabelTransformerArgs } from './vendor/metro/metroBabelTransformer'; -export type SentryBabelTransformerOptions = { annotateReactComponents?: { ignoredComponents?: string[] } }; +export type SentryBabelTransformerOptions = { + annotateReactComponents?: { + ignoredComponents?: string[]; + autoInjectSentryLabel?: boolean; + }; +}; export const SENTRY_DEFAULT_BABEL_TRANSFORMER_PATH = 'SENTRY_DEFAULT_BABEL_TRANSFORMER_PATH'; export const SENTRY_BABEL_TRANSFORMER_OPTIONS = 'SENTRY_BABEL_TRANSFORMER_OPTIONS'; @@ -111,10 +116,10 @@ function addSentryComponentAnnotatePlugin( } if (!args.filename.includes('node_modules')) { - if (options) { - args.plugins.push([componentAnnotatePlugin, options]); - } else { - args.plugins.push(componentAnnotatePlugin); - } + const pluginOptions = { + autoInjectSentryLabel: true, + ...options, + }; + args.plugins.push([componentAnnotatePlugin, pluginOptions]); } } diff --git a/packages/core/test/tools/sentryBabelTransformer.test.ts b/packages/core/test/tools/sentryBabelTransformer.test.ts index 4dc4195db5..12b8bf7631 100644 --- a/packages/core/test/tools/sentryBabelTransformer.test.ts +++ b/packages/core/test/tools/sentryBabelTransformer.test.ts @@ -45,20 +45,25 @@ describe('SentryBabelTransformer', () => { options: { projectRoot: 'project/root', }, - plugins: [expect.any(Function), expect.any(Function)], + plugins: [expect.any(Function), [expect.any(Function), expect.objectContaining({ autoInjectSentryLabel: true })]], }); - expect(MockDefaultBabelTransformer.transform.mock.calls[0][0]['plugins'][1].name).toEqual( + expect(MockDefaultBabelTransformer.transform.mock.calls[0][0]['plugins'][1][0].name).toEqual( 'componentNameAnnotatePlugin', ); }); - test('transform adds plugin', () => { + test('transform adds plugin with autoInjectSentryLabel enabled by default', () => { createSentryBabelTransformer().transform?.(createMinimalMockedTransformOptions()); expect(MockDefaultBabelTransformer.transform).toHaveBeenCalledTimes(1); expect(MockDefaultBabelTransformer.transform).toHaveBeenCalledWith( expect.objectContaining({ - plugins: expect.arrayContaining([expect.objectContaining({ name: 'componentNameAnnotatePlugin' })]), + plugins: expect.arrayContaining([ + [ + expect.objectContaining({ name: 'componentNameAnnotatePlugin' }), + expect.objectContaining({ autoInjectSentryLabel: true }), + ], + ]), }), ); }); @@ -79,6 +84,7 @@ describe('SentryBabelTransformer', () => { [ expect.objectContaining({ name: 'componentNameAnnotatePlugin' }), expect.objectContaining({ + autoInjectSentryLabel: true, ignoredComponents: ['MyCustomComponent'], }), ], @@ -87,7 +93,31 @@ describe('SentryBabelTransformer', () => { ); }); - test('degrades gracefully if options can not be parsed, transform adds plugin without options', () => { + test('transform respects autoInjectSentryLabel: false override', () => { + process.env[SENTRY_BABEL_TRANSFORMER_OPTIONS] = JSON.stringify({ + annotateReactComponents: { + autoInjectSentryLabel: false, + }, + }); + + createSentryBabelTransformer().transform?.(createMinimalMockedTransformOptions()); + + expect(MockDefaultBabelTransformer.transform).toHaveBeenCalledTimes(1); + expect(MockDefaultBabelTransformer.transform).toHaveBeenCalledWith( + expect.objectContaining({ + plugins: expect.arrayContaining([ + [ + expect.objectContaining({ name: 'componentNameAnnotatePlugin' }), + expect.objectContaining({ + autoInjectSentryLabel: false, + }), + ], + ]), + }), + ); + }); + + test('degrades gracefully if options can not be parsed, transform adds plugin with defaults', () => { process.env[SENTRY_BABEL_TRANSFORMER_OPTIONS] = 'invalid json'; createSentryBabelTransformer().transform?.(createMinimalMockedTransformOptions()); @@ -95,7 +125,12 @@ describe('SentryBabelTransformer', () => { expect(MockDefaultBabelTransformer.transform).toHaveBeenCalledTimes(1); expect(MockDefaultBabelTransformer.transform).toHaveBeenCalledWith( expect.objectContaining({ - plugins: expect.arrayContaining([expect.objectContaining({ name: 'componentNameAnnotatePlugin' })]), + plugins: expect.arrayContaining([ + [ + expect.objectContaining({ name: 'componentNameAnnotatePlugin' }), + expect.objectContaining({ autoInjectSentryLabel: true }), + ], + ]), }), ); }); From 476a3f9fcb6df27e6ab4b1b782bc852d95c6f457 Mon Sep 17 00:00:00 2001 From: Antonis Lilis Date: Tue, 12 May 2026 15:31:48 +0200 Subject: [PATCH 2/3] refactor: Remove unnecessary object spread in withSentryBabelTransformer Co-Authored-By: Claude Opus 4.6 --- packages/core/src/js/tools/metroconfig.ts | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/packages/core/src/js/tools/metroconfig.ts b/packages/core/src/js/tools/metroconfig.ts index c7d17a5ab3..f5057b5a77 100644 --- a/packages/core/src/js/tools/metroconfig.ts +++ b/packages/core/src/js/tools/metroconfig.ts @@ -213,9 +213,7 @@ export function withSentryBabelTransformer( if (typeof annotateReactComponents === 'object') { setSentryBabelTransformerOptions({ - annotateReactComponents: { - ...annotateReactComponents, - }, + annotateReactComponents, }); } From c48108281db96807392389ee80c86fcebb2ad04b Mon Sep 17 00:00:00 2001 From: Antonis Lilis Date: Tue, 12 May 2026 15:37:10 +0200 Subject: [PATCH 3/3] docs: Add changelog entry for autoInjectSentryLabel Co-Authored-By: Claude Opus 4.6 --- CHANGELOG.md | 1 + 1 file changed, 1 insertion(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 918609f0cd..c7fb25ed0c 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -11,6 +11,7 @@ ### Features - Extract text content from children of touched components as a label fallback for touch breadcrumbs ([#6106](https://github.com/getsentry/sentry-react-native/pull/6106)) +- Auto-inject `sentry-label` from static text content at build time when `annotateReactComponents` is enabled ([#6141](https://github.com/getsentry/sentry-react-native/pull/6141)) ### Dependencies