elbywan/yett

`onload` not fired on blocked scripts

jeanfredrik opened this issue · 3 comments

The load event doesn’t seem to fire on blocked script tags created with document.createElement in Chrome.

Reproduction:

<!DOCTYPE html>
<html>
  <head>
    <script>
      window.YETT_BLACKLIST = [/jquery/];
    </script>
    <script src="https://unpkg.com/yett"></script>
    <script>
      let scriptEl = document.createElement('script');
      scriptEl.src = 'https://code.jquery.com/jquery-3.5.1.slim.min.js';
      scriptEl.onload = function () {
        console.log('Loaded');
        console.log(window.jQuery);
      };
      document.head.appendChild(scriptEl);
    </script>
  </head>
  <body>
    <button onclick="window.yett.unblock();">Unblock</button>
  </body>
</html>

I expect "Loaded" and the value of window.jQuery to show in the console, but nothing happens. Preferably it should fire after the script has been loaded and executed.

Ok, so the problem is that the script element node is cloned before it’s added to the backup list. cloneNode won’t clone event listeners, and from what I can tell there’s no way to clone with event listeners in JS. Is it necessary to store a clone of the element since it’s also removed from the DOM?

https://github.com/snipsco/yett/blob/c65c516dfcd3f1d61a8b883848e40073b1f658a4/src/observer.js#L17

Hi @jeanfredrik, thanks for reporting this!

Is it necessary to store a clone of the element since it’s also removed from the DOM?

Yes, for multiple reasons:

  • First, we are mutating the original DOM node by changing the type and adding a firefox-specific event listener.
  • Then, Firefox will not download an HTMLScriptElement that has been inserted more than once inside a document.

So it won't be possible to remove the cloneNode() function, but keeping the event listeners is just a matter of copying the right object properties to the new node.

I just released yett v0.1.13 containing the fix 📦 .

Thanks for the quick fix! Works great!