Skip to content

Commit c1848cd

Browse files
authored
feat(bundles): Add pluggable integrations on CDN to Sentry namespace (getsentry#10452)
Previously, they were only put on `Sentry.Integrations.XXX`, now you can do e.g. `Sentry.httpClientIntegration()`. While at it, I also added a browser integration test for this. I also made the way we do this more future proof, as in v8 this will not be imported anymore from `@sentry/integrations` (which we rely on right now), plus the heuristic used to rely on integration name === filename. Now, there is a manual map of imported method names to a CDN bundle file name.
1 parent 0588a3f commit c1848cd

File tree

5 files changed

+112
-4
lines changed

5 files changed

+112
-4
lines changed
Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
import * as Sentry from '@sentry/browser';
2+
import { httpClientIntegration } from '@sentry/integrations';
3+
4+
window.Sentry = Sentry;
5+
6+
Sentry.init({
7+
dsn: 'https://[email protected]/1337',
8+
integrations: [httpClientIntegration()],
9+
tracesSampleRate: 1,
10+
sendDefaultPii: true,
11+
});
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
const xhr = new XMLHttpRequest();
2+
3+
xhr.open('GET', 'http://localhost:7654/foo', true);
4+
xhr.withCredentials = true;
5+
xhr.setRequestHeader('Accept', 'application/json');
6+
xhr.setRequestHeader('Content-Type', 'application/json');
7+
xhr.setRequestHeader('Cache', 'no-cache');
8+
xhr.send();
Lines changed: 64 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,64 @@
1+
import { expect } from '@playwright/test';
2+
import type { Event } from '@sentry/types';
3+
4+
import { sentryTest } from '../../../../utils/fixtures';
5+
import { getFirstSentryEnvelopeRequest } from '../../../../utils/helpers';
6+
7+
sentryTest('works with httpClientIntegration', async ({ getLocalTestPath, page }) => {
8+
const url = await getLocalTestPath({ testDir: __dirname });
9+
10+
await page.route('**/foo', route => {
11+
return route.fulfill({
12+
status: 500,
13+
body: JSON.stringify({
14+
error: {
15+
message: 'Internal Server Error',
16+
},
17+
}),
18+
headers: {
19+
'Content-Type': 'text/html',
20+
},
21+
});
22+
});
23+
24+
const eventData = await getFirstSentryEnvelopeRequest<Event>(page, url);
25+
26+
expect(eventData.exception?.values).toHaveLength(1);
27+
28+
// Not able to get the cookies from the request/response because of Playwright bug
29+
// https://github.com/microsoft/playwright/issues/11035
30+
expect(eventData).toMatchObject({
31+
message: 'HTTP Client Error with status code: 500',
32+
exception: {
33+
values: [
34+
{
35+
type: 'Error',
36+
value: 'HTTP Client Error with status code: 500',
37+
mechanism: {
38+
type: 'http.client',
39+
handled: false,
40+
},
41+
},
42+
],
43+
},
44+
request: {
45+
url: 'http://localhost:7654/foo',
46+
method: 'GET',
47+
headers: {
48+
accept: 'application/json',
49+
cache: 'no-cache',
50+
'content-type': 'application/json',
51+
},
52+
},
53+
contexts: {
54+
response: {
55+
status_code: 500,
56+
body_size: 45,
57+
headers: {
58+
'content-type': 'text/html',
59+
'content-length': '45',
60+
},
61+
},
62+
},
63+
});
64+
});

dev-packages/browser-integration-tests/utils/generatePlugin.ts

Lines changed: 28 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,27 @@ const useCompiledModule = bundleKey === 'esm' || bundleKey === 'cjs';
2222
const useBundleOrLoader = bundleKey && !useCompiledModule;
2323
const useLoader = bundleKey.startsWith('loader');
2424

25+
// These are imports that, when using CDN bundles, are not included in the main CDN bundle.
26+
// In this case, if we encounter this import, we want to add this CDN bundle file instead
27+
const IMPORTED_INTEGRATION_CDN_BUNDLE_PATHS: Record<string, string> = {
28+
httpClientIntegration: 'httpclient',
29+
HttpClient: 'httpclient',
30+
captureConsoleIntegration: 'captureconsole',
31+
CaptureConsole: 'captureconsole',
32+
debugIntegration: 'debug',
33+
Debug: 'debug',
34+
rewriteFramesIntegration: 'rewriteframes',
35+
RewriteFrames: 'rewriteframes',
36+
contextLinesIntegration: 'contextlines',
37+
ContextLines: 'contextlines',
38+
extraErrorDataIntegration: 'extraerrordata',
39+
ExtraErrorData: 'extraerrordata',
40+
reportingObserverIntegration: 'reportingobserver',
41+
ReportingObserver: 'reportingobserver',
42+
sessionTimingIntegration: 'sessiontiming',
43+
SessionTiming: 'sessiontiming',
44+
};
45+
2546
const BUNDLE_PATHS: Record<string, Record<string, string>> = {
2647
browser: {
2748
cjs: 'build/npm/cjs/index.js',
@@ -149,8 +170,8 @@ class SentryScenarioGenerationPlugin {
149170
'@sentry/browser': 'Sentry',
150171
'@sentry/tracing': 'Sentry',
151172
'@sentry/replay': 'Sentry',
152-
'@sentry/integrations': 'Sentry.Integrations',
153-
'@sentry/wasm': 'Sentry.Integrations',
173+
'@sentry/integrations': 'Sentry',
174+
'@sentry/wasm': 'Sentry',
154175
}
155176
: {};
156177

@@ -161,8 +182,11 @@ class SentryScenarioGenerationPlugin {
161182
parser.hooks.import.tap(
162183
this._name,
163184
(statement: { specifiers: [{ imported: { name: string } }] }, source: string) => {
164-
if (source === '@sentry/integrations') {
165-
this.requiredIntegrations.push(statement.specifiers[0].imported.name.toLowerCase());
185+
const imported = statement.specifiers?.[0]?.imported?.name;
186+
187+
if (imported && IMPORTED_INTEGRATION_CDN_BUNDLE_PATHS[imported]) {
188+
const bundleName = IMPORTED_INTEGRATION_CDN_BUNDLE_PATHS[imported];
189+
this.requiredIntegrations.push(bundleName);
166190
} else if (source === '@sentry/wasm') {
167191
this.requiresWASMIntegration = true;
168192
}

dev-packages/rollup-utils/bundleHelpers.mjs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -82,6 +82,7 @@ export function makeBaseBundleConfig(options) {
8282
' for (var key in exports) {',
8383
' if (Object.prototype.hasOwnProperty.call(exports, key)) {',
8484
' __window.Sentry.Integrations[key] = exports[key];',
85+
' __window.Sentry[key] = exports[key];',
8586
' }',
8687
' }',
8788
].join('\n'),

0 commit comments

Comments
 (0)