5

I'm using Webpack and VueJs 2. I want to use a 3rd party javascript library in my component, such as this:

<script async defer src="https://apis.google.com/js/api.js" ... ></script>

I found an article here about how to do this for npm packages, but that doesn't work for me since this library is not available as npm package.

It's not possible for me to download the file locally and use it since the library might change and stop working. Therefore it has to be loaded from the link every time the page is loaded by the browser.

I found one possible solution here but that is basically a hack(modify dom to add a script element after document is loaded)

I believe there must be a simple good practice solution for this issue since I assume this is a common use-case.

Update: If I put the script inside head tags in my index file, it would be loaded for all the components. For performance reasons, I would want it to be loaded only for a certain component.

6
  • Why don't you just include the script as seen in your example and instantiate it, if it needs to be .. inside the created/method hooks? Commented Mar 19, 2018 at 15:02
  • Why dont you put your script tag inside the <head> of your index.html file ? Commented Mar 19, 2018 at 15:03
  • @LoïcMonard see update Commented Mar 19, 2018 at 15:06
  • if you don't want to include it in your index file you can still include it inside a single component so it will only be loaded when that component is loaded Commented Mar 19, 2018 at 15:13
  • @samayo can you give an example how to do that? Commented Mar 19, 2018 at 15:15

2 Answers 2

7

As far as I know, there is no way you could use something better than adding the script tag into the head of your page dynamically. However, you could create a little plugin to handle that for you, and trigger the script loading only in the components you want, and just once.

Let's begin with the plugin itself:

import Vue from 'vue'

const scriptLoader = {
    loaded: [],
    load (src) {
        if (this.loaded.indexOf(src) !== -1) {
            return
        }

        this.loaded.push(src)

        if (document) {
            const script = document.createElement('script')
            script.setAttribute('src', src)
            document.head.appendChild(script)
        }
    }
}

Vue.use({
    install () {
        Vue.prototype.$scriptLoader = scriptLoader
    }
})

As you can see, you create an object scriptLoader that contains some sort of cache object loaded that will remember what script you already loaded at some point in your application. It also contains a load() method that will handle the adding of the script into your head.

The condition if (document) is here in case you would server side render your app, document would not exist.

You could then load your script into any of your component at creation using the created hook:

export default {
    ...
    created () {
        this.$scriptLoader.load('https://apis.google.com/js/api.js')
    }
}

This is the cleanest way I came with to handle that kind of script... I hope this can help...

Sign up to request clarification or add additional context in comments.

Comments

1

Ok, found a solution that satisfies all the requirements.

  • Script is downloaded from web, no npm package is needed
  • Script is only loaded for certain components when needed
  • No ugly dom-manipulation

Add the script inside index.html with v-if directive

<script v-if="loadGoogleAPI" async defer src="https://apis.google.com/js/api.js" ... ></script>

Inside the component file (.vue), if you want the script to be loaded set the flag to true:

<script>
export default {
  ...
  loadGoogleAPI: true,
  data() {
  ...
  }
};
</script>

4 Comments

If the script with the v-if is outside the Vue instance, the v-if has no effect at all.
Even if the v-if did work, removing the script has too no effect to the code that was already loaded. Removing the <script> does not unload its code.
@acdcjunior It's a good point, but I luckily don't need to unload the script. If I needed one work-around would be to make a multi-page vue app
Then the other question/answer I pointed do exactly the same thing.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.