Skip to content

Commit b20b711

Browse files
committed
feat(loader): Ensure default integrations are added & work for performance/replay
1 parent 930cd1e commit b20b711

File tree

3 files changed

+75
-28
lines changed

3 files changed

+75
-28
lines changed

src/sentry/templates/sentry/js-sdk-loader.js.tmpl

Lines changed: 32 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -50,13 +50,29 @@
5050
// Once our SDK is loaded
5151
_newScriptTag.addEventListener('load', function () {
5252
try {
53-
// Restore onerror/onunhandledrejection handlers
54-
_window[_onerror] = _oldOnerror;
55-
_window[_onunhandledrejection] = _oldOnunhandledrejection;
53+
// Restore onerror/onunhandledrejection handlers - only if not mutated in the meanwhile
54+
if (_window[_onerror] && _window[_onerror].__SENTRY_LOADER__) {
55+
_window[_onerror] = _oldOnerror;
56+
}
57+
if (_window[_onunhandledrejection] &&
58+
_window[_onunhandledrejection].__SENTRY_LOADER__) {
59+
_window[_onunhandledrejection] = _oldOnunhandledrejection;
60+
}
5661
// Add loader as SDK source
5762
_window.SENTRY_SDK_SOURCE = 'loader';
5863
var SDK = _window[_namespace];
5964
var oldInit_1 = SDK.init;
65+
// Add necessary integrations based on config
66+
var integrations = [];
67+
if (_config.tracesSampleRate) {
68+
integrations.push(new SDK.BrowserTracing());
69+
}
70+
if (_config.replaysSessionSampleRate || _config.replaysOnErrorSampleRate) {
71+
integrations.push(new SDK.Replay());
72+
}
73+
if (integrations.length) {
74+
_config.integrations = integrations;
75+
}
6076
// Configure it using provided DSN and config object
6177
SDK.init = function (options) {
6278
var target = _config;
@@ -75,23 +91,25 @@
7591
});
7692
_currentScriptTag.parentNode.insertBefore(_newScriptTag, _currentScriptTag);
7793
}
94+
function sdkIsLoaded() {
95+
var __sentry = _window.__SENTRY__;
96+
// If there is a global __SENTRY__ that means that in any of the callbacks init() was already invoked
97+
return !!(!(typeof __sentry === 'undefined') &&
98+
__sentry.hub &&
99+
__sentry.hub.getClient());
100+
}
78101
function sdkLoaded(callbacks, SDK) {
79102
try {
80-
var data = queue.data;
81103
// We have to make sure to call all callbacks first
82104
for (var i = 0; i < callbacks.length; i++) {
83105
if (typeof callbacks[i] === 'function') {
84106
callbacks[i]();
85107
}
86108
}
87-
var initAlreadyCalled = false;
88-
var __sentry = _window.__SENTRY__;
89-
// If there is a global __SENTRY__ that means that in any of the callbacks init() was already invoked
90-
if (!(typeof __sentry === 'undefined') &&
91-
__sentry.hub &&
92-
__sentry.hub.getClient()) {
93-
initAlreadyCalled = true;
94-
}
109+
var data = queue.data;
110+
var initAlreadyCalled = sdkIsLoaded();
111+
// Call init first, if provided
112+
data.sort(function (a) { return (a.f === 'init' ? -1 : 0); });
95113
// We want to replay all calls to Sentry and also make sure that `init` is called if it wasn't already
96114
// We replay all calls to `Sentry.*` now
97115
var calledSentry = false;
@@ -172,6 +190,7 @@
172190
_oldOnerror.apply(_window, arguments);
173191
}
174192
};
193+
_window[_onerror].__SENTRY_LOADER__ = true;
175194
// Do the same store/queue/call operations for `onunhandledrejection` event
176195
var _oldOnunhandledrejection = _window[_onunhandledrejection];
177196
_window[_onunhandledrejection] = function (e) {
@@ -186,6 +205,7 @@
186205
_oldOnunhandledrejection.apply(_window, arguments);
187206
}
188207
};
208+
_window[_onunhandledrejection].__SENTRY_LOADER__ = true;
189209
if (!lazy) {
190210
setTimeout(function () {
191211
injectSdk(onLoadCallbacks);
Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1 +1 @@
1-
{% load sentry_helpers %}!function(n,t,e,o,i,r,a,c,f,p){for(var u=p,forceLoad=!1,s=0;s<document.scripts.length;s++)if(document.scripts[s].src.indexOf(a)>-1){u&&"no"===document.scripts[s].getAttribute("data-lazy")&&(u=!1);break}var _=!1,d=[],l=function(n){("e"in n||"p"in n||n.f&&n.f.indexOf("capture")>-1||n.f&&n.f.indexOf("showReportDialog")>-1)&&u&&h(d),l.data.push(n)};function h(a){if(!_){_=!0;var p=t.scripts[0],u=t.createElement(e);u.src=c,u.crossOrigin="anonymous",u.addEventListener("load",(function(){try{n[o]=v,n[i]=y,n.SENTRY_SDK_SOURCE="loader";var t=n[r],e=t.init;t.init=function(n){var t=f;for(var o in n)Object.prototype.hasOwnProperty.call(n,o)&&(t[o]=n[o]);e(t)},function(t,e){try{for(var r=l.data,a=0;a<t.length;a++)"function"==typeof t[a]&&t[a]();var c=!1,f=n.__SENTRY__;void 0!==f&&f.hub&&f.hub.getClient()&&(c=!0);var p=!1;for(a=0;a<r.length;a++)if(r[a].f){p=!0;var u=r[a];!1===c&&"init"!==u.f&&e.init(),c=!0,e[u.f].apply(e,u.a)}!1===c&&!1===p&&e.init();var s=n[o],_=n[i];for(a=0;a<r.length;a++)"e"in r[a]&&s?s.apply(n,r[a].e):"p"in r[a]&&_&&_.apply(n,[r[a].p])}catch(n){console.error(n)}}(a,t)}catch(n){console.error(n)}})),p.parentNode.insertBefore(u,p)}}l.data=[],n[r]=n[r]||{},n[r].onLoad=function(n){d.push(n),u&&!forceLoad||h(d)},n[r].forceLoad=function(){forceLoad=!0,u&&setTimeout((function(){h(d)}))},["init","addBreadcrumb","captureMessage","captureException","captureEvent","configureScope","withScope","showReportDialog"].forEach((function(t){n[r][t]=function(){l({f:t,a:arguments})}}));var v=n[o];n[o]=function(){l({e:[].slice.call(arguments)}),v&&v.apply(n,arguments)};var y=n[i];n[i]=function(t){l({p:"reason"in t?t.reason:"detail"in t&&"reason"in t.detail?t.detail.reason:t}),y&&y.apply(n,arguments)},u||setTimeout((function(){h(d)}))}(window,document,"script","onerror","onunhandledrejection","Sentry",'{{ publicKey|safe }}','{{ jsSdkUrl|safe }}',{{ config|to_json|safe }},{{ isLazy|safe|lower }});
1+
{% load sentry_helpers %}!function(n,e,t,r,o,a,i,c,_,p){for(var s=p,forceLoad=!1,f=0;f<document.scripts.length;f++)if(document.scripts[f].src.indexOf(i)>-1){s&&"no"===document.scripts[f].getAttribute("data-lazy")&&(s=!1);break}var u=!1,l=[],d=function(n){("e"in n||"p"in n||n.f&&n.f.indexOf("capture")>-1||n.f&&n.f.indexOf("showReportDialog")>-1)&&s&&E(l),d.data.push(n)};function E(i){if(!u){u=!0;var p=e.scripts[0],s=e.createElement(t);s.src=c,s.crossOrigin="anonymous",s.addEventListener("load",(function(){try{n[r]&&n[r].__SENTRY_LOADER__&&(n[r]=R),n[o]&&n[o].__SENTRY_LOADER__&&(n[o]=h),n.SENTRY_SDK_SOURCE="loader";var e=n[a],t=e.init,c=[];_.tracesSampleRate&&c.push(new e.BrowserTracing),(_.replaysSessionSampleRate||_.replaysOnErrorSampleRate)&&c.push(new e.Replay),c.length&&(_.integrations=c),e.init=function(n){var e=_;for(var r in n)Object.prototype.hasOwnProperty.call(n,r)&&(e[r]=n[r]);t(e)},function(e,t){try{for(var a=0;a<e.length;a++)"function"==typeof e[a]&&e[a]();var i=d.data,c=!(void 0===(u=n.__SENTRY__)||!u.hub||!u.hub.getClient());i.sort((function(n){return"init"===n.f?-1:0}));var _=!1;for(a=0;a<i.length;a++)if(i[a].f){_=!0;var p=i[a];!1===c&&"init"!==p.f&&t.init(),c=!0,t[p.f].apply(t,p.a)}!1===c&&!1===_&&t.init();var s=n[r],f=n[o];for(a=0;a<i.length;a++)"e"in i[a]&&s?s.apply(n,i[a].e):"p"in i[a]&&f&&f.apply(n,[i[a].p])}catch(n){console.error(n)}var u}(i,e)}catch(n){console.error(n)}})),p.parentNode.insertBefore(s,p)}}d.data=[],n[a]=n[a]||{},n[a].onLoad=function(n){l.push(n),s&&!forceLoad||E(l)},n[a].forceLoad=function(){forceLoad=!0,s&&setTimeout((function(){E(l)}))},["init","addBreadcrumb","captureMessage","captureException","captureEvent","configureScope","withScope","showReportDialog"].forEach((function(e){n[a][e]=function(){d({f:e,a:arguments})}}));var R=n[r];n[r]=function(){d({e:[].slice.call(arguments)}),R&&R.apply(n,arguments)},n[r].__SENTRY_LOADER__=!0;var h=n[o];n[o]=function(e){d({p:"reason"in e?e.reason:"detail"in e&&"reason"in e.detail?e.detail.reason:e}),h&&h.apply(n,arguments)},n[o].__SENTRY_LOADER__=!0,s||setTimeout((function(){E(l)}))}(window,document,"script","onerror","onunhandledrejection","Sentry",'{{ publicKey|safe }}','{{ jsSdkUrl|safe }}',{{ config|to_json|safe }},{{ isLazy|safe|lower }});

src/sentry/templates/sentry/js-sdk-loader.ts

Lines changed: 42 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -74,9 +74,16 @@ declare const __LOADER__IS_LAZY__: any;
7474
// Once our SDK is loaded
7575
_newScriptTag.addEventListener('load', function () {
7676
try {
77-
// Restore onerror/onunhandledrejection handlers
78-
_window[_onerror] = _oldOnerror;
79-
_window[_onunhandledrejection] = _oldOnunhandledrejection;
77+
// Restore onerror/onunhandledrejection handlers - only if not mutated in the meanwhile
78+
if (_window[_onerror] && _window[_onerror].__SENTRY_LOADER__) {
79+
_window[_onerror] = _oldOnerror;
80+
}
81+
if (
82+
_window[_onunhandledrejection] &&
83+
_window[_onunhandledrejection].__SENTRY_LOADER__
84+
) {
85+
_window[_onunhandledrejection] = _oldOnunhandledrejection;
86+
}
8087

8188
// Add loader as SDK source
8289
_window.SENTRY_SDK_SOURCE = 'loader';
@@ -85,6 +92,20 @@ declare const __LOADER__IS_LAZY__: any;
8592

8693
const oldInit = SDK.init;
8794

95+
// Add necessary integrations based on config
96+
const integrations: unknown[] = [];
97+
if (_config.tracesSampleRate) {
98+
integrations.push(new SDK.BrowserTracing());
99+
}
100+
101+
if (_config.replaysSessionSampleRate || _config.replaysOnErrorSampleRate) {
102+
integrations.push(new SDK.Replay());
103+
}
104+
105+
if (integrations.length) {
106+
_config.integrations = integrations;
107+
}
108+
88109
// Configure it using provided DSN and config object
89110
SDK.init = function (options) {
90111
const target = _config;
@@ -105,27 +126,31 @@ declare const __LOADER__IS_LAZY__: any;
105126
_currentScriptTag.parentNode!.insertBefore(_newScriptTag, _currentScriptTag);
106127
}
107128

129+
function sdkIsLoaded() {
130+
const __sentry = _window.__SENTRY__;
131+
// If there is a global __SENTRY__ that means that in any of the callbacks init() was already invoked
132+
return !!(
133+
!(typeof __sentry === 'undefined') &&
134+
__sentry.hub &&
135+
__sentry.hub.getClient()
136+
);
137+
}
138+
108139
function sdkLoaded(callbacks, SDK) {
109140
try {
110-
const data = queue.data;
111-
112141
// We have to make sure to call all callbacks first
113142
for (let i = 0; i < callbacks.length; i++) {
114143
if (typeof callbacks[i] === 'function') {
115144
callbacks[i]();
116145
}
117146
}
118147

119-
let initAlreadyCalled = false;
120-
const __sentry = _window.__SENTRY__;
121-
// If there is a global __SENTRY__ that means that in any of the callbacks init() was already invoked
122-
if (
123-
!(typeof __sentry === 'undefined') &&
124-
__sentry.hub &&
125-
__sentry.hub.getClient()
126-
) {
127-
initAlreadyCalled = true;
128-
}
148+
const data = queue.data;
149+
150+
let initAlreadyCalled = sdkIsLoaded();
151+
152+
// Call init first, if provided
153+
data.sort(a => (a.f === 'init' ? -1 : 0));
129154

130155
// We want to replay all calls to Sentry and also make sure that `init` is called if it wasn't already
131156
// We replay all calls to `Sentry.*` now
@@ -213,6 +238,7 @@ declare const __LOADER__IS_LAZY__: any;
213238
_oldOnerror.apply(_window, arguments);
214239
}
215240
};
241+
_window[_onerror].__SENTRY_LOADER__ = true;
216242

217243
// Do the same store/queue/call operations for `onunhandledrejection` event
218244
const _oldOnunhandledrejection = _window[_onunhandledrejection];
@@ -229,6 +255,7 @@ declare const __LOADER__IS_LAZY__: any;
229255
_oldOnunhandledrejection.apply(_window, arguments);
230256
}
231257
};
258+
_window[_onunhandledrejection].__SENTRY_LOADER__ = true;
232259

233260
if (!lazy) {
234261
setTimeout(function () {

0 commit comments

Comments
 (0)