@@ -27,7 +27,7 @@ export function useScript<T>(_input: UseScriptInput, _options?: UseScriptOptions
27
27
const key = `use-script.${ id } `
28
28
if ( head . _scripts ?. [ id ] )
29
29
return head . _scripts [ id ]
30
-
30
+ options . beforeInit ?. ( )
31
31
const syncStatus = ( s : ScriptInstance < T > [ 'status' ] ) => {
32
32
script . status = s
33
33
head . hooks . callHook ( `script:updated` , hookCtx )
@@ -44,9 +44,11 @@ export function useScript<T>(_input: UseScriptInput, _options?: UseScriptOptions
44
44
const loadPromise = new Promise < T > ( ( resolve , reject ) => {
45
45
const cleanUp = head . hooks . hook ( 'script:updated' , ( { script } : { script : ScriptInstance < T > } ) => {
46
46
if ( script . id === id && ( script . status === 'loaded' || script . status === 'error' ) ) {
47
- if ( script . status === 'loaded' )
48
- resolve ( options . use ?.( ) as T )
49
- else if ( script . status === 'error' )
47
+ if ( script . status === 'loaded' ) {
48
+ const api = options . use ?.( )
49
+ api && resolve ( api )
50
+ }
51
+ else if ( script . status === 'error' ) {
50
52
reject ( new Error ( `Failed to load script: ${ input . src } ` ) )
51
53
cleanUp ( )
52
54
}
@@ -105,16 +107,19 @@ export function useScript<T>(_input: UseScriptInput, _options?: UseScriptOptions
105
107
// $script is stubbed by abstraction layers
106
108
if ( fn === '$script' )
107
109
return $script
108
- return ( ...args : any [ ] ) => {
109
- const hookCtx = { script, fn, args }
110
+ const attempt = ( args ?: any [ ] ) => {
111
+ if ( head . ssr )
112
+ return
113
+ const api = options . use ?.( )
114
+ const exists = ! ! ( api && fn in api )
115
+ const hookCtx = { script, fn, args, exists }
110
116
// we can't await this, mainly used for debugging
111
117
head . hooks . callHook ( 'script:instance-fn' , hookCtx )
112
- // third party scripts only run on client-side, mock the function
113
- if ( head . ssr || ! options . use )
114
- return
115
- // @ts -expect-error untyped
116
- return script . status === 'loaded' ? options . use ( ) [ fn ] ?.( ...args ) : loadPromise . then ( api => api [ fn ] ?.( ...args ) )
118
+ return exists && api [ fn ]
117
119
}
120
+ // api may already be loaded
121
+ // for instance GTM will already have dataLayer available, we can expose it directly
122
+ return attempt ( ) || ( ( ...args : any [ ] ) => loadPromise . then ( ( ) => attempt ( args ) ( ...args ) ) )
118
123
} ,
119
124
} ) as any as T & { $script : ScriptInstance < T > }
120
125
// 4. Providing a unique context for the script
0 commit comments