Skip to content

Commit 26f1f9b

Browse files
committed
remove nesting
1 parent 2cbd6b1 commit 26f1f9b

File tree

6 files changed

+13821
-3
lines changed

6 files changed

+13821
-3
lines changed
Lines changed: 220 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,220 @@
1+
// prettier-ignore
2+
// Prettier disabled due to trailing comma not working in IE10/11
3+
(function(
4+
_window,
5+
_document,
6+
_script,
7+
_onerror,
8+
_onunhandledrejection,
9+
_namespace,
10+
_publicKey,
11+
_sdkBundleUrl,
12+
_config
13+
) {
14+
var lazy = true;
15+
var forceLoad = false;
16+
17+
for (var i = 0; i < document.scripts.length; i++) {
18+
if (document.scripts[i].src.indexOf(_publicKey) > -1) {
19+
lazy = !(document.scripts[i].getAttribute('data-lazy') === 'no');
20+
break;
21+
}
22+
}
23+
24+
var injected = false;
25+
var onLoadCallbacks = [];
26+
27+
// Create a namespace and attach function that will store captured exception
28+
// Because functions are also objects, we can attach the queue itself straight to it and save some bytes
29+
var queue = function(content) {
30+
// content.e = error
31+
// content.p = promise rejection
32+
// content.f = function call the Sentry
33+
if (
34+
('e' in content ||
35+
'p' in content ||
36+
(content.f && content.f.indexOf('capture') > -1) ||
37+
(content.f && content.f.indexOf('showReportDialog') > -1)) &&
38+
lazy
39+
) {
40+
// We only want to lazy inject/load the sdk bundle if
41+
// an error or promise rejection occured
42+
// OR someone called `capture...` on the SDK
43+
injectSdk(onLoadCallbacks);
44+
}
45+
queue.data.push(content);
46+
};
47+
queue.data = [];
48+
49+
function injectSdk(callbacks) {
50+
if (injected) {
51+
return;
52+
}
53+
injected = true;
54+
55+
// Create a `script` tag with provided SDK `url` and attach it just before the first, already existing `script` tag
56+
// Scripts that are dynamically created and added to the document are async by default,
57+
// they don't block rendering and execute as soon as they download, meaning they could
58+
// come out in the wrong order. Because of that we don't need async=1 as GA does.
59+
// it was probably(?) a legacy behavior that they left to not modify few years old snippet
60+
// https://www.html5rocks.com/en/tutorials/speed/script-loading/
61+
var _currentScriptTag = _document.scripts[0];
62+
var _newScriptTag = _document.createElement(_script);
63+
_newScriptTag.src = _sdkBundleUrl;
64+
_newScriptTag.setAttribute('crossorigin', 'anonymous');
65+
66+
// Once our SDK is loaded
67+
_newScriptTag.addEventListener('load', function() {
68+
try {
69+
// Restore onerror/onunhandledrejection handlers
70+
_window[_onerror] = _oldOnerror;
71+
_window[_onunhandledrejection] = _oldOnunhandledrejection;
72+
73+
// Add loader as SDK source
74+
_window.SENTRY_SDK_SOURCE = 'loader';
75+
76+
var SDK = _window[_namespace];
77+
78+
var oldInit = SDK.init;
79+
80+
// Configure it using provided DSN and config object
81+
SDK.init = function(options) {
82+
var target = _config;
83+
for (var key in options) {
84+
if (Object.prototype.hasOwnProperty.call(options, key)) {
85+
target[key] = options[key];
86+
}
87+
}
88+
oldInit(target);
89+
};
90+
91+
sdkLoaded(callbacks, SDK);
92+
} catch (o_O) {
93+
console.error(o_O);
94+
}
95+
});
96+
97+
_currentScriptTag.parentNode.insertBefore(_newScriptTag, _currentScriptTag);
98+
}
99+
100+
function sdkLoaded(callbacks, SDK) {
101+
try {
102+
var data = queue.data;
103+
104+
// We have to make sure to call all callbacks first
105+
for (var i = 0; i < callbacks.length; i++) {
106+
if (typeof callbacks[i] === 'function') {
107+
callbacks[i]();
108+
}
109+
}
110+
111+
var initAlreadyCalled = false;
112+
var __sentry = _window['__SENTRY__'];
113+
// If there is a global __SENTRY__ that means that in any of the callbacks init() was already invoked
114+
if (!(typeof __sentry === 'undefined') && __sentry.hub && __sentry.hub.getClient()) {
115+
initAlreadyCalled = true;
116+
}
117+
118+
// We want to replay all calls to Sentry and also make sure that `init` is called if it wasn't already
119+
// We replay all calls to `Sentry.*` now
120+
var calledSentry = false;
121+
for (var i = 0; i < data.length; i++) {
122+
if (data[i].f) {
123+
calledSentry = true;
124+
var call = data[i];
125+
if (initAlreadyCalled === false && call.f !== 'init') {
126+
// First call always has to be init, this is a conveniece for the user so call to init is optional
127+
SDK.init();
128+
}
129+
initAlreadyCalled = true;
130+
SDK[call.f].apply(SDK, call.a);
131+
}
132+
}
133+
if (initAlreadyCalled === false && calledSentry === false) {
134+
// Sentry has never been called but we need Sentry.init() so call it
135+
SDK.init();
136+
}
137+
138+
// Because we installed the SDK, at this point we have an access to TraceKit's handler,
139+
// which can take care of browser differences (eg. missing exception argument in onerror)
140+
var tracekitErrorHandler = _window[_onerror];
141+
var tracekitUnhandledRejectionHandler = _window[_onunhandledrejection];
142+
143+
// And now capture all previously caught exceptions
144+
for (var i = 0; i < data.length; i++) {
145+
if ('e' in data[i] && tracekitErrorHandler) {
146+
tracekitErrorHandler.apply(_window, data[i].e);
147+
} else if ('p' in data[i] && tracekitUnhandledRejectionHandler) {
148+
tracekitUnhandledRejectionHandler.apply(_window, [data[i].p]);
149+
}
150+
}
151+
} catch (o_O) {
152+
console.error(o_O);
153+
}
154+
}
155+
156+
// We make sure we do not overwrite window.Sentry since there could be already integrations in there
157+
_window[_namespace] = _window[_namespace] || {};
158+
159+
_window[_namespace].onLoad = function (callback) {
160+
onLoadCallbacks.push(callback);
161+
if (lazy && !forceLoad) {
162+
return;
163+
}
164+
injectSdk(onLoadCallbacks);
165+
};
166+
167+
_window[_namespace].forceLoad = function() {
168+
forceLoad = true;
169+
if (lazy) {
170+
setTimeout(function() {
171+
injectSdk(onLoadCallbacks);
172+
});
173+
}
174+
};
175+
176+
177+
[
178+
'init',
179+
'addBreadcrumb',
180+
'captureMessage',
181+
'captureException',
182+
'captureEvent',
183+
'configureScope',
184+
'withScope',
185+
'showReportDialog'
186+
].forEach(function(f) {
187+
_window[_namespace][f] = function() {
188+
queue({ f: f, a: arguments });
189+
};
190+
});
191+
192+
// Store reference to the old `onerror` handler and override it with our own function
193+
// that will just push exceptions to the queue and call through old handler if we found one
194+
var _oldOnerror = _window[_onerror];
195+
_window[_onerror] = function(message, source, lineno, colno, exception) {
196+
// Use keys as "data type" to save some characters"
197+
queue({
198+
e: [].slice.call(arguments)
199+
});
200+
201+
if (_oldOnerror) _oldOnerror.apply(_window, arguments);
202+
};
203+
204+
// Do the same store/queue/call operations for `onunhandledrejection` event
205+
var _oldOnunhandledrejection = _window[_onunhandledrejection];
206+
_window[_onunhandledrejection] = function(e) {
207+
queue({
208+
p: 'reason' in e ? e.reason : 'detail' in e && 'reason' in e.detail ? e.detail.reason : e
209+
});
210+
if (_oldOnunhandledrejection) _oldOnunhandledrejection.apply(_window, arguments);
211+
};
212+
213+
if (!lazy) {
214+
setTimeout(function () {
215+
injectSdk(onLoadCallbacks);
216+
});
217+
}
218+
})(window, document, 'script', 'onerror', 'onunhandledrejection', 'Sentry', 'loader.js', '/base/artifacts/sdk.js', {
219+
dsn: 'https://[email protected]/1'
220+
});

0 commit comments

Comments
 (0)