Trying to improve my score on Lighthouse and the general performance of a site. The official docs about including stripe.js mention (emphasis mine):
To best leverage Stripe’s advanced fraud functionality, include this script on every page, not just the checkout page. This allows Stripe to detect suspicious behavior that may be indicative of fraud as customers browse your website.
Which is understandable but means that, without async
/defer
, the script slows down the page slightly (by ~190 ms in my tests) on a majority of pages that barely use it.
And:
You can also load Stripe.js using the
async
ordefer
attribute on the script tag. Note, however, that with asynchronous loading any API calls will have to be made only after the script execution has finished.
This leaves me with the following questions:
- How can I check whether stripe.js has finished executing?
async
ordefer
? i.e. is stripe.js completely independent (async), or does it depend on the DOM being fully built (defer)?- Rather than check if stripe.js has finished executing, maybe I should just move my own, inline, Stripe code (for a checkout page) into its own dedicated JS file, loaded as defer. This way things would load in a non-blocking way, and would still execute in their relative order.
CodePudding user response:
If using an npm module isn't your case for asynchronous loading, you can check for the Stripe function before initializing Stripe.js. Something like this:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8">
<title></title>
<script defer src="https://js.stripe.com/v3/"></script>
</head>
<body>
<script type="text/javascript">
try {
console.log("The first attempt to access Stripe: " Stripe.version);
} catch (e) {
console.log("Stripe is not ready.");
}
stripeScriptElement = document.querySelector("script[src^='https://js.stripe.com/v3']");
if (stripeScriptElement) {
stripeScriptElement.addEventListener("load", () => {
if (Stripe) {
console.log("Stripe v." Stripe.version " is ready. ");
} else {
console.error("Failed loading Stripe.js");
}
});
}
</script>
</body>
</html>
CodePudding user response:
In a React environment I initialize as below:
import { loadStripe } from "@stripe/stripe-js";
export let stripe = null;
export let stripe_started = false;
export let stripe_running = false;
(async () => {
try {
stripe = await loadStripe("pk_test_****");
stripe_running = true;
} catch (err) {
stripe_running = false;
} finally {
stripe_started = true;
}
})();
any module that imports this one has access to the flags; the closure allows the function to run async at top level.