--- title: "script:updated Hook" description: "Learn about the script:updated hook in Unhead that's triggered when a script instance is updated" navigation: title: "script:updated" internal: true --- 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. ## Hook Signature ```ts export interface Hook { 'script:updated': (ctx: { script: ScriptInstance<any> }) => void | Promise<void> } ``` ### Parameters | Name | Type | Description | |------|------|-------------| | `ctx` | Object | Context object with script information | | `ctx.script` | `ScriptInstance<any>` | The script instance that was updated | ### Returns `void` or `Promise<void>` ## Usage Example ```ts import { createHead } from '@unhead/dynamic-import' 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: ```ts import { defineHeadPlugin } from '@unhead/dynamic-import' 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: ```ts import { defineHeadPlugin } from '@unhead/dynamic-import' 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: ```ts import { defineHeadPlugin } from '@unhead/dynamic-import' 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 } ```