Skip to content

⬅️ Back to Table of Contents

📄 useScriptTag

📊 Analysis Summary

Metric Count
🔧 Functions 5
📦 Imports 10
⚡ Async/Await Patterns 2
📐 Interfaces 2

📚 Table of Contents

🛠️ File Location:

📂 packages/core/useScriptTag/index.ts

📦 Imports

Name Source
MaybeRefOrGetter vue
ShallowRef vue
ConfigurableDocument ../_configurable
noop @vueuse/shared
tryOnMounted @vueuse/shared
tryOnUnmounted @vueuse/shared
shallowRef vue
toValue vue
defaultDocument ../_configurable
useEventListener ../useEventListener

Async/Await Patterns

Type Function Await Expressions Promise Chains
promise-chain useScriptTag none new Promise(...)
promise-chain loadScript none new Promise(...)

Functions

useScriptTag(src: MaybeRefOrGetter<string>, onLoaded: (el: HTMLScriptElement) => void, options: UseScriptTagOptions): UseScriptTagReturn

Async script tag loading.

Parameters:

  • src any: No description
  • onLoaded any: No description
  • options any: No description

See: https://vueuse.org/useScriptTag

Raw JSDoc
/**
 * Async script tag loading.
 *
 * @see https://vueuse.org/useScriptTag
 * @param src
 * @param onLoaded
 * @param options
 */

Calls:

  • shallowRef (from vue)
  • resolve
  • document.querySelector
  • toValue (from vue)
  • document.createElement
  • Object.entries(attrs).forEach
  • el?.setAttribute
  • el.hasAttribute
  • resolveWithElement
  • useEventListener (from ../useEventListener)
  • reject
  • el!.setAttribute
  • onLoaded
  • document.head.appendChild
  • loadScript
  • document.head.removeChild
  • tryOnMounted (from @vueuse/shared)
  • tryOnUnmounted (from @vueuse/shared)

Internal Comments:

/**
   * Load the script specified via `src`.
   *
   * @param waitForScriptLoad Whether if the Promise should resolve once the "load" event is emitted by the <script> attribute, or right after appending it to the DOM.
   * @returns Promise<HTMLScriptElement>
   */ (x2)
// Some little closure for resolving the Promise. (x2)
// Check if document actually exists, otherwise resolve the Promise (SSR Support).
// Local variable defining if the <script> tag should be appended or not. (x2)
// Script tag not found, preparing the element for appending
// Optional attributes
// Enables shouldAppend (x3)
// Event listeners (x2)
// Append the <script> tag to head.
// If script load awaiting isn't needed, we can resolve the Promise.
/**
   * Exposed singleton wrapper for `loadScript`, avoiding calling it twice.
   *
   * @param waitForScriptLoad Whether if the Promise should resolve once the "load" event is emitted by the <script> attribute, or right after appending it to the DOM.
   * @returns Promise<HTMLScriptElement>
   */ (x2)
/**
   * Unload the script specified by `src`.
   */ (x2)

Code
export function useScriptTag(
  src: MaybeRefOrGetter<string>,
  onLoaded: (el: HTMLScriptElement) => void = noop,
  options: UseScriptTagOptions = {},
): UseScriptTagReturn {
  const {
    immediate = true,
    manual = false,
    type = 'text/javascript',
    async = true,
    crossOrigin,
    referrerPolicy,
    noModule,
    defer,
    document = defaultDocument,
    attrs = {},
    nonce = undefined,
  } = options
  const scriptTag = shallowRef<HTMLScriptElement | null>(null)

  let _promise: Promise<HTMLScriptElement | boolean> | null = null

  /**
   * Load the script specified via `src`.
   *
   * @param waitForScriptLoad Whether if the Promise should resolve once the "load" event is emitted by the <script> attribute, or right after appending it to the DOM.
   * @returns Promise<HTMLScriptElement>
   */
  const loadScript = (waitForScriptLoad: boolean): Promise<HTMLScriptElement | boolean> => new Promise((resolve, reject) => {
    // Some little closure for resolving the Promise.
    const resolveWithElement = (el: HTMLScriptElement) => {
      scriptTag.value = el
      resolve(el)
      return el
    }

    // Check if document actually exists, otherwise resolve the Promise (SSR Support).
    if (!document) {
      resolve(false)
      return
    }

    // Local variable defining if the <script> tag should be appended or not.
    let shouldAppend = false

    let el = document.querySelector<HTMLScriptElement>(`script[src="${toValue(src)}"]`)

    // Script tag not found, preparing the element for appending
    if (!el) {
      el = document.createElement('script')
      el.type = type
      el.async = async
      el.src = toValue(src)

      // Optional attributes
      if (defer)
        el.defer = defer
      if (crossOrigin)
        el.crossOrigin = crossOrigin
      if (noModule)
        el.noModule = noModule
      if (referrerPolicy)
        el.referrerPolicy = referrerPolicy
      if (nonce) {
        el.nonce = nonce
      }
      Object.entries(attrs).forEach(([name, value]) => el?.setAttribute(name, value))

      // Enables shouldAppend
      shouldAppend = true
    }
    // Script tag already exists, resolve the loading Promise with it.
    else if (el.hasAttribute('data-loaded')) {
      resolveWithElement(el)
    }

    // Event listeners
    const listenerOptions = {
      passive: true,
    }
    useEventListener(el, 'error', event => reject(event), listenerOptions)
    useEventListener(el, 'abort', event => reject(event), listenerOptions)
    useEventListener(el, 'load', () => {
      el!.setAttribute('data-loaded', 'true')

      onLoaded(el!)
      resolveWithElement(el!)
    }, listenerOptions)

    // Append the <script> tag to head.
    if (shouldAppend)
      el = document.head.appendChild(el)

    // If script load awaiting isn't needed, we can resolve the Promise.
    if (!waitForScriptLoad)
      resolveWithElement(el)
  })

  /**
   * Exposed singleton wrapper for `loadScript`, avoiding calling it twice.
   *
   * @param waitForScriptLoad Whether if the Promise should resolve once the "load" event is emitted by the <script> attribute, or right after appending it to the DOM.
   * @returns Promise<HTMLScriptElement>
   */
  const load = (waitForScriptLoad = true): Promise<HTMLScriptElement | boolean> => {
    if (!_promise)
      _promise = loadScript(waitForScriptLoad)

    return _promise
  }

  /**
   * Unload the script specified by `src`.
   */
  const unload = () => {
    if (!document)
      return

    _promise = null

    if (scriptTag.value)
      scriptTag.value = null

    const el = document.querySelector<HTMLScriptElement>(`script[src="${toValue(src)}"]`)
    if (el)
      document.head.removeChild(el)
  }

  if (immediate && !manual)
    tryOnMounted(load)

  if (!manual)
    tryOnUnmounted(unload)

  return { scriptTag, load, unload }
}

Internal helpers

Declared inside another function in this file.

loadScript(waitForScriptLoad: boolean): Promise<HTMLScriptElement | boolean>

Parameters:

  • waitForScriptLoad boolean

Returns: Promise<HTMLScriptElement | boolean>

Code
(waitForScriptLoad: boolean): Promise<HTMLScriptElement | boolean> => new Promise((resolve, reject) => {
    // Some little closure for resolving the Promise.
    const resolveWithElement = (el: HTMLScriptElement) => {
      scriptTag.value = el
      resolve(el)
      return el
    }

    // Check if document actually exists, otherwise resolve the Promise (SSR Support).
    if (!document) {
      resolve(false)
      return
    }

    // Local variable defining if the <script> tag should be appended or not.
    let shouldAppend = false

    let el = document.querySelector<HTMLScriptElement>(`script[src="${toValue(src)}"]`)

    // Script tag not found, preparing the element for appending
    if (!el) {
      el = document.createElement('script')
      el.type = type
      el.async = async
      el.src = toValue(src)

      // Optional attributes
      if (defer)
        el.defer = defer
      if (crossOrigin)
        el.crossOrigin = crossOrigin
      if (noModule)
        el.noModule = noModule
      if (referrerPolicy)
        el.referrerPolicy = referrerPolicy
      if (nonce) {
        el.nonce = nonce
      }
      Object.entries(attrs).forEach(([name, value]) => el?.setAttribute(name, value))

      // Enables shouldAppend
      shouldAppend = true
    }
    // Script tag already exists, resolve the loading Promise with it.
    else if (el.hasAttribute('data-loaded')) {
      resolveWithElement(el)
    }

    // Event listeners
    const listenerOptions = {
      passive: true,
    }
    useEventListener(el, 'error', event => reject(event), listenerOptions)
    useEventListener(el, 'abort', event => reject(event), listenerOptions)
    useEventListener(el, 'load', () => {
      el!.setAttribute('data-loaded', 'true')

      onLoaded(el!)
      resolveWithElement(el!)
    }, listenerOptions)

    // Append the <script> tag to head.
    if (shouldAppend)
      el = document.head.appendChild(el)

    // If script load awaiting isn't needed, we can resolve the Promise.
    if (!waitForScriptLoad)
      resolveWithElement(el)
  })

resolveWithElement(el: HTMLScriptElement): HTMLScriptElement

Parameters:

  • el HTMLScriptElement

Returns: HTMLScriptElement

Calls:

  • resolve
Code
(el: HTMLScriptElement) => {
      scriptTag.value = el
      resolve(el)
      return el
    }

load(waitForScriptLoad: boolean): Promise<HTMLScriptElement | boolean>

Parameters:

  • waitForScriptLoad boolean

Returns: Promise<HTMLScriptElement | boolean>

Calls:

  • loadScript
Code
(waitForScriptLoad = true): Promise<HTMLScriptElement | boolean> => {
    if (!_promise)
      _promise = loadScript(waitForScriptLoad)

    return _promise
  }

unload(): void

Returns: void

Calls:

  • document.querySelector
  • toValue (from vue)
  • document.head.removeChild
Code
() => {
    if (!document)
      return

    _promise = null

    if (scriptTag.value)
      scriptTag.value = null

    const el = document.querySelector<HTMLScriptElement>(`script[src="${toValue(src)}"]`)
    if (el)
      document.head.removeChild(el)
  }

Interfaces

UseScriptTagOptions

Interface Code
export interface UseScriptTagOptions extends ConfigurableDocument {
  /**
   * Load the script immediately
   *
   * @default true
   */
  immediate?: boolean

  /**
   * Add `async` attribute to the script tag
   *
   * @default true
   */
  async?: boolean

  /**
   * Script type
   *
   * @default 'text/javascript'
   */
  type?: string

  /**
   * Manual controls the timing of loading and unloading
   *
   * @default false
   */
  manual?: boolean

  crossOrigin?: 'anonymous' | 'use-credentials'
  referrerPolicy?: 'no-referrer' | 'no-referrer-when-downgrade' | 'origin' | 'origin-when-cross-origin' | 'same-origin' | 'strict-origin' | 'strict-origin-when-cross-origin' | 'unsafe-url'
  noModule?: boolean

  defer?: boolean

  /**
   * Add custom attribute to the script tag
   *
   */
  attrs?: Record<string, string>

  /**
   * Nonce value for CSP (Content Security Policy)
   * @default undefined
   */
  nonce?: string
}

Properties

Name Type Optional Description
immediate boolean not shown
async boolean not shown
type string not shown
manual boolean not shown
crossOrigin 'anonymous' \| 'use-credentials' not shown
referrerPolicy 'no-referrer' \| 'no-referrer-when-downgrade' \| 'origin' \| 'origin-when-cro... not shown
noModule boolean not shown
defer boolean not shown
attrs Record<string, string> not shown
nonce string not shown

UseScriptTagReturn

Interface Code
export interface UseScriptTagReturn {
  scriptTag: ShallowRef<HTMLScriptElement | null>
  load: (waitForScriptLoad?: boolean) => Promise<HTMLScriptElement | boolean>
  unload: () => void
}

Properties

Name Type Optional Description
scriptTag ShallowRef<HTMLScriptElement \| null> not shown
load (waitForScriptLoad?: boolean) => Promise<HTMLScriptElement \| boolean> not shown
unload () => void not shown

Generated by Syntax Scribe