react 页面如何自动监控版本更新
一般我们打包的js bundle,都自带了hash,所以,刷新页面就会加载最新的内容。
但如果用户一直不去刷新页面,停留在当前页面呢?
- 可以前端写个轮询,去检测,2. 后端推送
对于第一种方案实现简单,但会有一点性能损耗,第二种需要后端实现,SSE,或websocket?
下面代码展示第一种轮询方案:
usePoller.js
import { useEffect, useState } from 'react'
export const UsePoller = ({ deploymentUrl }: any) => {
const [isNewVersionAvailable, setIsNewVersionAvailable] = useState(false)
useEffect(() => {
const compareVersions = async () => {
// request the index.html file from the deployment
const fetchedPage = await fetch(deploymentUrl, { method: 'get', mode: 'cors' })
// get the text from the response
const loadedText = await fetchedPage.text()
// get the index.js file to get hash
const SCRIPT_REJEX_MAIN = /^.*<script.*\/(index.*\.js).*$/gim
const matchResponses = SCRIPT_REJEX_MAIN.exec(loadedText)
const remoteMainScript =
matchResponses && matchResponses?.length > 0 ? matchResponses[1] : undefined
if (remoteMainScript === undefined) {
console.log('Could not find index script in index.html')
setIsNewVersionAvailable(false)
return
}
// get the current version hash from current deployment
let currentMainScript = undefined
// get text representation of document
const scriptTags = document.head.getElementsByTagName('script')
for (let i = 0; i < scriptTags.length; i++) {
const scriptTag: any = scriptTags[i]
const reg = /^.*\/(index.*\.js).*$/gim
if (scriptTag.src) {
const obj = reg.exec(scriptTag.src)
if (obj !== null) {
currentMainScript = obj[1]
} else {
currentMainScript = undefined
}
}
}
// if the current index script, or the remote index script is undefined, we can't compare
// but if they are there, compare them
setIsNewVersionAvailable(
!!currentMainScript &&
!!remoteMainScript &&
currentMainScript !== remoteMainScript
)
console.log('Current index script: ', currentMainScript)
console.log('Remote index script: ', remoteMainScript)
}
// compare versions every 5 minutes
const createdInterval = setInterval(compareVersions, 5 * 60 * 1000)
return () => {
// clear the interval when the component unmounts
clearInterval(createdInterval)
}
}, [deploymentUrl])
// return the state
return { isNewVersionAvailable }
}
app.tsx
import { UsePoller } from './usePoller'
export default function App() {
const { isNewVersionAvailable } = UsePoller({
deploymentUrl: INDEX_HTML_DEPLOYMENT_URL,
})
useEffect(() => {
if (isNewVersionAvailable) {
console.log('New version available, reloading...')
alert('New version available, click ok to reload')
window.location.reload()
} else {
console.log('No new version available...')
}
}, [isNewVersionAvailable])
rerturn ...
}