Svelte
You're viewing Unhead v3 beta documentation. Install with unhead@beta
Hooks

script:updated Hook

The script:updated hook is called when a script instance managed by Unhead is updated. This hook is specific to Unhead's script management features and provides a way to react to changes in script status, such as loading, execution, or errors.

Lifecycle Position

This hook is separate from the main tag resolution lifecycle. It is triggered independently whenever a script instance changes status (loading, loaded, error, idle).

Hook Signature

export interface Hook {
  'script:updated': (ctx: { script: ScriptInstance<any> }) => void | Promise<void>
}

Parameters

NameTypeDescription
ctxObjectContext object with script information
ctx.scriptScriptInstance<any>The script instance that was updated

Returns

void or Promise<void>

Usage Example

import { createHead } from '@unhead/svelte'

const head = createHead({
  hooks: {
    'script:updated': (ctx) => {
      // Log script status changes
      const { script } = ctx
      console.log(`Script "${script.id}" updated, status: ${script.status}`)

      // React to specific script updates
      if (script.id === 'analytics' && script.status === 'loaded') {
        console.log('Analytics script has loaded successfully')
      }
    }
  }
})

Use Cases

Script Loading Monitoring

Track script loading status across your application:

import { defineHeadPlugin } from '@unhead/svelte'

export const scriptMonitoringPlugin = defineHeadPlugin({
  hooks: {
    'script:updated': (ctx) => {
      const { script } = ctx

      // Log detailed script status updates
      switch (script.status) {
        case 'loading':
          console.log(`Script loading started: ${script.id}`)
          break
        case 'loaded':
          console.log(`Script loaded successfully: ${script.id}`)
          break
        case 'error':
          console.error(`Script failed to load: ${script.id}`, script.error)
          break
        case 'idle':
          console.log(`Script waiting: ${script.id}`)
          break
      }

      // Track loading times for performance monitoring
      if (script.status === 'loaded' && script.loadStart) {
        const loadTime = Date.now() - script.loadStart
        console.log(`Script "${script.id}" loaded in ${loadTime}ms`)

        // Report to analytics or performance monitoring
        if (window.performance && window.performance.mark) {
          window.performance.mark(`script-${script.id}-loaded`)
          window.performance.measure(
            `script-${script.id}-load-time`,
            `script-${script.id}-loading`,
            `script-${script.id}-loaded`
          )
        }
      }
    }
  }
})

Dependency Management

Manage script dependencies and trigger actions when scripts load:

import { defineHeadPlugin } from '@unhead/svelte'

export const scriptDependencyPlugin = defineHeadPlugin({
  hooks: {
    'script:updated': (ctx) => {
      const { script } = ctx

      // Track loaded scripts in a global registry
      if (!window.__LOADED_SCRIPTS) {
        window.__LOADED_SCRIPTS = new Set()
      }

      if (script.status === 'loaded') {
        // Add to loaded scripts registry
        window.__LOADED_SCRIPTS.add(script.id)

        // Check for dependency chains
        checkDependencies(script.id)
      }
    }
  }
})

// Helper function to check and execute dependent scripts
function checkDependencies(loadedScriptId) {
  // Define script dependencies (scripts that depend on others)
  const dependencyMap = {
    'maps-init': ['google-maps-api'],
    'analytics-enhanced': ['analytics-base'],
    'shop-components': ['vue', 'shopping-cart-api']
  }

  // Check if any scripts are waiting for this one
  Object.entries(dependencyMap).forEach(([scriptId, dependencies]) => {
    if (dependencies.includes(loadedScriptId)) {
      // Check if all dependencies for this script are now loaded
      const allDepsLoaded = dependencies.every(dep =>
        window.__LOADED_SCRIPTS.has(dep)
      )

      if (allDepsLoaded) {
        console.log(`All dependencies loaded for ${scriptId}, initializing...`)
        initScript(scriptId)
      }
    }
  })
}

// Helper function to initialize dependent scripts
function initScript(scriptId) {
  // This would handle the initialization of scripts that depend on others
  console.log(`Initializing dependent script: ${scriptId}`)

  // Your actual initialization logic would go here
  // For example, you might call a global function that was loaded
  if (scriptId === 'maps-init' && window.google && window.google.maps) {
    window.initGoogleMaps?.()
  }
}

Error Recovery

Implement error recovery strategies for failed scripts:

import { defineHeadPlugin } from '@unhead/svelte'

export const scriptErrorRecoveryPlugin = defineHeadPlugin({
  hooks: {
    'script:updated': (ctx) => {
      const { script } = ctx

      // Handle script loading errors
      if (script.status === 'error') {
        console.error(`Script "${script.id}" failed to load:`, script.error)

        // Track retry attempts
        script.retryCount = (script.retryCount || 0) + 1

        // Implement retry strategy with exponential backoff
        if (script.retryCount <= 3) {
          const backoffTime = 2 ** script.retryCount * 1000
          console.log(`Retrying script "${script.id}" in ${backoffTime}ms (attempt ${script.retryCount}/3)`)

          setTimeout(() => {
            // Reset status and try again
            script.status = 'idle'

            // Use a different CDN or fallback URL if available
            if (script.retryCount > 1 && script.fallbackSrc) {
              script.src = script.fallbackSrc
              console.log(`Using fallback source for "${script.id}": ${script.fallbackSrc}`)
            }

            // Trigger reload
            script.load()
          }, backoffTime)
        }
        else {
          // After max retries, log failure and try to recover app state
          console.error(`Script "${script.id}" failed after ${script.retryCount} retry attempts`)

          // Notify user if the script was critical
          if (script.critical) {
            showUserErrorNotification(script.id)
          }

          // Try to load from local fallback if available
          if (script.localFallback) {
            console.log(`Loading local fallback for "${script.id}"`)
            loadLocalFallback(script.id, script.localFallback)
          }
        }
      }
    }
  }
})

// Helper functions for error recovery
function showUserErrorNotification(scriptId) {
  console.log(`Showing error notification for script: ${scriptId}`)
  // Your notification logic
}

function loadLocalFallback(scriptId, fallbackPath) {
  console.log(`Loading local fallback for ${scriptId} from ${fallbackPath}`)
  // Your fallback loading logic
}
Did this page help you?