External script tag (3rd party javascript) with Quasar and Vue 3?

Viewed 582

I need to add some external JavaScript scripts to my Quasar / Vue 3 app.

For example, I need to use this on certain pages within my app for Zoho Desk:

<script type="text/javascript" nonce="{place_your_nonce_value_here}" src="https://desk.zoho.com.au/portal/api/web/inapp/9999999999?orgId=111111111" defer > </script>

Another example is Stripe.js, where I only want it to load on the payment pages:

<script src="https://js.stripe.com/v3/"></script>

I imagine I there are many other examples of needing to selectivly inject these 3rd party JavaScript snippets.

Quasar has boot files, which might be good for this but I'm not sure how to implement it with that, or even if that's the best solution.

Any guidance is welcome.

1 Answers

The correct answer is that it depends on the third-party library, the ways it provides for installation and if it has integration support with Vue.js and/or Quasar.

For example for Stripe, you can install it as an npm package and use it like this (non-tested code):

<script setup> 
import { onMounted } from 'vue'
import {loadStripe} from '@stripe/stripe-js';

onMounted(() => {
const stripe = await loadStripe('pk_test_TYooMQauvdEDq54NiTphI7jx');
})
</script>

Third-party library with script tag installation

I am going to assume though, that the question is more on how to add a third-party library that provides only a script tag installation:

  1. Create a JS file (load-script.js):
function createTag(src) {
  let script
  
  script = document.createElement('script')
  script.type = 'application/javascript'
  script.async = true
  script.src = src
  
  return script
}

function addListeners(script, resolve, reject) {
  script.addEventListener('error', reject)
  script.addEventListener('abort', reject)
  script.addEventListener('load', function loadScriptHandler() {
    script.setAttribute('data-loaded', '')
    resolve(removeScript.bind(null, script))
  })
}

export function removeScript(scriptOrSrc) {
  let script
  
  if (typeof scriptOrSrc === 'string') {
    script = document.querySelector(`script[src="${scriptOrSrc}"]`)
  } else {
    script = scriptOrSrc
  }
  
  if (script) script.parentNode.removeChild(script)
}

export function loadScript(src) {
  return new Promise((resolve, reject) => {
    let script = document.querySelector(`script[src="${src}"]`)
    
    if (script && script.hasAttribute('data-loaded')) {
      resolve(removeScript.bind(null, script))
      return
    }
    
    script = createTag(src)
    addListeners(script, resolve, reject)
    document.head.appendChild(script)
  })
}
  1. Use that function to load or remove script tag in your components:
<script setup>
import { onUnmounted } from 'vue'
import { loadScript, removeScript } from '../load-script'

const src = '3rd-part-url'

loadScript(src)

onUnmounted(() => removeScript(src))
</script>

With .then approach:

<script setup>
import { onUnmounted } from 'vue'
import { loadScript } from '../load-script'

let removeScript

loadScript('3rd-part-url').then((removeScriptCallback) => {
  // script is loaded use `removeScriptCallback()` to remove it
  removeScript = removeScriptCallback
})

onUnmounted(() => removeScript())
</script>

with Options API:

<script>
import { loadScript, removeScript } from './load-script.js'

export default {
  created() {
    this.externalScriptUrl = '...'
    loadScript(externalScriptUrl).then(removeScript => {
      // script is loaded use `removeScript()` to remove it
    })
  },

  unmounted() {
    removeScript(this.externalScriptUrl)
  }
}
</script>

Explanation

The load-script.js file uses async attribute. It registers error, abort and load events for the script tag. Then load event resolves the then block whereas error and abort fall in the catch block of the promise. AFAIK since events are registered in the element there is no need to remove listeners.

The script tag will be appended in the head.

The script can be easily enhanced by adding support for script attributes or to be able to append it in body but for the purpose of this answer, it's better to keep it simple.


Things to know

  1. You may or may not have security issues loading external js on the fly.
  2. Removing the script tag, doesn't mean you unloaded the script:

any code loaded as part of the external JavaScript file remains in the browser's memory. That is to say, you can still access variables, functions etc that were added when the external file first loaded

Related