实现思路:通过轮询fetch跟路由获取script的hash值对比实现
新建useCheckForUpdates.ts文件
import {
ref, onMounted, onUnmounted, Ref,
} from 'vue'
interface UseCheckForUpdatesOptions {
url?: string
interval?: number
}
interface UseCheckForUpdatesReturn {
updateAvailable: Ref<boolean>
checkForUpdates: () => void
}
export function useCheckForUpdates({
url = '/',
interval = 60000,
}: UseCheckForUpdatesOptions = {}): UseCheckForUpdatesReturn {
const updateAvailable = ref(false)
let timeoutId: number | undefined
let previousHashes: string[] = []
const getCurrentHashesFromHTML = async (): Promise<string[]> => {
try {
const response = await fetch(url)
const htmlText = await response.text()
const parser = new DOMParser()
const doc = parser.parseFromString(htmlText, 'text/html')
const scripts = Array.from(doc.scripts).filter(script => script.src)
return scripts.map(script => {
const hashMatch = script.src.match(/\.([a-f0-9]+)\.js/)
return hashMatch ? hashMatch[1] : ''
}).filter(hash => hash !== '')
} catch (error) {
console.error('Error fetching root HTML:', error)
return []
}
}
const scheduleNextCheck = () => {
timeoutId = window.setTimeout(checkForUpdates, interval)
}
const checkForUpdates = async () => {
const currentHashes = await getCurrentHashesFromHTML()
if (previousHashes.length === 0) {
previousHashes = currentHashes
scheduleNextCheck()
return
}
const hashesChanged = currentHashes.some(hash => !previousHashes.includes(hash))
if (hashesChanged) {
updateAvailable.value = true
} else {
previousHashes = currentHashes
scheduleNextCheck()
}
}
onMounted(() => {
checkForUpdates()
})
onUnmounted(() => {
if (timeoutId) {
clearTimeout(timeoutId)
}
})
return { updateAvailable, checkForUpdates }
}
使用方法
import { useCheckForUpdates } from '~/hooks/useCheckForUpdates.ts'
const { updateAvailable } = useCheckForUpdates({
url: '/',
interval: 60000,
})
watch(() => updateAvailable.value, async () => {
if (updateAvailable.value) {
console.log('版本已更新')
}
})