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
| 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
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?