Skip to content

Conversation

@BYK
Copy link
Member

@BYK BYK commented Nov 13, 2025

Implements full Spotlight spec with support for multiple framework-specific
environment variable prefixes. Adds defensive environment variable access
for both process.env and import.meta.env to support various bundlers.

Supported environment variables (in priority order):

  • PUBLIC_SENTRY_SPOTLIGHT (SvelteKit, Astro, Qwik)
  • NEXT_PUBLIC_SENTRY_SPOTLIGHT (Next.js)
  • VITE_SENTRY_SPOTLIGHT (Vite)
  • NUXT_PUBLIC_SENTRY_SPOTLIGHT (Nuxt)
  • REACT_APP_SENTRY_SPOTLIGHT (Create React App)
  • VUE_APP_SENTRY_SPOTLIGHT (Vue CLI)
  • GATSBY_SENTRY_SPOTLIGHT (Gatsby)
  • SENTRY_SPOTLIGHT (base/official)

SENTRY_SPOTLIGHT is last as in environments like Docker Compose, we actually make the front-end env variable different than the base SENTRY_SPOTLIGHT one -- the backends need to reach docker.host.internal whereas front-ends always need localhost as we assume the browser runs on the same host with Spotlight.

Refactors envToBool utility from node-core to core package for shared usage.
Adds resolveSpotlightOptions utility to ensure consistent precedence rules
across Browser and Node SDKs.

Includes comprehensive test coverage for all new utilities and integration
tests for environment variable precedence behavior.

Closes #18404

@github-actions
Copy link
Contributor

github-actions bot commented Nov 13, 2025

size-limit report 📦

Path Size % Change Change
@sentry/browser 24.81 kB - -
@sentry/browser - with treeshaking flags 23.3 kB - -
@sentry/browser (incl. Tracing) 41.55 kB - -
@sentry/browser (incl. Tracing, Profiling) 46.14 kB - -
@sentry/browser (incl. Tracing, Replay) 79.97 kB - -
@sentry/browser (incl. Tracing, Replay) - with treeshaking flags 69.7 kB - -
@sentry/browser (incl. Tracing, Replay with Canvas) 84.64 kB - -
@sentry/browser (incl. Tracing, Replay, Feedback) 96.89 kB - -
@sentry/browser (incl. Feedback) 41.52 kB - -
@sentry/browser (incl. sendFeedback) 29.49 kB - -
@sentry/browser (incl. FeedbackAsync) 34.48 kB - -
@sentry/react 26.52 kB - -
@sentry/react (incl. Tracing) 43.75 kB - -
@sentry/vue 29.27 kB - -
@sentry/vue (incl. Tracing) 43.36 kB - -
@sentry/svelte 24.82 kB - -
CDN Bundle 27.28 kB +0.17% +45 B 🔺
CDN Bundle (incl. Tracing) 42.28 kB +0.12% +50 B 🔺
CDN Bundle (incl. Tracing, Replay) 78.81 kB +0.07% +53 B 🔺
CDN Bundle (incl. Tracing, Replay, Feedback) 84.25 kB +0.05% +41 B 🔺
CDN Bundle - uncompressed 80.12 kB +0.11% +83 B 🔺
CDN Bundle (incl. Tracing) - uncompressed 125.47 kB +0.07% +83 B 🔺
CDN Bundle (incl. Tracing, Replay) - uncompressed 241.5 kB +0.04% +83 B 🔺
CDN Bundle (incl. Tracing, Replay, Feedback) - uncompressed 254.27 kB +0.04% +83 B 🔺
@sentry/nextjs (client) 46.58 kB +1.32% +606 B 🔺
@sentry/sveltekit (client) 41.92 kB - -
@sentry/node-core 51.52 kB +0.05% +22 B 🔺
@sentry/node 159.95 kB +0.02% +17 B 🔺
@sentry/node - without tracing 92.92 kB +0.01% +9 B 🔺
@sentry/aws-serverless 108.46 kB +0.03% +27 B 🔺

View base workflow run

@github-actions
Copy link
Contributor

github-actions bot commented Nov 13, 2025

node-overhead report 🧳

Note: This is a synthetic benchmark with a minimal express app and does not necessarily reflect the real-world performance impact in an application.

Scenario Requests/s % of Baseline Prev. Requests/s Change %
GET Baseline 9,551 - 9,410 +1%
GET With Sentry 1,812 19% 1,685 +8%
GET With Sentry (error only) 6,303 66% 6,040 +4%
POST Baseline 1,213 - 1,195 +2%
POST With Sentry 600 49% 581 +3%
POST With Sentry (error only) 1,078 89% 1,052 +2%
MYSQL Baseline 3,410 - 3,284 +4%
MYSQL With Sentry 507 15% 464 +9%
MYSQL With Sentry (error only) 2,757 81% 2,679 +3%

View base workflow run

…ration

- Add support for multiple framework/bundler-specific environment variables with proper precedence
  - SENTRY_SPOTLIGHT (highest priority - base name, supported natively by many bundlers)
  - PUBLIC_SENTRY_SPOTLIGHT (SvelteKit, Astro, Qwik)
  - NEXT_PUBLIC_SENTRY_SPOTLIGHT (Next.js)
  - VITE_SENTRY_SPOTLIGHT (Vite)
  - NUXT_PUBLIC_SENTRY_SPOTLIGHT (Nuxt.js)
  - REACT_APP_SENTRY_SPOTLIGHT (Create React App)
  - VUE_APP_SENTRY_SPOTLIGHT (Vue CLI)
  - GATSBY_SENTRY_SPOTLIGHT (Gatsby)
- Add defensive environment variable access via process.env (transformed by all major bundlers)
- Move envToBool utility from node-core to core for shared usage
- Add resolveSpotlightOptions utility for consistent precedence rules
- Update node-core and aws-serverless to use shared utilities
- Add comprehensive tests for all new utilities and SDK integration

Note: import.meta.env is intentionally not checked because bundlers only replace static
references (e.g., import.meta.env.VITE_VAR) at build time, not dynamic access. All major
bundlers transform process.env references, making it the universal solution.
@BYK BYK force-pushed the feat/spotlight-environment-variable-support branch from 92ffd33 to 6cb5513 Compare November 13, 2025 22:51
@BYK BYK force-pushed the feat/spotlight-environment-variable-support branch from 4f6dcd0 to fda3d61 Compare November 14, 2025 11:31
@BYK BYK marked this pull request as ready for review November 14, 2025 11:32
@BYK BYK requested review from Lms24, andreiborza and timfish November 14, 2025 11:32
Before submitting a pull request, please take a look at our

[Contributing](https://github.com/getsentry/sentry-javascript/blob/master/CONTRIBUTING.md)
guidelines and verify:

- [x] If you've added code that should be tested, please add tests.
- [x] Ensure your code lints and the test suite passes (`yarn lint`) &
(`yarn test`).

Fixes a test failure where `getSpotlightConfig` was returning empty or
whitespace-only strings for `SENTRY_SPOTLIGHT` environment variables,
instead of `undefined`. This change explicitly filters out such values,
aligning the function's behavior with test expectations and preventing
invalid Spotlight configurations.

---
<a
href="https://cursor.com/background-agent?bcId=bc-88bd0365-3796-47b2-bb84-29c93d0430e8"><picture><source
media="(prefers-color-scheme: dark)"
srcset="https://cursor.com/open-in-cursor-dark.svg"><source
media="(prefers-color-scheme: light)"
srcset="https://cursor.com/open-in-cursor-light.svg"><img alt="Open in
Cursor"
src="https://cursor.com/open-in-cursor.svg"></picture></a>&nbsp;<a
href="https://cursor.com/agents?id=bc-88bd0365-3796-47b2-bb84-29c93d0430e8"><picture><source
media="(prefers-color-scheme: dark)"
srcset="https://cursor.com/open-in-web-dark.svg"><source
media="(prefers-color-scheme: light)"
srcset="https://cursor.com/open-in-web-light.svg"><img alt="Open in Web"
src="https://cursor.com/open-in-web.svg"></picture></a>

---------

Co-authored-by: Cursor Agent <[email protected]>
@BYK BYK requested a review from a team as a code owner November 14, 2025 16:59
Copy link
Member

@Lms24 Lms24 left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

First pass review. I still want to figure out why size bot reports a slight increase for the CDN bundles.

Comment on lines 3 to 9
* Checks process.env which is transformed by most bundlers (Webpack, Vite, Rollup, Rspack, Parcel, etc.)
* at build time.
*
* Note: We don't check import.meta.env because:
* 1. Bundlers only replace static references like `import.meta.env.VITE_VAR`, not dynamic access
* 2. Dynamic access causes syntax errors in unsupported environments
* 3. Most bundlers transform process.env references anyway
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

m: My impression while doing some research for #18050 (comment) was what very few bundlers inject process.env into browser bundles. For example, this code will not work in Angular.
Vite instructs checking on import.meta.env, so not sure if it double-writes to process.env (my gut feeling is no).

Did you test this in the respective frameworks? Maybe I'm also misinformed and this works just fine 😅 Ideally we can add an e2e test for at least NextJS and some Vite-based framework app to be sure.

Comment on lines 62 to 64

// No Spotlight configuration found in environment
return undefined;
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

l: neat size trick: You can let the function return void and simply omit the return undefined here. Saves a couple of bytes and JS returns undefined anyway. 😅 (but feel free to ignore since this is shaken out for prod builds anyway)

Before submitting a pull request, please take a look at our

[Contributing](https://github.com/getsentry/sentry-javascript/blob/master/CONTRIBUTING.md)
guidelines and verify:

- [x] If you've added code that should be tested, please add tests.
- [x] Ensure your code lints and the test suite passes (`yarn lint`) &
(`yarn test`).

---

This PR addresses critical feedback regarding environment variable
detection, particularly for Vite-based frameworks.

**Key Changes:**

* **`packages/browser/src/utils/env.ts`**: The `getEnvValue` function
now checks both `process.env` (for Webpack, Next.js, CRA) and
`import.meta.env` (for Vite, Astro, SvelteKit). This ensures that
environment variables (like those for Spotlight) are correctly detected
across a wider range of bundlers and frameworks, fixing a significant
compatibility issue.
* **`packages/browser/test/utils/env.test.ts`**: Updated unit tests to
focus on `process.env` scenarios. Added a note explaining that
`import.meta.env` cannot be unit tested due to its read-only,
compile-time nature and is covered by e2e tests.
* **`packages/browser/src/utils/spotlightConfig.ts`**: Added a comment
to clarify the explicit `return undefined` for readability, noting its
optimization in production builds.

---
<a
href="https://cursor.com/background-agent?bcId=bc-d6001dc9-59fc-42eb-8354-a573e3ae71a9"><picture><source
media="(prefers-color-scheme: dark)"
srcset="https://cursor.com/open-in-cursor-dark.svg"><source
media="(prefers-color-scheme: light)"
srcset="https://cursor.com/open-in-cursor-light.svg"><img alt="Open in
Cursor"
src="https://cursor.com/open-in-cursor.svg"></picture></a>&nbsp;<a
href="https://cursor.com/agents?id=bc-d6001dc9-59fc-42eb-8354-a573e3ae71a9"><picture><source
media="(prefers-color-scheme: dark)"
srcset="https://cursor.com/open-in-web-dark.svg"><source
media="(prefers-color-scheme: light)"
srcset="https://cursor.com/open-in-web-light.svg"><img alt="Open in Web"
src="https://cursor.com/open-in-web.svg"></picture></a>

Co-authored-by: Cursor Agent <[email protected]>
Copy link
Collaborator

@timfish timfish left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Looks good but needs some e2e tests of some kind otherwise we could inadvertently break this in the future.

It should be quite easy to test Vite by adding some additional tests to dev-packages/bundler-tests with the specific variables set and then check they make it into the bundle.

Then as @Lms24 says, a Nextjs test would probably be a good idea too!

@BYK BYK requested a review from a team as a code owner November 20, 2025 14:08
Copy link

@cursor cursor bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Bug: Breaking change: `envToBool` export removed from `@sentry/node-core` (Bugbot Rules)

The envToBool function was previously exported from @sentry/node-core but has been removed in this change (now exported from @sentry/core instead). This is a breaking change for any external consumers who were importing envToBool directly from @sentry/node-core. The function is still available from @sentry/core, but existing code using import { envToBool } from '@sentry/node-core' will break. Flagging this per the review rules about "Removal of publicly exported functions, classes, or types."

packages/node-core/src/index.ts#L44-L45

export { ensureIsWrapped } from './utils/ensureIsWrapped';
export { createMissingInstrumentationContext } from './utils/createMissingInstrumentationContext';

Fix in Cursor Fix in Web


],
"main": "build/npm/cjs/prod/index.js",
"module": "build/npm/esm/prod/index.js",
"types": "build/npm/types/index.d.ts",
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Bug: Missing module field may break older bundler ESM resolution

The module field was removed from package.json. While the exports field provides the same functionality for modern bundlers, older bundlers (like Webpack 4) that don't support conditional exports rely on the module field to resolve ESM entry points. Without it, these bundlers will fall back to main (CJS), which may break tree-shaking. Flagged per user rules about bundle size concerns in browser packages.

Fix in Cursor Fix in Web

BYK added 5 commits December 11, 2025 19:53
…blement

The Spotlight auto-enablement code was wrapped in rollup-include-development-only,
which stripped it from production builds. But users install production builds of
the SDK from npm and still expect auto-enablement to work during their app's
development (when they set NEXT_PUBLIC_SENTRY_SPOTLIGHT=true, etc.).

The env vars won't be set in production deployments anyway, and users can
explicitly disable Spotlight with `spotlight: false` if needed.
The browser SDK's Spotlight auto-detection is wrapped in rollup-include-development-only,
which strips it from production builds. Since users install production builds from npm,
the Next.js SDK needs to handle Spotlight auto-enablement explicitly.

This moves the Spotlight env var detection from the browser SDK to the Next.js client SDK,
which reads the injected NEXT_PUBLIC_SENTRY_SPOTLIGHT value from globalThis and adds the
Spotlight integration when appropriate.

This also avoids the issue where CI sets VITE_SENTRY_SPOTLIGHT=true globally, which was
accidentally enabling Spotlight in all test apps and potentially causing timing issues.
The nextjs-15-spotlight test expects NEXT_PUBLIC_SENTRY_SPOTLIGHT to be set,
but CI only set VITE_SENTRY_SPOTLIGHT. Adding the Next.js variant so the
Spotlight auto-enablement test works in CI.

Also fix import to use @sentry/browser directly for spotlightBrowserIntegration
to avoid build order issues.
The makeStripEsmPlugin and makeStripCjsPlugin additions to rollup-utils
were causing the build output to be incorrectly structured (files going
to browser/nextjs subdirectories instead of root).

Also fix import to use @sentry/react instead of @sentry/browser directly.
The import.meta syntax causes 'Cannot use import.meta outside a module'
errors in CommonJS builds. Since the makeStripEsmPlugin that was supposed
to strip this code doesn't exist, removing the import.meta.env check entirely.

The SDK will still auto-enable Spotlight via:
- process.env: Works with Webpack, Next.js, CRA, Vite (with define config)
- globalThis: Works with Turbopack and other bundlers that inject at runtime

Also removed the related Vite spotlight-env tests since they were testing
the now-removed import.meta.env functionality.
Previously, the Spotlight integration logic was gated behind checking
if the NEXT_PUBLIC_SENTRY_SPOTLIGHT env var was set. This meant that
if a user set `spotlight: true` in Sentry.init() without the env var,
their explicit configuration was silently ignored.

Now the code always checks resolveSpotlightOptions which properly
handles both the explicit option and the env var with correct precedence.
…lementation

The tests were expecting import.meta.env code that was intentionally removed
from the source to avoid CJS syntax errors. Updated tests to verify:
- Neither CJS nor ESM builds contain import.meta.env in code
- Both builds use process.env for env var access
- Both builds use globalThis for bundler-injected values
BYK added 2 commits December 11, 2025 23:24
Spotlight env vars (VITE_SENTRY_SPOTLIGHT, NEXT_PUBLIC_SENTRY_SPOTLIGHT)
should only be set for tests that specifically test Spotlight functionality.
Setting them globally was causing other tests to potentially behave
differently (e.g., adding Spotlight integration, making extra network
requests).

The nextjs-15-spotlight test already has NEXT_PUBLIC_SENTRY_SPOTLIGHT
set in its next.config.js, so it will continue to work.
…ad of next.config.js

This is more realistic - testing the actual env var flow that users would use.
The env var is now conditionally set in CI only for test apps that contain
'spotlight' in their name.
PUBLIC_E2E_TEST_DSN: dsn,
REACT_APP_E2E_TEST_DSN: dsn,
VITE_E2E_TEST_DSN: dsn,
VITE_SENTRY_SPOTLIGHT: 'true',
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Bug: Spotlight enabled globally for all E2E tests

The run.ts file globally sets VITE_SENTRY_SPOTLIGHT: 'true' for ALL E2E tests when run locally, and nextjs-15/next.config.js permanently enables NEXT_PUBLIC_SENTRY_SPOTLIGHT: 'true'. This contradicts the CI workflow comments which explicitly state Spotlight env vars should only be set for spotlight-specific tests. All Vite-based and nextjs-15 tests will now attempt to connect to http://localhost:8969/stream, causing failed network requests, console error spam, and potentially slower/flakier tests. The existing nextjs-15 test suite (AI tests, i18n tests, ISR tests, etc.) will be affected even though they don't test Spotlight functionality.

Additional Locations (1)

Fix in Cursor Fix in Web

BYK added 2 commits December 12, 2025 00:19
The webServer config was setting `env: { PORT: ... }` which REPLACES
the parent environment instead of merging with it. This meant env vars
like NEXT_PUBLIC_SENTRY_SPOTLIGHT weren't being passed to the Next.js
dev server, causing the Spotlight auto-enablement test to fail.

By spreading `...process.env`, we now inherit all environment variables
from the CI runner, allowing the valueInjectionLoader to work correctly.
PUBLIC_E2E_TEST_DSN: dsn,
REACT_APP_E2E_TEST_DSN: dsn,
VITE_E2E_TEST_DSN: dsn,
VITE_SENTRY_SPOTLIGHT: 'true',
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Bug: Vite Spotlight env var injection ineffective without define config

The VITE_SENTRY_SPOTLIGHT: 'true' setting here won't work for Vite test applications. Vite only exposes VITE_* environment variables through import.meta.env, not process.env. The browser SDK's getEnvValue() function only checks process.env and globalThis, so this value will never be detected. For this to work in Vite apps, the Vite config would need a define option to inject the value into process.env, which isn't configured. This makes the injection effectively dead code for Vite-based E2E tests.

Fix in Cursor Fix in Web

The valueInjectionLoader may not run in all scenarios (e.g., Next.js dev
mode with Turbopack). Next.js already replaces process.env.NEXT_PUBLIC_*
at build time, so we can use this as a fallback when globalThis is not set.

Also removes debug logging that was added for CI debugging and fixes
prettier formatting issues.
PUBLIC_E2E_TEST_DSN: dsn,
REACT_APP_E2E_TEST_DSN: dsn,
VITE_E2E_TEST_DSN: dsn,
VITE_SENTRY_SPOTLIGHT: 'true',
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Bug: E2E test runner sets Spotlight env var globally

The local E2E test runner unconditionally sets VITE_SENTRY_SPOTLIGHT: 'true' for all test applications. This contradicts the CI workflow (.github/workflows/build.yml lines 931-932 and 994-996) which explicitly states Spotlight env vars should NOT be set globally and only sets NEXT_PUBLIC_SENTRY_SPOTLIGHT for tests containing "spotlight" in the name. This inconsistency causes different behavior between local and CI test runs, potentially enabling Spotlight in tests that don't expect it.

Fix in Cursor Fix in Web

…light auto-enablement

The valueInjectionLoader now injects both NEXT_PUBLIC_SENTRY_SPOTLIGHT and
_sentrySpotlight into globalThis. This provides a reliable fallback chain:

1. globalThis.NEXT_PUBLIC_SENTRY_SPOTLIGHT - primary (valueInjectionLoader)
2. process.env._sentrySpotlight - fallback (Next.js env config replacement)
3. globalThis._sentrySpotlight - final fallback (valueInjectionLoader)

This ensures Spotlight auto-enablement works in Next.js 15 Turbopack dev mode
where Next.js doesn't reliably replace process.env values in node_modules code.

Also adds _sentrySpotlight to the env config buildTimeVariables for build-time
replacement in production builds.
In Next.js 15 Turbopack dev mode, custom loaders aren't applied to
instrumentation files, and process.env replacements don't work in
node_modules code. This means the auto-detection mechanism doesn't work.

As a workaround, the test now explicitly reads the env var in the user's
instrumentation-client.ts (where Next.js DOES replace process.env values)
and passes it to Sentry.init() as the spotlight option.

This ensures the Spotlight integration is properly tested while
acknowledging the Turbopack limitation.
PUBLIC_E2E_TEST_DSN: dsn,
REACT_APP_E2E_TEST_DSN: dsn,
VITE_E2E_TEST_DSN: dsn,
VITE_SENTRY_SPOTLIGHT: 'true',
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Bug: Spotlight env var globally set causes local/CI test inconsistency

The VITE_SENTRY_SPOTLIGHT: 'true' is injected globally for ALL e2e tests when running locally via run.ts, but the GitHub CI workflow only sets NEXT_PUBLIC_SENTRY_SPOTLIGHT conditionally for tests containing "spotlight" in their name. This creates an inconsistency where Spotlight is enabled in all Vite-based tests locally but not in CI, potentially causing tests to behave differently in the two environments and producing unexpected error logs from failed Spotlight sidecar connections.

Fix in Cursor Fix in Web

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

feat(browser): Add environment variable support for Spotlight configuration

5 participants