Skip to content

Commit 19250ad

Browse files
antonisclaude
andauthored
feat(core): Enable autoInjectSentryLabel by default in Metro config (#6141)
* 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 <noreply@anthropic.com> * refactor: Remove unnecessary object spread in withSentryBabelTransformer Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com> * docs: Add changelog entry for autoInjectSentryLabel Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com> --------- Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>
1 parent f094ebf commit 19250ad

4 files changed

Lines changed: 61 additions & 12 deletions

File tree

CHANGELOG.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@
1414
- New `ready` prop. When a screen has multiple async data sources, mount one `<TimeToFullDisplay ready={...} />` per source — TTID/TTFD is recorded only when every instance reports `ready === true`.
1515
- The existing `record` prop is unchanged BUT it is now deprecated in favor of `ready`.
1616
- 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))
17+
- 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))
1718
- Respect Replay Mask boundaries when reading `sentry-label` for touch breadcrumbs ([#6142](https://github.com/getsentry/sentry-react-native/pull/6142))
1819

1920
### Fixes

packages/core/src/js/tools/metroconfig.ts

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -33,6 +33,14 @@ export interface SentryMetroConfigOptions {
3333
| boolean
3434
| {
3535
ignoredComponents?: string[];
36+
/**
37+
* Automatically inject `sentry-label` props from static text content.
38+
* When enabled, the Babel plugin extracts text from children of touchable
39+
* components and injects it as a `sentry-label` prop at build time.
40+
*
41+
* @default true when `annotateReactComponents` is enabled
42+
*/
43+
autoInjectSentryLabel?: boolean;
3644
};
3745
/**
3846
* Adds the Sentry replay package for web.

packages/core/src/js/tools/sentryBabelTransformerUtils.ts

Lines changed: 11 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,12 @@ import * as process from 'process';
44

55
import type { BabelTransformer, BabelTransformerArgs } from './vendor/metro/metroBabelTransformer';
66

7-
export type SentryBabelTransformerOptions = { annotateReactComponents?: { ignoredComponents?: string[] } };
7+
export type SentryBabelTransformerOptions = {
8+
annotateReactComponents?: {
9+
ignoredComponents?: string[];
10+
autoInjectSentryLabel?: boolean;
11+
};
12+
};
813

914
export const SENTRY_DEFAULT_BABEL_TRANSFORMER_PATH = 'SENTRY_DEFAULT_BABEL_TRANSFORMER_PATH';
1015
export const SENTRY_BABEL_TRANSFORMER_OPTIONS = 'SENTRY_BABEL_TRANSFORMER_OPTIONS';
@@ -111,10 +116,10 @@ function addSentryComponentAnnotatePlugin(
111116
}
112117

113118
if (!args.filename.includes('node_modules')) {
114-
if (options) {
115-
args.plugins.push([componentAnnotatePlugin, options]);
116-
} else {
117-
args.plugins.push(componentAnnotatePlugin);
118-
}
119+
const pluginOptions = {
120+
autoInjectSentryLabel: true,
121+
...options,
122+
};
123+
args.plugins.push([componentAnnotatePlugin, pluginOptions]);
119124
}
120125
}

packages/core/test/tools/sentryBabelTransformer.test.ts

Lines changed: 41 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -45,20 +45,25 @@ describe('SentryBabelTransformer', () => {
4545
options: {
4646
projectRoot: 'project/root',
4747
},
48-
plugins: [expect.any(Function), expect.any(Function)],
48+
plugins: [expect.any(Function), [expect.any(Function), expect.objectContaining({ autoInjectSentryLabel: true })]],
4949
});
50-
expect(MockDefaultBabelTransformer.transform.mock.calls[0][0]['plugins'][1].name).toEqual(
50+
expect(MockDefaultBabelTransformer.transform.mock.calls[0][0]['plugins'][1][0].name).toEqual(
5151
'componentNameAnnotatePlugin',
5252
);
5353
});
5454

55-
test('transform adds plugin', () => {
55+
test('transform adds plugin with autoInjectSentryLabel enabled by default', () => {
5656
createSentryBabelTransformer().transform?.(createMinimalMockedTransformOptions());
5757

5858
expect(MockDefaultBabelTransformer.transform).toHaveBeenCalledTimes(1);
5959
expect(MockDefaultBabelTransformer.transform).toHaveBeenCalledWith(
6060
expect.objectContaining({
61-
plugins: expect.arrayContaining([expect.objectContaining({ name: 'componentNameAnnotatePlugin' })]),
61+
plugins: expect.arrayContaining([
62+
[
63+
expect.objectContaining({ name: 'componentNameAnnotatePlugin' }),
64+
expect.objectContaining({ autoInjectSentryLabel: true }),
65+
],
66+
]),
6267
}),
6368
);
6469
});
@@ -79,6 +84,7 @@ describe('SentryBabelTransformer', () => {
7984
[
8085
expect.objectContaining({ name: 'componentNameAnnotatePlugin' }),
8186
expect.objectContaining({
87+
autoInjectSentryLabel: true,
8288
ignoredComponents: ['MyCustomComponent'],
8389
}),
8490
],
@@ -87,15 +93,44 @@ describe('SentryBabelTransformer', () => {
8793
);
8894
});
8995

90-
test('degrades gracefully if options can not be parsed, transform adds plugin without options', () => {
96+
test('transform respects autoInjectSentryLabel: false override', () => {
97+
process.env[SENTRY_BABEL_TRANSFORMER_OPTIONS] = JSON.stringify({
98+
annotateReactComponents: {
99+
autoInjectSentryLabel: false,
100+
},
101+
});
102+
103+
createSentryBabelTransformer().transform?.(createMinimalMockedTransformOptions());
104+
105+
expect(MockDefaultBabelTransformer.transform).toHaveBeenCalledTimes(1);
106+
expect(MockDefaultBabelTransformer.transform).toHaveBeenCalledWith(
107+
expect.objectContaining({
108+
plugins: expect.arrayContaining([
109+
[
110+
expect.objectContaining({ name: 'componentNameAnnotatePlugin' }),
111+
expect.objectContaining({
112+
autoInjectSentryLabel: false,
113+
}),
114+
],
115+
]),
116+
}),
117+
);
118+
});
119+
120+
test('degrades gracefully if options can not be parsed, transform adds plugin with defaults', () => {
91121
process.env[SENTRY_BABEL_TRANSFORMER_OPTIONS] = 'invalid json';
92122

93123
createSentryBabelTransformer().transform?.(createMinimalMockedTransformOptions());
94124

95125
expect(MockDefaultBabelTransformer.transform).toHaveBeenCalledTimes(1);
96126
expect(MockDefaultBabelTransformer.transform).toHaveBeenCalledWith(
97127
expect.objectContaining({
98-
plugins: expect.arrayContaining([expect.objectContaining({ name: 'componentNameAnnotatePlugin' })]),
128+
plugins: expect.arrayContaining([
129+
[
130+
expect.objectContaining({ name: 'componentNameAnnotatePlugin' }),
131+
expect.objectContaining({ autoInjectSentryLabel: true }),
132+
],
133+
]),
99134
}),
100135
);
101136
});

0 commit comments

Comments
 (0)