Javascript methods are not working after bugsnag load

Highlighted
Shopify Partner
4 0 1

Hello,

I have some weird issue on theme development.
I'm using some setTimeout / requestAnimationFrame methods. 

Native javascript behavior are working before Bugsnag is loaded.
I investigate into bugsnag source code and it seems they override some native javascript method. 
Once Bugsnag is loaded, setTimeout / requestAnimationFrame callbacks are never called. 

I already open an issue on bugsnag js repository :https://github.com/bugsnag/bugsnag-js/issues/850

Does anyone have similar issue or fixed ?

0 Likes
Highlighted
New Member
3 0 0

I have the same error, but nobody gives answer. How to remove bugsnag from product page? Or, please, fix it.

0 Likes
Highlighted
Shopify Partner
4 0 1

Hello, 

The only solution I made for now is to block the loading of bugsnag during page load.

Unfortunately,  Shopify development team doesn't want to investigate on this because the issue is on Bugsnag side for them... 

So you can use the following as workaround for now. 

Hope that helps 

const needsToBeBlacklisted = (src) => src.includes('bugsnag.min.js')

const observer = new MutationObserver(mutations => {
  mutations.forEach(({ addedNodes }) => {
    addedNodes.forEach(node => {
      // For each added script tag
      if (needsToBeBlacklisted(node.src || '')) {
        node.type = 'javascript/blocked'

        // Firefox has this additional event which prevents scripts from beeing executed
        const beforeScriptExecuteListener = function (event) {
          // Prevent only marked scripts from executing
          if (node.getAttribute('type') === 'javascript/blocked') { event.preventDefault() }
          node.removeEventListener('beforescriptexecute', beforeScriptExecuteListener)
        }
        node.addEventListener('beforescriptexecute', beforeScriptExecuteListener)
      }
    })
  })
})
observer.observe(document.documentElement, {
  childList: true,
  subtree: true
})
const scriptBlocker = () => {
  const createElementBackup = document.createElement
  document.createElement = function (...args) {
    // If this is not a script tag, bypass
    if (args[0].toLowerCase() !== 'script') {
      return createElementBackup.bind(document)(...args)
    }

    const scriptElt = createElementBackup.bind(document)(...args)
    const originalSetAttribute = scriptElt.setAttribute.bind(scriptElt)

    // Define getters / setters to ensure that the script type is properly set
    Object.defineProperties(scriptElt, {
      src: {
        get () {
          return scriptElt.getAttribute('src')
        },
        set (value) {
          if (needsToBeBlacklisted(value || '', scriptElt.type)) {
            originalSetAttribute('type', 'javascript/blocked')
          }
          originalSetAttribute('src', value)
          return true
        }
      },
      // eslint-disable-next-line accessor-pairs
      type: {
        set (value) {
          const typeValue =
            needsToBeBlacklisted(scriptElt.src || '', scriptElt.type)
              ? 'javascript/blocked'
              : value
          originalSetAttribute('type', typeValue)
          return true
        }
      }
    })

    // Monkey patch the setAttribute function so that the setter is called instead.
    // Otherwise, setAttribute('type', 'whatever') will bypass our custom descriptors!
    if (scriptElt) {
      scriptElt.setAttribute = function (name, value) {
        if (name === 'type' || name === 'src') {
          scriptElt[name] = value
        } else {
          HTMLScriptElement.prototype.setAttribute.call(scriptElt, name, value)
        }
      }
      return scriptElt
    }
  }
}
scriptBlocker()
Highlighted

Thanks @Antonin I was having so much trouble with this since it didn't show up until video content was chosen for the page.

0 Likes