It seems that the Stripe JavaScript is adding nearly 1/2 a second of main-thread blocking to my site. According to the Stripe documentation, it's totally fine to either async or defer their JS. In fact, they say that if you include it through npm it does this automatically. This is probably what I would have done if I were implementing this on my own, but I'm using Stripe through a WordPress plugin that, whatever they're doing, is pulling the Stripe JS in through an iFrame, and not setting async:
<iframe name="__privateStripeController5481" ...>
<!DOCTYPE html>
<html lang="en">
<head>
<script src="https://js.stripe.com/v3/fingerprinted/js/shared-0950781806f615c0693abdcbbb4bfc19.js"></script>
<script src="https://js.stripe.com/v3/fingerprinted/js/controller-842819e3871bc12ac5b51fa16b375c03.js"></script>
</head>
<body></body>
</html>
</iframe>
I'm thinking there should be some way to fix this, without waiting on the plugin developers to do it on their own. My idea is to do something like:
document.getElementById('ifrm').onload = function() {
const ifrm = document.getElementById('ifrm');
const scripts = ifrm.contentDocument?
ifrm.contentDocument: ifrm.contentWindow.document.getElementsByTagName('script');
for (const element of scripts) {
element.hasAttribute('async') ? {} : element.setAttribute('async', '');
}
};
But onload, will, I'm pretty sure, be way too late. Is there a way to accomplish this modification such that it happens early enough that the scripts in the iFrame end up being non-blocking?
No, you can't change how the script tag is processed after the browser has read it from the HTML and started processing it. (Not least because your page and the iframe are running on the same one main UI thread — the very thread being blocked by that script tag.)
You'll have to modify the plugin's code. (And perhaps do a PR to get it adopted by the plugin project maintainers.)