-
-
Notifications
You must be signed in to change notification settings - Fork 1.7k
feat(browser): Add environment variable support for Spotlight configuration #18198
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: develop
Are you sure you want to change the base?
Changes from 68 commits
6cb5513
f16380f
fda3d61
bcff50d
cd42ebd
0ac2828
0915965
6ea8d90
870be3b
1cf7f7f
b6fda2b
469940b
be6f1b5
c9b13e3
d129a79
f542f62
4c28587
f9b555a
e12b3fc
ab56171
6cbd1fd
3bc5309
c78da67
fb3f764
d556863
64c4692
75f2b49
9f1e28f
a23d53a
90eca4e
f16915a
c7c9b95
cb298e2
5fdcf7d
c12edfc
2ea8c45
433c0ac
212a8bb
516ede0
5df223a
102dc61
d4662e5
7cffb67
dde88ca
9c6d19a
de9943d
f7d1ffd
3cf3a95
42d832c
4c6aaad
d9d7124
a313e1c
77be213
0d69896
e32150d
2346b4c
e549260
93eceb5
33df6a0
669c71b
8d639f4
ca898d9
855ff97
5deeb64
9ef14ff
fcab9df
693c80e
7c1107f
9a9ba91
65860d4
1ab6f28
7501e60
351046b
eca64b5
0ad25a3
b9d3337
b2716ec
94d86a0
43572cf
df539cf
c23f1d7
e5409e6
bf2e634
b16f01d
40c4967
1642e35
67d1d4b
ce30f02
5bc01a0
939e0cd
f24fa13
c7652fe
bb65b10
d62b54e
12481ec
d873831
4f2f69d
0a8c255
bae7fb6
d72f2f2
87f6dc6
f00a377
6465550
8d3702a
1c05b4c
130bd92
70435c7
7d9e165
6e7eb39
ad6b021
03eb6e5
73ea2d6
51262cf
fa8debc
ee9ae35
4189085
86cce1f
76980e2
1614dbb
7b8612c
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -4,3 +4,4 @@ tmp | |
| .tmp_build_stderr | ||
| pnpm-lock.yaml | ||
| .last-run.json | ||
| .next | ||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -74,6 +74,8 @@ async function run(): Promise<void> { | |
| NEXT_PUBLIC_E2E_TEST_DSN: dsn, | ||
| PUBLIC_E2E_TEST_DSN: dsn, | ||
| REACT_APP_E2E_TEST_DSN: dsn, | ||
| VITE_E2E_TEST_DSN: dsn, | ||
| VITE_SENTRY_SPOTLIGHT: 'true', | ||
BYK marked this conversation as resolved.
Outdated
Show resolved
Hide resolved
|
||
| E2E_TEST_SENTRY_ORG_SLUG: process.env.E2E_TEST_SENTRY_ORG_SLUG || DEFAULT_SENTRY_ORG_SLUG, | ||
| E2E_TEST_SENTRY_PROJECT: process.env.E2E_TEST_SENTRY_PROJECT || DEFAULT_SENTRY_PROJECT, | ||
| // Pass workspace root so tests copied to temp dirs can find local packages | ||
|
|
||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,199 @@ | ||
| # Spotlight Environment Variable E2E Tests | ||
|
|
||
| This document describes the E2E tests for Spotlight environment variable handling across different bundlers and module formats. | ||
|
|
||
| ## Overview | ||
|
|
||
| The Sentry JavaScript SDK supports Spotlight configuration via environment variables. The implementation must handle: | ||
|
|
||
| 1. **Multiple environment variable prefixes** for different frameworks (e.g., `NEXT_PUBLIC_*`, `VITE_*`) | ||
| 2. **Different module formats** (ESM vs CJS) | ||
| 3. **Different environment variable access methods** (`process.env` vs `import.meta.env`) | ||
| 4. **Empty string filtering** (empty strings should be treated as undefined) | ||
|
|
||
| ## Test Coverage | ||
|
|
||
| ### Next.js Tests (`nextjs-15/tests/spotlight-env.test.ts`) | ||
|
|
||
| Tests the **CJS build** scenario where `import.meta` must be stripped to avoid syntax errors. | ||
|
|
||
| **Test Page**: `/spotlight-env-test` | ||
| **Source**: `nextjs-15/app/spotlight-env-test/page.tsx` | ||
|
|
||
| #### Tests: | ||
|
|
||
| 1. **`respects NEXT_PUBLIC_SENTRY_SPOTLIGHT environment variable`** | ||
| - Verifies that `NEXT_PUBLIC_SENTRY_SPOTLIGHT=true` enables Spotlight | ||
| - Checks that the Spotlight integration is registered | ||
|
|
||
| 2. **`NEXT_PUBLIC_SENTRY_SPOTLIGHT takes precedence over SENTRY_SPOTLIGHT`** | ||
| - Verifies that `SENTRY_SPOTLIGHT` (backend-only) is not accessible in browser | ||
| - Ensures framework-specific vars have priority | ||
|
|
||
| 3. **`handles empty string environment variables correctly`** | ||
| - Documents expected behavior: empty strings should disable Spotlight | ||
| - Tests that `resolveSpotlightOptions` filters empty strings | ||
|
|
||
| 4. **`process.env check works without errors in CJS build`** | ||
| - **Critical test**: Verifies no `import.meta` syntax errors in CJS build | ||
| - Checks that the rollup plugin successfully stripped ESM-only code | ||
| - Monitors console for syntax errors | ||
|
|
||
| #### Environment Setup: | ||
|
|
||
| ```bash | ||
| NEXT_PUBLIC_SENTRY_SPOTLIGHT=true | ||
| # SENTRY_SPOTLIGHT can be set for backend, but won't be exposed to browser | ||
| ``` | ||
|
|
||
| ### Vite Tests (`browser-webworker-vite/tests/spotlight-env.test.ts`) | ||
|
|
||
| Tests the **ESM build** scenario where `import.meta` should be present and functional. | ||
|
|
||
| **Test Page**: `/spotlight-env-test.html` | ||
| **Source**: `browser-webworker-vite/src/spotlight-env-test.ts` | ||
|
|
||
| #### Tests: | ||
|
|
||
| 1. **`respects VITE_SENTRY_SPOTLIGHT environment variable`** | ||
| - Verifies that `VITE_SENTRY_SPOTLIGHT=true` enables Spotlight | ||
| - Checks that the Spotlight integration is registered | ||
|
|
||
| 2. **`import.meta.env is available in ESM build`** | ||
| - **Critical test**: Verifies `import.meta` is present in ESM builds | ||
| - Checks that `import.meta.env.VITE_SENTRY_SPOTLIGHT` is accessible | ||
| - Confirms the build format is ESM | ||
|
|
||
| 3. **`process.env also works via Vite transformation`** | ||
| - Verifies that Vite transforms `process.env` references | ||
| - Both `process.env` and `import.meta.env` should work | ||
|
|
||
| 4. **`handles empty string environment variables correctly`** | ||
| - Documents expected behavior for empty strings | ||
| - Tests that `resolveSpotlightOptions` filters empty strings | ||
|
|
||
| 5. **`no syntax errors from import.meta in ESM build`** | ||
| - Verifies no syntax errors when using `import.meta` | ||
| - Monitors console for errors | ||
|
|
||
| 6. **`getEnvValue function works with import.meta.env`** | ||
| - Tests the `getEnvValue` utility function | ||
| - Verifies it successfully reads from `import.meta.env` | ||
|
|
||
| #### Environment Setup: | ||
|
|
||
| ```bash | ||
| VITE_SENTRY_SPOTLIGHT=true | ||
| ``` | ||
|
|
||
| ## Implementation Details | ||
|
|
||
| ### Rollup Plugins | ||
|
|
||
| Two rollup plugins handle module-format-specific code: | ||
|
|
||
| 1. **`makeStripEsmPlugin()`** - Strips ESM-only code from CJS builds | ||
| - Removes code between `/* rollup-esm-only */` and `/* rollup-esm-only-end */` | ||
| - Applied to all CJS builds | ||
|
|
||
| 2. **`makeStripCjsPlugin()`** - Strips CJS-only code from ESM builds | ||
| - Removes code between `/* rollup-cjs-only */` and `/* rollup-cjs-only-end */` | ||
| - Applied to all ESM builds | ||
|
|
||
| ### Source Code | ||
|
|
||
| **File**: `packages/browser/src/utils/env.ts` | ||
|
|
||
| The `import.meta.env` check is wrapped in special comments: | ||
|
|
||
| ```typescript | ||
| /* rollup-esm-only */ | ||
| // Check import.meta.env (Vite, Astro, SvelteKit, etc.) | ||
| try { | ||
| if (typeof import.meta !== 'undefined' && import.meta.env) { | ||
| const value = import.meta.env[key]; | ||
| if (value !== undefined) { | ||
| return value; | ||
| } | ||
| } | ||
| } catch (e) { | ||
| // Silently ignore | ||
| } | ||
| /* rollup-esm-only-end */ | ||
| ``` | ||
|
|
||
| This code is: | ||
|
|
||
| - **Included** in ESM builds (Vite, Astro, SvelteKit) | ||
| - **Stripped** from CJS builds (Next.js, Webpack, etc.) | ||
|
|
||
| ### Empty String Handling | ||
|
|
||
| **File**: `packages/core/src/utils/resolveSpotlightOptions.ts` | ||
|
|
||
| The shared `resolveSpotlightOptions` function filters empty/whitespace strings: | ||
|
|
||
| ```typescript | ||
| // Treat empty/whitespace-only strings as undefined | ||
| const envUrl = typeof envSpotlight === 'string' && envSpotlight.trim() !== '' ? envSpotlight : undefined; | ||
| ``` | ||
|
|
||
| This ensures: | ||
|
|
||
| - Empty strings never enable Spotlight | ||
| - Whitespace-only strings are treated as undefined | ||
| - No invalid URL connections are attempted | ||
|
|
||
| ## Running the Tests | ||
|
|
||
| ### Next.js Tests | ||
|
|
||
| ```bash | ||
| cd dev-packages/e2e-tests/test-applications/nextjs-15 | ||
| NEXT_PUBLIC_SENTRY_SPOTLIGHT=true pnpm test tests/spotlight-env.test.ts | ||
| ``` | ||
|
|
||
| ### Vite Tests | ||
|
|
||
| ```bash | ||
| cd dev-packages/e2e-tests/test-applications/browser-webworker-vite | ||
| VITE_SENTRY_SPOTLIGHT=true pnpm test tests/spotlight-env.test.ts | ||
| ``` | ||
|
|
||
| ## Expected Outcomes | ||
|
|
||
| ### Next.js (CJS) | ||
|
|
||
| - ✅ `process.env.NEXT_PUBLIC_SENTRY_SPOTLIGHT` accessible | ||
| - ✅ `SENTRY_SPOTLIGHT` NOT accessible (backend-only) | ||
| - ✅ No `import.meta` syntax in output | ||
| - ✅ No syntax errors | ||
| - ✅ Spotlight integration enabled | ||
|
|
||
| ### Vite (ESM) | ||
|
|
||
| - ✅ `import.meta.env.VITE_SENTRY_SPOTLIGHT` accessible | ||
| - ✅ `process.env.VITE_SENTRY_SPOTLIGHT` NOT accessible (Vite only exposes import.meta.env) | ||
| - ✅ `import.meta` syntax present in output | ||
| - ✅ No syntax errors | ||
| - ✅ Spotlight integration enabled | ||
|
|
||
| ## Troubleshooting | ||
|
|
||
| ### Syntax Error: Cannot use import.meta outside a module | ||
|
|
||
| - **Cause**: `import.meta` code not stripped from CJS build | ||
| - **Fix**: Verify `makeStripEsmPlugin()` is applied to CJS builds | ||
| - **Check**: Look for `/* rollup-esm-only */` comments in source | ||
|
|
||
| ### Spotlight not enabled despite env var set | ||
|
|
||
| - **Cause**: Empty string or wrong prefix | ||
| - **Fix**: Use correct prefix (`NEXT_PUBLIC_*` for Next.js, `VITE_*` for Vite) | ||
| - **Check**: Verify `resolveSpotlightOptions` receives non-empty string | ||
|
|
||
| ### import.meta.env returns undefined in Vite | ||
|
|
||
| - **Cause**: `import.meta` code stripped from ESM build | ||
| - **Fix**: Verify `makeStripEsmPlugin()` is NOT applied to ESM builds | ||
| - **Check**: ESM builds should only use `makeStripCjsPlugin()` |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -1,13 +1,13 @@ | ||
| <!doctype html> | ||
| <html lang="en"> | ||
| <head> | ||
| <meta charset="utf-8"> | ||
| <title>Angular17</title> | ||
| <base href="/"> | ||
| <meta name="viewport" content="width=device-width, initial-scale=1"> | ||
| <link rel="icon" type="image/x-icon" href="favicon.ico"> | ||
| </head> | ||
| <body> | ||
| <app-root></app-root> | ||
| </body> | ||
| <head> | ||
| <meta charset="utf-8" /> | ||
| <title>Angular17</title> | ||
| <base href="/" /> | ||
| <meta name="viewport" content="width=device-width, initial-scale=1" /> | ||
| <link rel="icon" type="image/x-icon" href="favicon.ico" /> | ||
| </head> | ||
| <body> | ||
| <app-root></app-root> | ||
| </body> | ||
| </html> |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -1,13 +1,13 @@ | ||
| <!doctype html> | ||
| <html lang="en"> | ||
| <head> | ||
| <meta charset="utf-8"> | ||
| <title>Angular 18</title> | ||
| <base href="/"> | ||
| <meta name="viewport" content="width=device-width, initial-scale=1"> | ||
| <link rel="icon" type="image/x-icon" href="favicon.ico"> | ||
| </head> | ||
| <body> | ||
| <app-root></app-root> | ||
| </body> | ||
| <head> | ||
| <meta charset="utf-8" /> | ||
| <title>Angular 18</title> | ||
| <base href="/" /> | ||
| <meta name="viewport" content="width=device-width, initial-scale=1" /> | ||
| <link rel="icon" type="image/x-icon" href="favicon.ico" /> | ||
| </head> | ||
| <body> | ||
| <app-root></app-root> | ||
| </body> | ||
| </html> |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -1,13 +1,13 @@ | ||
| <!doctype html> | ||
| <html lang="en"> | ||
| <head> | ||
| <meta charset="utf-8"> | ||
| <title>Angular19</title> | ||
| <base href="/"> | ||
| <meta name="viewport" content="width=device-width, initial-scale=1"> | ||
| <link rel="icon" type="image/x-icon" href="favicon.ico"> | ||
| </head> | ||
| <body> | ||
| <app-root></app-root> | ||
| </body> | ||
| <head> | ||
| <meta charset="utf-8" /> | ||
| <title>Angular19</title> | ||
| <base href="/" /> | ||
| <meta name="viewport" content="width=device-width, initial-scale=1" /> | ||
| <link rel="icon" type="image/x-icon" href="favicon.ico" /> | ||
| </head> | ||
| <body> | ||
| <app-root></app-root> | ||
| </body> | ||
| </html> |
Uh oh!
There was an error while loading. Please reload this page.