Yesterday I tweeted this question out to the world:
Only one person liked it. Maybe Twitter isn't the best forum for that question. Or maybe the character limit made it unclear what I meant. Or maybe I don't have enough followers for the tweet to get any traction....
I thought it was a good question though.
Here's the question worded more clearly:
How would you go about bringing in a script from a third-party into a Vue component? And then making sure the script is there before performing logic on something brought in by the script?
I was able to do this one way, but I'm curious if there are other approaches.
Here's an example scenario and my solution.
Scenario: Load Google Recaptcha API and Perform Action if API has Loaded
This is an example for the sake of showing how to do this, but it could be applied to anytime you need to load a JS script into your component and wait until after it has loaded to perform some action.
The example is a Recaptcha checkmark to verify that the user is not a robot.
Step 1: Load the Script in the setup function
First, create a script element using Vanilla JS document.createElement
and setAttribute
with "src" set to the script source url. Then use appendChild
to append that element do the document head.:
export default {
setup() {
const recaptchaScript = document.createElement("script");
recaptchaScript.setAttribute(
"src",
"https://www.google.com/recaptcha/api.js"
);
document.head.appendChild(recaptchaScript);
}
In Vue 3, the setup
function runs before anything else, so we can create the script
element at the very start of the component lifecycle. That ensures the script is there as soon as possible.
In Vue 2, this would be equivalent to building out the script
element in the create
lifecycle hook. There is a stack overflow question that shows how to do this in Vue 2.
Step 2: Use setInterval to check that the script has fully loaded
Create a variable to keep track of the state of the script being loaded. Set it to false to start.
let recaptchaScriptIsReady = false;
Write a function using setInterval to continuously run, checking that the script is loaded:
let checkInterval = setInterval(function () {
if (grecaptcha) {
recaptchaScriptIsReady = true;
clearInterval(checkInterval);
grecaptcha.ready(function () {
grecaptcha.render("g-recaptcha", {
sitekey: "YOUR API KEY",
});
});
}
return recaptchaScriptIsReady;
}, 500);
Notice that inside the function, the clearInterval
takes in the named function checkInterval
, which stops the setInterval
from continuing to run. Here's the line of code I'm talking about:
clearInterval(checkInterval);
So basically, to solve this problem, I create the variable recaptchaScriptIsReady
to track the state of the script that is loading, then use the if-check to make sure the script is now there, set the recaptchaScriptIsReady
to true
which now opens the gate to allowing the next part of the code to run, the code that is dependent upon the original script being loaded.
Do you have a different way to do this? I would be really interested to know! Please tell me in the comments!
And please follow me on Twitter! I hope this post was helpful to someone.
Recaptcha resource: https://developers.google.com/recaptcha
Top comments (6)
checkout vue-meta package. you can specify script and give it a callback.
I just took a look. Looks like an easy way to bring in a script to specific component. Thanks for the suggestion!
Why not use onload ? demo
I didn't use onload because I'm still learning this stuff and I didn't think to use it. I know that there are better ways of doing this so I was hoping to get some ideas from people out there.
This is awesome, thanks!
@t_pavard Thanks for the demo,
I am trying to replicate an issue in sfc vue playground
Is there any more convenient way for using packages there? I don't mind if it is cdn or npm.
If I was to add content inside the script tag and not as an attribute, could I still use the onMounted() / setup method? Sorry if I'm wording it wrong.