323

I've to use two external scripts for the payment gateways.

Right now both are put in the index.html file.

However, I don't want to load these files at the beginning itself.

The payment gateway is needed only in when user open a specific component (using router-view).

Is there anyway to achieve this?

Thanks.

Jerry Chong
9,4504 gold badges54 silver badges44 bronze badges
asked Jul 12, 2017 at 2:02
0

24 Answers 24

485

A simple and effective way to solve this, it's by adding your external script into the vue mounted() of your component. I will illustrate you with the Google Recaptcha script:

<template>
 .... your HTML
</template>
<script>
 export default {
 data: () => ({
 ......data of your component
 }),
 mounted() {
 let recaptchaScript = document.createElement('script')
 recaptchaScript.setAttribute('src', 'https://www.google.com/recaptcha/api.js')
 document.head.appendChild(recaptchaScript)
 },
 methods: {
 ......methods of your component
 }
 }
</script>

Source: https://medium.com/@lassiuosukainen/how-to-include-a-script-tag-on-a-vue-component-fe10940af9e8

Narendra Jadhav
10.3k15 gold badges35 silver badges45 bronze badges
answered Oct 29, 2017 at 16:59
Sign up to request clarification or add additional context in comments.

9 Comments

created() method can not get document, use mounted() instead
Using variables defined by the script afterwards, even with defer set to false, doesn't work. Example: load api.mapbox.com/mapbox-gl-js/v1.11.1/mapbox-gl.js mapboxgl.accessToken = 123. Had to use vue-plugin-load-script .then() for this to work.
This is a good way to include external libraries that you don't control and can't include directly. To access constructors and functions within them, without the Vue compiler complaining, see stackoverflow.com/a/62617268/917444
Hello! I tried this solution. I want to load a script from project src/assets/js/ folder but it has error uncaught SyntaxError: Unexpected token '<'. But when I try to load from CDN it has no error. I am new to Vue and I used vue-cli to create the project. TIA
@marius you should add an onLoad event listener and event handler to that script. Meaning a function that runs when that scripts onLoad event triggers.
|
68

I have downloaded some HTML template that comes with custom js files and jquery. I had to attach those js to my app. and continue with Vue.

This package works perfectly for me in this case https://www.npmjs.com/package/vue-plugin-load-script

// local files
// you have to put your scripts into the public folder. 
// that way webpack simply copy these files as it is.
Vue.loadScript("/js/jquery-2.2.4.min.js")
// cdn
Vue.loadScript("https://maps.googleapis.com/maps/api/js")
answered Jan 2, 2019 at 6:42

3 Comments

What file would this Vue.loadScript() be located in? Is the the App.vue file?
Probably in main.js file
likely app.js/main.js/main.ts depending on if you're using javascript or typescript.
43

using webpack and vue loader you can do something like this

it waits for the external script to load before creating the component, so globar vars etc are available in the component

components: {
 SomeComponent: () => {
 return new Promise((resolve, reject) => {
 let script = document.createElement('script')
 script.onload = () => {
 resolve(import(someComponent))
 }
 script.async = true
 script.src = 'https://maps.googleapis.com/maps/api/js?key=APIKEY&libraries=places'
 document.head.appendChild(script)
 })
 }
},
Erich
2,66623 silver badges46 bronze badges
answered Dec 15, 2017 at 17:57

3 Comments

>> "Where do you place this code?" : It is in components section in your vuejs component.
What if you have to use this component several times? You will have script loaded multiple times. In case of google scripts it will throw warnings in your console.
Can you explain what's going on with import(someComponent)? Does the script you're loading have to be defined as an es module? Does this not work if you are importing a script that attaches itself to window?
34

UPDATE: This no longer works in Vue 3. You will receive this error:

VueCompilerError: Tags with side effect ( and ) are ignored in client component templates.


If you are trying to embed external js scripts to the vue.js component template, follow below:

I wanted to add a external JavaScript embed code to my component like this:

<template>
 <div>
 This is my component
 <script src="https://badge.dimensions.ai/badge.js"></script>
 </div>
<template>

And Vue showed me this error:

Templates should only be responsible for mapping the state to the UI. Avoid placing tags with side-effects in your templates, such as , as they will not be parsed.


The way I solved it was by adding type="application/javascript" (See this question to learn more about MIME type for js):

<script type="application/javascript" defer src="..."></script>


You may notice the defer attribute. If you want to learn more watch this video by Kyle

kissu
47.3k16 gold badges94 silver badges197 bronze badges
answered Feb 21, 2020 at 19:56

3 Comments

Works great, thanks! Additional tip with Webpack: require('module-name/file-name.js')
Thanks! I have a MVC app that I was trying to send some data from Razor page to vue (but outside the layout defined for vue app). This solution worked for me when I changed type of the script, I am using vue 2.
This didn't work for me using Vite - [vite] Internal server error: Tags with side effect (<script> and <style>) are ignored in client component templates.
26

This can be simply done like this.

 created() {
 var scripts = [
 "https://cloudfront.net/js/jquery-3.4.1.min.js",
 "js/local.js"
 ];
 scripts.forEach(script => {
 let tag = document.createElement("script");
 tag.setAttribute("src", script);
 document.head.appendChild(tag);
 });
 }
answered Feb 17, 2020 at 7:48

2 Comments

Side-question: Does it make sense to add the attribute "defer"? I guess not because the website is already loaded, but maybe it still makes sense... Any idea?
@PhilippMochine You are right, adding defer will not affect initial pageload since we load the js file during vue's created event which by that time already done loading the page.
18

A fast and easy way that i found to do it is like this:

<template>
 <div>Some HTML</div>
 <component
 src="https://unpkg.com/[email protected]/dist/flowbite.js"
 :is="'script'"
 ></component>
</template>
answered Dec 12, 2022 at 13:21

1 Comment

This is great but if you need to access properties defined in said script then sometimes onMounted runs before and by then they are still undefined
14

With Vue 3, I use mejiamanuel57 answer with an additional check to ensure the script tag hasn't been loaded already.

 mounted() {
 const scripts = [
 "js/script1.js",
 "js/script2.js"
 ];
 scripts.forEach(script => {
 let tag = document.head.querySelector(`[src="${ script }"`);
 if (!tag) {
 tag = document.createElement("script");
 tag.setAttribute("src", script);
 tag.setAttribute("type", 'text/javascript');
 document.head.appendChild(tag); 
 }
 });
 // ...
answered Dec 24, 2021 at 7:26

Comments

11

You can use the vue-head package to add scripts, and other tags to the head of your vue component.

Its as simple as:

var myComponent = Vue.extend({
 data: function () {
 return {
 ...
 }
 },
 head: {
 title: {
 inner: 'It will be a pleasure'
 },
 // Meta tags
 meta: [
 { name: 'application-name', content: 'Name of my application' },
 { name: 'description', content: 'A description of the page', id: 'desc' }, // id to replace intead of create element
 // ...
 // Twitter
 { name: 'twitter:title', content: 'Content Title' },
 // with shorthand
 { n: 'twitter:description', c: 'Content description less than 200 characters'},
 // ...
 // Google+ / Schema.org
 { itemprop: 'name', content: 'Content Title' },
 { itemprop: 'description', content: 'Content Title' },
 // ...
 // Facebook / Open Graph
 { property: 'fb:app_id', content: '123456789' },
 { property: 'og:title', content: 'Content Title' },
 // with shorthand
 { p: 'og:image', c: 'https://example.com/image.jpg' },
 // ...
 ],
 // link tags
 link: [
 { rel: 'canonical', href: 'http://example.com/#!/contact/', id: 'canonical' },
 { rel: 'author', href: 'author', undo: false }, // undo property - not to remove the element
 { rel: 'icon', href: require('./path/to/icon-16.png'), sizes: '16x16', type: 'image/png' }, 
 // with shorthand
 { r: 'icon', h: 'path/to/icon-32.png', sz: '32x32', t: 'image/png' },
 // ...
 ],
 script: [
 { type: 'text/javascript', src: 'cdn/to/script.js', async: true, body: true}, // Insert in body
 // with shorthand
 { t: 'application/ld+json', i: '{ "@context": "http://schema.org" }' },
 // ...
 ],
 style: [
 { type: 'text/css', inner: 'body { background-color: #000; color: #fff}', undo: false },
 // ...
 ]
 }
})

Check out this link for more examples.

answered Jan 27, 2019 at 5:49

1 Comment

I know Vue head but thanks for the detailed example containing schema and social network props! quite useful
11

You can load the script you need with a promise based solution:

export default {
 data () {
 return { is_script_loading: false }
 },
 created () {
 // If another component is already loading the script
 this.$root.$on('loading_script', e => { this.is_script_loading = true })
 },
 methods: {
 load_script () {
 let self = this
 return new Promise((resolve, reject) => {
 // if script is already loading via another component
 if ( self.is_script_loading ){
 // Resolve when the other component has loaded the script
 this.$root.$on('script_loaded', resolve)
 return
 }
 let script = document.createElement('script')
 script.setAttribute('src', 'https://www.google.com/recaptcha/api.js')
 script.async = true
 
 this.$root.$emit('loading_script')
 script.onload = () => {
 /* emit to global event bus to inform other components
 * we are already loading the script */
 this.$root.$emit('script_loaded')
 resolve()
 }
 document.head.appendChild(script)
 })
 },
 
 async use_script () {
 try {
 await this.load_script()
 // .. do what you want after script has loaded
 } catch (err) { console.log(err) }
 }
 }
}

Please note that this.$root is a little hacky and you should use a vuex or eventHub solution for the global events instead.

You would make the above into a component and use it wherever needed, it will only load the script when used.

NOTE: This is a Vue 2.x based solution. Vue 3 has stopped supporting $on.

tony19
140k24 gold badges281 silver badges354 bronze badges
answered Apr 18, 2018 at 7:14

Comments

8

Are you using one of the Webpack starter templates for vue (https://github.com/vuejs-templates/webpack)? It already comes set up with vue-loader (https://github.com/vuejs/vue-loader). If you're not using a starter template, you have to set up webpack and vue-loader.

You can then import your scripts to the relevant (single file) components. Before that, you have toexport from your scripts what you want to import to your components.

ES6 import:
- https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Statements/import
- http://exploringjs.com/es6/ch_modules.html

~Edit~
You can import from these wrappers:
- https://github.com/matfish2/vue-stripe
- https://github.com/khoanguyen96/vue-paypal-checkout

answered Jul 12, 2017 at 3:54

2 Comments

These scripts are from paypal and stripe. I can't download the put the file locally
7

The top answer of create tag in mounted is good, but it has some problems: If you change your link multiple times, it will repeat create tag over and over.

So I created a script to resolve this, and you can delete the tag if you want.

It's very simple, but can save your time to create it by yourself.

// PROJECT/src/assets/external.js
function head_script(src) {
 if(document.querySelector("script[src='" + src + "']")){ return; }
 let script = document.createElement('script');
 script.setAttribute('src', src);
 script.setAttribute('type', 'text/javascript');
 document.head.appendChild(script)
}
function body_script(src) {
 if(document.querySelector("script[src='" + src + "']")){ return; }
 let script = document.createElement('script');
 script.setAttribute('src', src);
 script.setAttribute('type', 'text/javascript');
 document.body.appendChild(script)
}
function del_script(src) {
 let el = document.querySelector("script[src='" + src + "']");
 if(el){ el.remove(); }
}
function head_link(href) {
 if(document.querySelector("link[href='" + href + "']")){ return; }
 let link = document.createElement('link');
 link.setAttribute('href', href);
 link.setAttribute('rel', "stylesheet");
 link.setAttribute('type', "text/css");
 document.head.appendChild(link)
}
function body_link(href) {
 if(document.querySelector("link[href='" + href + "']")){ return; }
 let link = document.createElement('link');
 link.setAttribute('href', href);
 link.setAttribute('rel', "stylesheet");
 link.setAttribute('type', "text/css");
 document.body.appendChild(link)
}
function del_link(href) {
 let el = document.querySelector("link[href='" + href + "']");
 if(el){ el.remove(); }
}
export {
 head_script,
 body_script,
 del_script,
 head_link,
 body_link,
 del_link,
}

And you can use it like this:

// PROJECT/src/views/xxxxxxxxx.vue
......
<script>
 import * as external from '@/assets/external.js'
 export default {
 name: "xxxxxxxxx",
 mounted(){
 external.head_script('/assets/script1.js');
 external.body_script('/assets/script2.js');
 external.head_link('/assets/style1.css');
 external.body_link('/assets/style2.css');
 },
 destroyed(){
 external.del_script('/assets/script1.js');
 external.del_script('/assets/script2.js');
 external.del_link('/assets/style1.css');
 external.del_link('/assets/style2.css');
 },
 }
</script>
......
answered Jun 19, 2019 at 12:22

1 Comment

Once a script is loaded it is already in memory. Removing it from the dom does not remove its footprint.
6

Simplest solution is to add the script in the index.html file of your vue-project

index.html:

<!DOCTYPE html>
<html lang="en">
 <head>
 <meta charset="utf-8">
 <title>vue-webpack</title>
 </head>
 <body>
 <div id="app"></div>
 <!-- start Mixpanel --><script type="text/javascript">(function(c,a){if(!a.__SV){var b=window;try{var d,m,j,k=b.location,f=k.hash;d=function(a,b){return(m=a.match(RegExp(b+"=([^&]*)")))?m[1]:null};f&&d(f,"state")&&(j=JSON.parse(decodeURIComponent(d(f,"state"))),"mpeditor"===j.action&&(b.sessionStorage.setItem("_mpcehash",f),history.replaceState(j.desiredHash||"",c.title,k.pathname+k.search)))}catch(n){}var l,h;window.mixpanel=a;a._i=[];a.init=function(b,d,g){function c(b,i){var a=i.split(".");2==a.length&&(b=b[a[0]],i=a[1]);b[i]=function(){b.push([i].concat(Array.prototype.slice.call(arguments,
 0)))}}var e=a;"undefined"!==typeof g?e=a[g]=[]:g="mixpanel";e.people=e.people||[];e.toString=function(b){var a="mixpanel";"mixpanel"!==g&&(a+="."+g);b||(a+=" (stub)");return a};e.people.toString=function(){return e.toString(1)+".people (stub)"};l="disable time_event track track_pageview track_links track_forms track_with_groups add_group set_group remove_group register register_once alias unregister identify name_tag set_config reset opt_in_tracking opt_out_tracking has_opted_in_tracking has_opted_out_tracking clear_opt_in_out_tracking people.set people.set_once people.unset people.increment people.append people.union people.track_charge people.clear_charges people.delete_user people.remove".split(" ");
 for(h=0;h<l.length;h++)c(e,l[h]);var f="set set_once union unset remove delete".split(" ");e.get_group=function(){function a(c){b[c]=function(){call2_args=arguments;call2=[c].concat(Array.prototype.slice.call(call2_args,0));e.push([d,call2])}}for(var b={},d=["get_group"].concat(Array.prototype.slice.call(arguments,0)),c=0;c<f.length;c++)a(f[c]);return b};a._i.push([b,d,g])};a.__SV=1.2;b=c.createElement("script");b.type="text/javascript";b.async=!0;b.src="undefined"!==typeof MIXPANEL_CUSTOM_LIB_URL?
 MIXPANEL_CUSTOM_LIB_URL:"file:"===c.location.protocol&&"//cdn.mxpnl.com/libs/mixpanel-2-latest.min.js".match(/^\/\//)?"https://cdn.mxpnl.com/libs/mixpanel-2-latest.min.js":"//cdn.mxpnl.com/libs/mixpanel-2-latest.min.js";d=c.getElementsByTagName("script")[0];d.parentNode.insertBefore(b,d)}})(document,window.mixpanel||[]);
 mixpanel.init("xyz");
 </script><!-- end Mixpanel -->
 <script src="/dist/build.js"></script>
 </body>
</html>
Jerry Chong
9,4504 gold badges54 silver badges44 bronze badges
answered Jul 21, 2020 at 11:28

1 Comment

then how to use it inside Vue.js?
5

The answer from mejiamanuel57 is great, but I want to add a couple of tips that work in my case (I spent some hours on them). First, I needed to use the "window" scope. Also, if you need to access any Vue element inside the "onload" function, you need a new variable for the "this" instance.

<script>
import { mapActions } from "vuex";
export default {
 name: "Payment",
 methods: {
 ...mapActions(["aVueAction"])
 },
 created() {
 let paywayScript = document.createElement("script");
 let self = this;
 paywayScript.onload = () => {
 // call to Vuex action.
 self.aVueAction();
 // call to script function
 window.payway.aScriptFunction();
 };
 // paywayScript.async = true;
 paywayScript.setAttribute(
 "src",
 "https://api.payway.com.au/rest/v1/payway.js"
 );
 document.body.appendChild(paywayScript);
 }
};
</script>

I worked with this on Vue 2.6. Here there is an explanation about how the trick "let self = this;" works in Javascript:

What does 'var that = this;' mean in JavaScript?

answered Mar 15, 2021 at 10:13

Comments

5

If you're using Vue 3 and the Composition API (I highly recommend), and you're using <script> tags a lot, you can write a "composable" function for this:

import { onMounted } from "vue";
export const useScript = (src, async = false, defer = false) => {
 onMounted(() => {
 // check if script already exists
 if (document.querySelector(`head script[src="${src}"`)) return;
 // add tag to head
 const tag = document.createElement("script");
 tag.setAttribute("src", src);
 if (async) tag.setAttribute("async", "");
 if (defer) tag.setAttribute("defer", "");
 tag.setAttribute("type", "text/javascript");
 document.head.append(tag);
 });
};

OR, if you are using VueUse (I also highly recommend), you can use their existing useScriptTag function.

answered Aug 8, 2022 at 19:27

Comments

5

In Vue 3 you can use teleport to add a script to the head of the document. The script tag will then automatically be removed when the component is destroyed.

<template>
 ...
 <teleport to="head">
 <component
 :is="'script'"
 src="https://cdnjs.cloudflare.com/ajax/libs/mathjax/2.7.2/MathJax.js?config=TeX-AMS_HTML"
 async
 />
 </teleport>
 ...
<template>
answered Apr 3, 2024 at 10:52

Comments

4

To keep clean components you can use mixins.

On your component import external mixin file.

Profile.vue

import externalJs from '@client/mixins/externalJs';
export default{
 mounted(){
 this.externalJsFiles();
 }
}

externalJs.js

import('@JSassets/js/file-upload.js').then(mod => {
 // your JS elements 
})

babelrc (I include this, if any get stuck on import)

{
 "presets":["@babel/preset-env"],
 "plugins":[
 [
 "module-resolver", {
 "root": ["./"],
 alias : {
 "@client": "./client",
 "@JSassets": "./server/public",
 }
 }
 ]
}
answered Aug 30, 2019 at 7:33

Comments

4
mounted() {
 if (document.getElementById('myScript')) { return }
 let src = 'your script source'
 let script = document.createElement('script')
 script.setAttribute('src', src)
 script.setAttribute('type', 'text/javascript')
 script.setAttribute('id', 'myScript')
 document.head.appendChild(script)
}
beforeDestroy() {
 let el = document.getElementById('myScript')
 if (el) { el.remove() }
}
answered Jan 10, 2021 at 2:52

Comments

3

if you are using Vue.js 3, you can use useScriptTag from vue-use library to load external scripts in a simple way it gives you a simple and configurable Api to load, unload and use callback events

import { useScriptTag } from '@vueuse/core'
useScriptTag(
 'https://player.twitch.tv/js/embed/v1.js',
 // on script tag loaded.
 (el: HTMLScriptElement) => {
 // do something
 },
)
answered Feb 28, 2023 at 8:10

Comments

2

You can use vue-loader and code your components in their own files (Single file components). This will allow you to include scripts and css on a component basis.

kissu
47.3k16 gold badges94 silver badges197 bronze badges
answered Jul 12, 2017 at 2:31

3 Comments

These scripts are from paypal and stripe. I can't download the put the file locally
You can download the external scripts, view source, copy/paste in to your own file.
@minimallinux In the case of Stripe and Paypal, that will violate PCI-DSS. So don't do that.
1

well, this is my practice in qiokian (a live2d anime figure vuejs component):

(below is from the file src/qiokian.vue)

<script>
export default {
 data() {
 return {
 live2d_path:
 'https://cdn.jsdelivr.net/gh/knowscount/live2d-widget@latest/',
 cdnPath: 'https://cdn.jsdelivr.net/gh/fghrsh/live2d_api/',
 }
 },
<!-- ... -->
 loadAssets() {
 // load waifu.css live2d.min.js waifu-tips.js
 if (screen.width >= 768) {
 Promise.all([
 this.loadExternalResource(
 this.live2d_path + 'waifu.css',
 'css'
 ),
<!-- ... -->
 loadExternalResource(url, type) {
 // note: live2d_path parameter should be an absolute path
 // const live2d_path =
 // "https://cdn.jsdelivr.net/gh/knowscount/live2d-widget@latest/";
 //const live2d_path = "/live2d-widget/";
 return new Promise((resolve, reject) => {
 let tag
 if (type === 'css') {
 tag = document.createElement('link')
 tag.rel = 'stylesheet'
 tag.href = url
 } else if (type === 'js') {
 tag = document.createElement('script')
 tag.src = url
 }
 if (tag) {
 tag.onload = () => resolve(url)
 tag.onerror = () => reject(url)
 document.head.appendChild(tag)
 }
 })
 },
 },
}
answered Jun 16, 2021 at 11:04

Comments

0

There is a vue component for this usecase

https://github.com/TheDynomike/vue-script-component#usage

<template>
 <div>
 <VueScriptComponent script='<script type="text/javascript"> alert("Peekaboo!"); </script>'/>
 <div>
</template>
<script>
import VueScriptComponent from 'vue-script-component'
export default {
 ...
 components: {
 ...
 VueScriptComponent
 }
 ...
}
</script>
answered Sep 17, 2020 at 18:22

Comments

0

If you are attempting to utilize a variable that is defined within a JavaScript file that is being loaded asynchronously and you receive an 'undefined' error, it is likely because the script has not yet finished loading. To resolve this issue, you can utilize the onload function to ensure that the script has completed loading before attempting to access the variable. As an example:

const script = document.createElement(...) // set attribute and so on...
script.onload = () => {
 // do something with some variables/functions/logic from the loaded script
}
answered Jan 7, 2023 at 9:22

Comments

0

You can use the head property in vue to return a custom script


export default {
 head: {
 script: [{
 src: 'https://cdn.polygraph.net/pg.js',
 type: 'text/javascript'
 }]
 }
}
answered Feb 16, 2023 at 20:18

Comments

0
const plugin = document.createElement("script");
 plugin.setAttribute(
 "src",
 "src/assets/singup/js/singup.js"
 );
 plugin.async = true;
 document.head.appendChild(plugin);
answered Mar 24, 2024 at 17:49

Comments

Your Answer

Draft saved
Draft discarded

Sign up or log in

Sign up using Google
Sign up using Email and Password

Post as a guest

Required, but never shown

Post as a guest

Required, but never shown

By clicking "Post Your Answer", you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.