amplitude/Amplitude-TypeScript

"Types" property not available in browser SDK before main library loads

salomoneb opened this issue · 0 comments

Expected Behavior

amplitude.Types should be immediately defined after the browser SDK snippet is inserted. Example:

<script type="text/javascript">
!function(){"use strict";!function(e,t){var r=e.amplitude||{_q:[],_iq:{}};if(r.invoked)e.console&&console.error&&console.error("Amplitude snippet has been loaded.");else{var n=function(e,t){e.prototype[t]=function(){return this._q.push({name:t,args:Array.prototype.slice.call(arguments,0)}),this}},s=function(e,t,r){return function(n){e._q.push({name:t,args:Array.prototype.slice.call(r,0),resolve:n})}},o=function(e,t,r){e._q.push({name:t,args:Array.prototype.slice.call(r,0)})},i=function(e,t,r){e[t]=function(){if(r)return{promise:new Promise(s(e,t,Array.prototype.slice.call(arguments)))};o(e,t,Array.prototype.slice.call(arguments))}},a=function(e){for(var t=0;t<g.length;t++)i(e,g[t],!1);for(var r=0;r<m.length;r++)i(e,m[r],!0)};r.invoked=!0;var c=t.createElement("script");c.type="text/javascript",c.integrity="sha384-Dv01ylQWH3OMRpOnXgNXTEJypJSg/Si512H2KxfFik12c676LxjHoC1W2pF8xyR5",c.crossOrigin="anonymous",c.async=!0,c.src="https://cdn.amplitude.com/libs/analytics-browser-2.6.0-min.js.gz",c.onload=function(){e.amplitude.runQueuedFunctions||console.log("[Amplitude] Error: could not load SDK")};var u=t.getElementsByTagName("script")[0];u.parentNode.insertBefore(c,u);for(var p=function(){return this._q=[],this},l=["add","append","clearAll","prepend","set","setOnce","unset","preInsert","postInsert","remove","getUserProperties"],d=0;d<l.length;d++)n(p,l[d]);r.Identify=p;for(var f=function(){return this._q=[],this},v=["getEventProperties","setProductId","setQuantity","setPrice","setRevenue","setRevenueType","setEventProperties"],y=0;y<v.length;y++)n(f,v[y]);r.Revenue=f;var g=["getDeviceId","setDeviceId","getSessionId","setSessionId","getUserId","setUserId","setOptOut","setTransport","reset","extendSession"],m=["init","add","remove","track","logEvent","identify","groupIdentify","setGroup","revenue","flush"];a(r),r.createInstance=function(e){return r._iq[e]={_q:[]},a(r._iq[e]),r._iq[e]},e.amplitude=r}}(window,document)}(); // eslint-disable-line

console.log(amplitude) // typeof amplitude.Types should not equal undefined

amplitude.init("<YOUR_API_KEY>");
</script>

Current Behavior

amplitude.Types is undefined right below the browser SDK snippet and remains undefined until the Amplitude library injected by the snippet is loaded. My team discovered this when we tried to do something like:

const configOptions = {
  logLevel: window.amplitude.Types.LogLevel[<string passed in through env variable, e.g. "Debug">],
  defaultTracking: false,
};

amplitude.init(<key>, null, configOptions);

Our code fails the first (and only the first) time this runs. This seems to be because the amplitude object properties are stubbed prior to the Amplitude library loading. However, the Types property does not appear to stubbed with the other expected properties.

On subsequent page loads, our code runs fine because the browser has cached the Amplitude library script (which loaded on the previous page load) and the amplitude object is fully hydrated immediately.

Possible Solution

Stub Types in amplitude-snippet.js so that the property is available before the library loads.

Steps to Reproduce

  1. In a clean Chrome browser profile (it's important that you're in a window where the Amplitude library file hasn't been cached), add the following code:
<script type="text/javascript">
!function(){"use strict";!function(e,t){var r=e.amplitude||{_q:[],_iq:{}};if(r.invoked)e.console&&console.error&&console.error("Amplitude snippet has been loaded.");else{var n=function(e,t){e.prototype[t]=function(){return this._q.push({name:t,args:Array.prototype.slice.call(arguments,0)}),this}},s=function(e,t,r){return function(n){e._q.push({name:t,args:Array.prototype.slice.call(r,0),resolve:n})}},o=function(e,t,r){e._q.push({name:t,args:Array.prototype.slice.call(r,0)})},i=function(e,t,r){e[t]=function(){if(r)return{promise:new Promise(s(e,t,Array.prototype.slice.call(arguments)))};o(e,t,Array.prototype.slice.call(arguments))}},a=function(e){for(var t=0;t<g.length;t++)i(e,g[t],!1);for(var r=0;r<m.length;r++)i(e,m[r],!0)};r.invoked=!0;var c=t.createElement("script");c.type="text/javascript",c.integrity="sha384-Dv01ylQWH3OMRpOnXgNXTEJypJSg/Si512H2KxfFik12c676LxjHoC1W2pF8xyR5",c.crossOrigin="anonymous",c.async=!0,c.src="https://cdn.amplitude.com/libs/analytics-browser-2.6.0-min.js.gz",c.onload=function(){e.amplitude.runQueuedFunctions||console.log("[Amplitude] Error: could not load SDK")};var u=t.getElementsByTagName("script")[0];u.parentNode.insertBefore(c,u);for(var p=function(){return this._q=[],this},l=["add","append","clearAll","prepend","set","setOnce","unset","preInsert","postInsert","remove","getUserProperties"],d=0;d<l.length;d++)n(p,l[d]);r.Identify=p;for(var f=function(){return this._q=[],this},v=["getEventProperties","setProductId","setQuantity","setPrice","setRevenue","setRevenueType","setEventProperties"],y=0;y<v.length;y++)n(f,v[y]);r.Revenue=f;var g=["getDeviceId","setDeviceId","getSessionId","setSessionId","getUserId","setUserId","setOptOut","setTransport","reset","extendSession"],m=["init","add","remove","track","logEvent","identify","groupIdentify","setGroup","revenue","flush"];a(r),r.createInstance=function(e){return r._iq[e]={_q:[]},a(r._iq[e]),r._iq[e]},e.amplitude=r}}(window,document)}(); // eslint-disable-line

console.log(amplitude);
debugger;
amplitude.init("<YOUR_API_KEY>");

</script>
  1. When debugger pauses script execution, take a look at the amplitude object in the console. You should see something like:

Screenshot 2024-03-29 at 3 59 48 PM

Notice that Types is not defined.

  1. Wait a few seconds and/or refresh your page, and type amplitude into the devtools console. Types should now be defined on the amplitude object.

Environment

  • JS SDK Version: 2.6.0
  • Installation Method: script loader
  • Browser and Version: Chrome 123.0.6312.87