unhead@betaThe useScript composable provides a powerful way to load and manage external scripts in your application. Built on top of useHead(), it offers advanced features for script loading, performance optimization, and safe script interaction.
Quick Answer: Use useScript('https://example.com/script.js') to load external scripts with automatic singleton behavior, proxy for safe function calls, and configurable loading triggers.
A key feature of useScript is its singleton pattern - scripts with the same source or key are only loaded once globally, regardless of how many components request them.
import { useScript } from '@unhead/angular'
// In component A
useScript('https://maps.googleapis.com/maps/api/js')
// In component B - reuses the same script instance, doesn't load twice
useScript('https://maps.googleapis.com/maps/api/js')
For better organization and reuse, wrap script initialization in dedicated composables:
// composables/useGoogleMaps.ts
import { useScript } from '@unhead/angular'
export function useGoogleMaps(options = {}) {
return useScript({
src: 'https://maps.googleapis.com/maps/api/js',
key: 'google-maps',
...options
})
}
By default, useScript is configured for optimal performance and privacy:
async: true - Load without blocking renderdefer: true - Execute in document order after page has loadedfetchpriority: 'low' - Prioritize other critical resources firstcrossorigin: 'anonymous' - Prevent third-party cookie accessreferrerpolicy: 'no-referrer' - Block referrer headers to script domainThe proxy feature allows you to safely call script functions even before the script has loaded:
import { useScript } from '@unhead/angular'
const { proxy } = useScript('https://www.googletagmanager.com/gtag/js')
// Works immediately, even if script hasn't loaded yet
proxy.gtag('event', 'page_view')
These function calls are queued and executed once the script loads. If the script fails to load, the calls are silently dropped.
.onError() handlers for critical scripts to catch loading issues.For direct access to the script's API after loading:
import { useScript } from '@unhead/angular'
const { onLoaded } = useScript('https://www.googletagmanager.com/gtag/js')
onLoaded(({ gtag }) => {
// Direct access to the API after script is loaded
const result = gtag('event', 'page_view')
console.log(result)
})
Control when scripts load using triggers:
import { useScript } from '@unhead/angular'
// Load after a timeout
useScript('https://example.com/analytics.js', {
trigger: new Promise(resolve => setTimeout(resolve, 3000))
})
// Load on user interaction
useScript('https://example.com/video-player.js', {
trigger: (load) => {
// Only runs on client
document.querySelector('#video-container')
?.addEventListener('click', () => load())
}
})
// Manual loading (useful for lazy loading)
const { load } = useScript('https://example.com/heavy-library.js', {
trigger: 'manual'
})
// Load when needed
function handleSpecialFeature() {
load()
// Rest of the feature code...
}
Optimize loading with resource hints to warm up connections before loading the script:
import { useScript } from '@unhead/angular'
useScript('https://example.com/script.js', {
// Choose a strategy
warmupStrategy: 'preload' | 'prefetch' | 'preconnect' | 'dns-prefetch'
})
preload - High priority, use for immediately needed scriptsprefetch - Lower priority, use for scripts needed soonpreconnect - Establish early connection, use for third-party domainsdns-prefetch - Lightest option, just resolves DNSfalse - Disable warmup entirelyFor granular control over resource warming:
import { useScript } from '@unhead/angular'
const script = useScript('https://example.com/video-player.js', {
trigger: 'manual'
})
// Add warmup hint when user might need the script
function handleHoverVideo() {
script.warmup('preconnect')
}
// Load when definitely needed
function handlePlayVideo() {
script.load()
}
import { useScript } from '@unhead/angular'
const analytics = useScript({
src: 'https://example.com/analytics.js',
key: 'analytics',
defer: true,
async: true,
crossorigin: 'anonymous',
referrerpolicy: 'no-referrer'
}, {
warmupStrategy: 'preconnect',
trigger: new Promise((resolve) => {
// Load after user has been on page for 3 seconds
setTimeout(resolve, 3000)
})
})
// Track page view immediately (queued until script loads)
analytics.proxy.track('pageview')
// Access direct API after script is loaded
analytics.onLoaded(({ track }) => {
// Do something with direct access
const result = track('event', { category: 'engagement' })
console.log('Event tracked:', result)
})
// Handle errors
analytics.onError((error) => {
console.error('Failed to load analytics:', error)
})
export function useGoogleAnalytics() {
const script = useScript({
src: 'https://www.googletagmanager.com/gtag/js',
defer: true
})
// Initialize GA
script.proxy.gtag('js', new Date())
script.proxy.gtag('config', 'G-XXXXXXXXXX')
return {
...script,
trackEvent: (category, action, label) => {
script.proxy.gtag('event', action, {
event_category: category,
event_label: label
})
}
}
}
.onError() handlers for critical scripts to catch loading failurespreconnect, preload) to optimize loading performance