Skip to content

Commit 22905fe

Browse files
authored
fix(feedback): Ensure feedback can be lazy loaded in CDN bundles (#13241)
This was brought up in slack - if you use a CDN bundle (or the loader) without feedback included, and you try to lazy-load the feedbackIntegration, it fails as of today. The reason is that we check if `window.Sentry.feedbackIntegration` exists, which it _does_, because we register a shim integration for compatibility in the loader. So this PR adds a property on the shim integration which we can check for during lazy loading. While at it, I also added a missing method to the feedback integration shim.
1 parent ea20c21 commit 22905fe

File tree

6 files changed

+80
-15
lines changed

6 files changed

+80
-15
lines changed
Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
import * as Sentry from '@sentry/browser';
2+
3+
Sentry.init({
4+
dsn: 'https://[email protected]/1337',
5+
integrations: [],
6+
});
7+
8+
window.Sentry = {
9+
...Sentry,
10+
};
Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
window._testLazyLoadIntegration = async function run() {
2+
const integration = await window.Sentry.lazyLoadIntegration('feedbackIntegration');
3+
4+
window.Sentry.getClient()?.addIntegration(integration());
5+
6+
window._integrationLoaded = true;
7+
};
Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,38 @@
1+
import { expect } from '@playwright/test';
2+
import { SDK_VERSION } from '@sentry/browser';
3+
4+
import { sentryTest } from '../../../../utils/fixtures';
5+
6+
sentryTest('it allows to lazy load the feedback integration', async ({ getLocalTestUrl, page }) => {
7+
const bundle = process.env.PW_BUNDLE || '';
8+
const url = await getLocalTestUrl({ testDir: __dirname });
9+
10+
await page.route(`https://browser.sentry-cdn.com/${SDK_VERSION}/feedback.min.js`, route => {
11+
return route.fulfill({
12+
status: 200,
13+
contentType: 'application/javascript;',
14+
body: "window.Sentry.feedbackIntegration = () => ({ name: 'Feedback', attachTo: () => {} })",
15+
});
16+
});
17+
18+
await page.goto(url);
19+
20+
await page.waitForFunction('window.Sentry?.getClient()');
21+
22+
const integrationOutput1 = await page.evaluate('window.Sentry.feedbackIntegration?._isShim');
23+
24+
// Multiple cases are possible here:
25+
// 1. Bundle without feedback, should have _isShim property
26+
if (bundle.startsWith('bundle') && !bundle.includes('feedback')) {
27+
expect(integrationOutput1).toBe(true);
28+
} else {
29+
// 2. Either bundle with feedback, or ESM, should not have _isShim property
30+
expect(integrationOutput1).toBe(undefined);
31+
}
32+
33+
await page.evaluate('window._testLazyLoadIntegration()');
34+
await page.waitForFunction('window._integrationLoaded');
35+
36+
const integrationOutput2 = await page.evaluate('window.Sentry.feedbackIntegration?._isShim');
37+
expect(integrationOutput2).toBe(undefined);
38+
});

dev-packages/rollup-utils/plugins/bundlePlugins.mjs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -133,6 +133,8 @@ export function makeTerserPlugin() {
133133
'_sentryIsolationScope',
134134
// require-in-the-middle calls `Module._resolveFilename`. We cannot mangle this (AWS lambda layer bundle).
135135
'_resolveFilename',
136+
// Set on e.g. the shim feedbackIntegration to be able to detect it
137+
'_isShim',
136138
],
137139
},
138140
},

packages/browser/src/utils/lazyLoadIntegration.ts

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -43,7 +43,10 @@ export async function lazyLoadIntegration(name: keyof typeof LazyLoadableIntegra
4343

4444
// Bail if the integration already exists
4545
const existing = sentryOnWindow[name];
46-
if (typeof existing === 'function') {
46+
// The `feedbackIntegration` is loaded by default in the CDN bundles,
47+
// so we need to differentiate between the real integration and the shim.
48+
// if only the shim exists, we still want to lazy load the real integration.
49+
if (typeof existing === 'function' && !('_isShim' in existing)) {
4750
return existing;
4851
}
4952

packages/integration-shims/src/Feedback.ts

Lines changed: 19 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@ import type { Integration } from '@sentry/types';
22
import { consoleSandbox } from '@sentry/utils';
33
import { FAKE_FUNCTION } from './common';
44

5-
const FEEDBACK_INTEGRATION_METHODS = ['attachTo', 'createWidget', 'remove'] as const;
5+
const FEEDBACK_INTEGRATION_METHODS = ['attachTo', 'createForm', 'createWidget', 'remove'] as const;
66

77
type FeedbackSpecificMethods = Record<(typeof FEEDBACK_INTEGRATION_METHODS)[number], () => void>;
88

@@ -13,17 +13,22 @@ interface FeedbackIntegration extends Integration, FeedbackSpecificMethods {}
1313
* It is needed in order for the CDN bundles to continue working when users add/remove feedback
1414
* from it, without changing their config. This is necessary for the loader mechanism.
1515
*/
16-
export function feedbackIntegrationShim(_options: unknown): FeedbackIntegration {
17-
consoleSandbox(() => {
18-
// eslint-disable-next-line no-console
19-
console.warn('You are using feedbackIntegration() even though this bundle does not include feedback.');
20-
});
16+
export const feedbackIntegrationShim = Object.assign(
17+
(_options: unknown): FeedbackIntegration => {
18+
consoleSandbox(() => {
19+
// eslint-disable-next-line no-console
20+
console.warn('You are using feedbackIntegration() even though this bundle does not include feedback.');
21+
});
2122

22-
return {
23-
name: 'Feedback',
24-
...(FEEDBACK_INTEGRATION_METHODS.reduce((acc, method) => {
25-
acc[method] = FAKE_FUNCTION;
26-
return acc;
27-
}, {} as FeedbackSpecificMethods) as FeedbackSpecificMethods),
28-
};
29-
}
23+
return {
24+
name: 'Feedback',
25+
...(FEEDBACK_INTEGRATION_METHODS.reduce((acc, method) => {
26+
acc[method] = FAKE_FUNCTION;
27+
return acc;
28+
}, {} as FeedbackSpecificMethods) as FeedbackSpecificMethods),
29+
};
30+
},
31+
{
32+
_isShim: true,
33+
},
34+
);

0 commit comments

Comments
 (0)