Skip to content

Commit

Permalink
fix(scripts): support re-registering the load trigger (#389)
Browse files Browse the repository at this point in the history
  • Loading branch information
huang-julien authored Sep 2, 2024
1 parent fc564e7 commit 0ff0595
Show file tree
Hide file tree
Showing 3 changed files with 49 additions and 7 deletions.
1 change: 1 addition & 0 deletions packages/schema/src/script.ts
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@ export interface ScriptInstance<T extends BaseScriptApi> {
entry?: ActiveHeadEntry<any>
load: () => Promise<T>
remove: () => boolean
updateTrigger: (trigger: UseScriptOptions['trigger']) => void
// cbs
onLoaded: (fn: (instance: T) => void | Promise<void>) => void
onError: (fn: (err?: Error) => void | Promise<void>) => void
Expand Down
33 changes: 27 additions & 6 deletions packages/unhead/src/composables/useScript.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,9 @@ import { ScriptNetworkEvents, hashCode } from '@unhead/shared'
import type {
AsAsyncFunctionValues,
Head,
SchemaAugmentations,
ScriptInstance,
Unhead,
UseFunctionType,
UseScriptInput,
UseScriptOptions,
Expand Down Expand Up @@ -96,6 +98,8 @@ export function useScript<T extends Record<symbol | string, any> = Record<symbol
}
})
})

const triggerAbortController = new AbortController()
const script = Object.assign(loadPromise, <Partial<UseScriptContext<T>>> {
instance: (!head.ssr && options?.use?.()) || null,
proxy: null,
Expand Down Expand Up @@ -137,6 +141,11 @@ export function useScript<T extends Record<symbol | string, any> = Record<symbol
onError(cb: (err?: Error) => void | Promise<void>) {
return _registerCb('error', cb)
},
updateTrigger(trigger: UseScriptOptions['trigger']) {
// cancel previous trigger
triggerAbortController.abort()
handleTrigger(trigger, triggerAbortController, script, head)
},
_cbs,
}) as UseScriptContext<T>
// script is ready
Expand All @@ -153,13 +162,8 @@ export function useScript<T extends Record<symbol | string, any> = Record<symbol
_cbs.error = null
})
const hookCtx = { script }
if ((trigger === 'client' && !head.ssr) || trigger === 'server')
script.load()
else if (trigger instanceof Promise)
trigger.then(script.load)
else if (typeof trigger === 'function')
trigger(async () => script.load())

handleTrigger(trigger, triggerAbortController, script, head)
// support deprecated behavior
script.$script = script
const proxyChain = (instance: any, accessor?: string | symbol, accessors?: (string | symbol)[]) => {
Expand Down Expand Up @@ -211,3 +215,20 @@ export function useScript<T extends Record<symbol | string, any> = Record<symbol
head._scripts = Object.assign(head._scripts || {}, { [id]: res })
return res
}

function handleTrigger(trigger: UseScriptOptions['trigger'], abortController: AbortController, script: UseScriptContext<any>, head: Unhead<Head<SchemaAugmentations>>) {
if ((trigger === 'client' && !head.ssr) || trigger === 'server') {
script.load()
}
else if (trigger instanceof Promise) {
new Promise((resolve, reject) => {
trigger.then(script.load).then(resolve)
abortController.signal.addEventListener('abort', reject)
}).catch(() => {
// cancelled
})
}
else if (typeof trigger === 'function') {
trigger(async () => script.load())
}
}
22 changes: 21 additions & 1 deletion test/unhead/e2e/scripts.test.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import { describe, it } from 'vitest'
import { createHead, useHead } from 'unhead'
import { createHead, useHead, useScript } from 'unhead'
import { renderSSRHead } from '@unhead/ssr'
import { renderDOMHead } from '@unhead/dom'
import { useDom } from '../../fixtures'
Expand Down Expand Up @@ -53,4 +53,24 @@ describe('unhead e2e scripts', () => {
</body></html>"
`)
})

it('expect to update trigger', async () => {
const promise = new Promise<void>(() => {})
const script = useScript({
src: 'https://cdn.example.com/script.js',
}, {
trigger: promise,
})

const newPromise = new Promise<void>((resolve) => {
setTimeout(() => {
resolve()
}, 25)
})
expect(script.status).toBe('awaitingLoad')
script.updateTrigger(newPromise)
expect(script.status).toBe('awaitingLoad')
await newPromise
expect(script.status).toBe('loading')
})
})

0 comments on commit 0ff0595

Please sign in to comment.