Skip to content

feat(loader): Ensure default integrations are added & work for performance #46995

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

Merged
merged 1 commit into from
Apr 6, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
44 changes: 32 additions & 12 deletions src/sentry/templates/sentry/js-sdk-loader.js.tmpl
Original file line number Diff line number Diff line change
Expand Up @@ -50,13 +50,29 @@
// Once our SDK is loaded
_newScriptTag.addEventListener('load', function () {
try {
// Restore onerror/onunhandledrejection handlers
_window[_onerror] = _oldOnerror;
_window[_onunhandledrejection] = _oldOnunhandledrejection;
// Restore onerror/onunhandledrejection handlers - only if not mutated in the meanwhile
if (_window[_onerror] && _window[_onerror].__SENTRY_LOADER__) {
_window[_onerror] = _oldOnerror;
}
if (_window[_onunhandledrejection] &&
_window[_onunhandledrejection].__SENTRY_LOADER__) {
_window[_onunhandledrejection] = _oldOnunhandledrejection;
}
// Add loader as SDK source
_window.SENTRY_SDK_SOURCE = 'loader';
var SDK = _window[_namespace];
var oldInit_1 = SDK.init;
// Add necessary integrations based on config
var integrations = [];
if (_config.tracesSampleRate) {
integrations.push(new SDK.BrowserTracing());
}
if (_config.replaysSessionSampleRate || _config.replaysOnErrorSampleRate) {
integrations.push(new SDK.Replay());
}
if (integrations.length) {
_config.integrations = integrations;
}
// Configure it using provided DSN and config object
SDK.init = function (options) {
var target = _config;
Expand All @@ -75,23 +91,25 @@
});
_currentScriptTag.parentNode.insertBefore(_newScriptTag, _currentScriptTag);
}
function sdkIsLoaded() {
var __sentry = _window.__SENTRY__;
// If there is a global __SENTRY__ that means that in any of the callbacks init() was already invoked
return !!(!(typeof __sentry === 'undefined') &&
__sentry.hub &&
__sentry.hub.getClient());
}
function sdkLoaded(callbacks, SDK) {
try {
var data = queue.data;
// We have to make sure to call all callbacks first
for (var i = 0; i < callbacks.length; i++) {
if (typeof callbacks[i] === 'function') {
callbacks[i]();
}
}
var initAlreadyCalled = false;
var __sentry = _window.__SENTRY__;
// If there is a global __SENTRY__ that means that in any of the callbacks init() was already invoked
if (!(typeof __sentry === 'undefined') &&
__sentry.hub &&
__sentry.hub.getClient()) {
initAlreadyCalled = true;
}
var data = queue.data;
var initAlreadyCalled = sdkIsLoaded();
// Call init first, if provided
data.sort(function (a) { return (a.f === 'init' ? -1 : 0); });
// We want to replay all calls to Sentry and also make sure that `init` is called if it wasn't already
// We replay all calls to `Sentry.*` now
var calledSentry = false;
Expand Down Expand Up @@ -172,6 +190,7 @@
_oldOnerror.apply(_window, arguments);
}
};
_window[_onerror].__SENTRY_LOADER__ = true;
// Do the same store/queue/call operations for `onunhandledrejection` event
var _oldOnunhandledrejection = _window[_onunhandledrejection];
_window[_onunhandledrejection] = function (e) {
Expand All @@ -186,6 +205,7 @@
_oldOnunhandledrejection.apply(_window, arguments);
}
};
_window[_onunhandledrejection].__SENTRY_LOADER__ = true;
if (!lazy) {
setTimeout(function () {
injectSdk(onLoadCallbacks);
Expand Down
2 changes: 1 addition & 1 deletion src/sentry/templates/sentry/js-sdk-loader.min.js.tmpl
Original file line number Diff line number Diff line change
@@ -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 }});
{% 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 }});
57 changes: 42 additions & 15 deletions src/sentry/templates/sentry/js-sdk-loader.ts
Original file line number Diff line number Diff line change
Expand Up @@ -74,9 +74,16 @@ declare const __LOADER__IS_LAZY__: any;
// Once our SDK is loaded
_newScriptTag.addEventListener('load', function () {
try {
// Restore onerror/onunhandledrejection handlers
_window[_onerror] = _oldOnerror;
_window[_onunhandledrejection] = _oldOnunhandledrejection;
// Restore onerror/onunhandledrejection handlers - only if not mutated in the meanwhile
if (_window[_onerror] && _window[_onerror].__SENTRY_LOADER__) {
_window[_onerror] = _oldOnerror;
}
if (
_window[_onunhandledrejection] &&
_window[_onunhandledrejection].__SENTRY_LOADER__
) {
_window[_onunhandledrejection] = _oldOnunhandledrejection;
}

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

const oldInit = SDK.init;

// Add necessary integrations based on config
const integrations: unknown[] = [];
if (_config.tracesSampleRate) {
integrations.push(new SDK.BrowserTracing());
}

if (_config.replaysSessionSampleRate || _config.replaysOnErrorSampleRate) {
integrations.push(new SDK.Replay());
}

if (integrations.length) {
_config.integrations = integrations;
}

// Configure it using provided DSN and config object
SDK.init = function (options) {
const target = _config;
Expand All @@ -105,27 +126,31 @@ declare const __LOADER__IS_LAZY__: any;
_currentScriptTag.parentNode!.insertBefore(_newScriptTag, _currentScriptTag);
}

function sdkIsLoaded() {
const __sentry = _window.__SENTRY__;
// If there is a global __SENTRY__ that means that in any of the callbacks init() was already invoked
return !!(
!(typeof __sentry === 'undefined') &&
__sentry.hub &&
__sentry.hub.getClient()
);
}

function sdkLoaded(callbacks, SDK) {
try {
const data = queue.data;

// We have to make sure to call all callbacks first
for (let i = 0; i < callbacks.length; i++) {
if (typeof callbacks[i] === 'function') {
callbacks[i]();
}
}

let initAlreadyCalled = false;
const __sentry = _window.__SENTRY__;
// If there is a global __SENTRY__ that means that in any of the callbacks init() was already invoked
if (
!(typeof __sentry === 'undefined') &&
__sentry.hub &&
__sentry.hub.getClient()
) {
initAlreadyCalled = true;
}
const data = queue.data;

let initAlreadyCalled = sdkIsLoaded();

// Call init first, if provided
data.sort(a => (a.f === 'init' ? -1 : 0));

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

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

if (!lazy) {
setTimeout(function () {
Expand Down