Skip to content

Commit 89b801e

Browse files
antonisclaude
andcommitted
feat(spotlight): Disable spotlight in production builds
Spotlight integration is now automatically disabled in production builds (when __DEV__ is false), even if explicitly enabled via the spotlight option. This prevents accidental inclusion of the development-only Spotlight tool in production releases, which would be non-functional (requires local Sidecar server) and could impact performance. Changes: - Add __DEV__ check in getDefaultIntegrations() to block spotlight in production - Update spotlight option documentation to clarify automatic disabling - Add comprehensive tests for spotlight integration behavior - Advanced users can still manually add spotlightIntegration() if needed Related to PR #5667 which makes native spotlight debug-only on Android. Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
1 parent 52912ad commit 89b801e

File tree

3 files changed

+88
-2
lines changed

3 files changed

+88
-2
lines changed

packages/core/src/js/integrations/default.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -132,7 +132,7 @@ export function getDefaultIntegrations(options: ReactNativeClientOptions): Integ
132132

133133
integrations.push(expoContextIntegration());
134134

135-
if (options.spotlight) {
135+
if (options.spotlight && __DEV__) {
136136
const sidecarUrl = typeof options.spotlight === 'string' ? options.spotlight : undefined;
137137
integrations.push(spotlightIntegration({ sidecarUrl }));
138138
}

packages/core/src/js/options.ts

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -184,7 +184,10 @@ export interface BaseReactNativeOptions {
184184
*
185185
* More details: https://spotlightjs.com/
186186
*
187-
* IMPORTANT: Only set this option to `true` while developing, not in production!
187+
* NOTE: Spotlight is automatically disabled in production builds (when __DEV__ is false).
188+
* If you need Spotlight in non-development environments, you must manually add
189+
* spotlightIntegration() to your integrations array. However, this is not recommended
190+
* as Spotlight requires a local Sidecar server and is designed for development only.
188191
*/
189192
spotlight?: boolean | string;
190193

Lines changed: 83 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,83 @@
1+
import type { Integration } from '@sentry/core';
2+
import { getDefaultIntegrations } from '../../src/js/integrations/default';
3+
import { spotlightIntegration } from '../../src/js/integrations/spotlight';
4+
import type { ReactNativeClientOptions } from '../../src/js/options';
5+
import { notWeb } from '../../src/js/utils/environment';
6+
7+
jest.mock('../../src/js/utils/environment', () => {
8+
const actual = jest.requireActual('../../src/js/utils/environment');
9+
return {
10+
...actual,
11+
notWeb: jest.fn(() => true),
12+
};
13+
});
14+
15+
const spotlightIntegrationName = spotlightIntegration().name;
16+
17+
describe('getDefaultIntegrations - spotlight integration', () => {
18+
let originalDev: boolean | undefined;
19+
20+
beforeEach(() => {
21+
(notWeb as jest.Mock).mockReturnValue(true);
22+
originalDev = (global as typeof globalThis & { __DEV__?: boolean }).__DEV__;
23+
});
24+
25+
afterEach(() => {
26+
(global as typeof globalThis & { __DEV__?: boolean }).__DEV__ = originalDev;
27+
});
28+
29+
const createOptions = (overrides: Partial<ReactNativeClientOptions>): ReactNativeClientOptions => {
30+
return {
31+
dsn: 'https://example.com/1',
32+
enableNative: true,
33+
...overrides,
34+
} as ReactNativeClientOptions;
35+
};
36+
37+
const getIntegrationNames = (options: ReactNativeClientOptions): string[] => {
38+
const integrations = getDefaultIntegrations(options);
39+
return integrations.map((integration: Integration) => integration.name);
40+
};
41+
42+
it('does not add spotlight integration when spotlight option is not set', () => {
43+
(global as typeof globalThis & { __DEV__?: boolean }).__DEV__ = true;
44+
const names = getIntegrationNames(createOptions({}));
45+
46+
expect(names).not.toContain(spotlightIntegrationName);
47+
});
48+
49+
it('adds spotlight integration when spotlight is true and __DEV__ is true', () => {
50+
(global as typeof globalThis & { __DEV__?: boolean }).__DEV__ = true;
51+
const names = getIntegrationNames(createOptions({ spotlight: true }));
52+
53+
expect(names).toContain(spotlightIntegrationName);
54+
});
55+
56+
it('adds spotlight integration when spotlight is a URL string and __DEV__ is true', () => {
57+
(global as typeof globalThis & { __DEV__?: boolean }).__DEV__ = true;
58+
const names = getIntegrationNames(createOptions({ spotlight: 'http://custom-url:8969/stream' }));
59+
60+
expect(names).toContain(spotlightIntegrationName);
61+
});
62+
63+
it('does not add spotlight integration when spotlight is true but __DEV__ is false', () => {
64+
(global as typeof globalThis & { __DEV__?: boolean }).__DEV__ = false;
65+
const names = getIntegrationNames(createOptions({ spotlight: true }));
66+
67+
expect(names).not.toContain(spotlightIntegrationName);
68+
});
69+
70+
it('does not add spotlight integration when spotlight is a URL but __DEV__ is false', () => {
71+
(global as typeof globalThis & { __DEV__?: boolean }).__DEV__ = false;
72+
const names = getIntegrationNames(createOptions({ spotlight: 'http://custom-url:8969/stream' }));
73+
74+
expect(names).not.toContain(spotlightIntegrationName);
75+
});
76+
77+
it('does not add spotlight integration when spotlight is false regardless of __DEV__', () => {
78+
(global as typeof globalThis & { __DEV__?: boolean }).__DEV__ = true;
79+
const names = getIntegrationNames(createOptions({ spotlight: false }));
80+
81+
expect(names).not.toContain(spotlightIntegrationName);
82+
});
83+
});

0 commit comments

Comments
 (0)