场景
对于单页面应用,用户一直停留在当前页面,网站更新了,路由跳转加载资源可能就会找不到,这时可以通过 window.onerror
监听资源加载失败来被动提醒用户,但如果不等用户操作,主动弹出提醒该怎么做呢?
fetch('')
一种方案是隔一段时间就请求网页源码,如果和当前网页源码不一致了就说明页面发生了更新。
一般打包后 index.html 肯定会发生变动。
setInterval(async () => {
try {
const res = await fetch('')
const html = await res.text()
if (window.latestHtml && window.latestHtml !== html) console.log('请刷新')
window.latestHtml = html
} catch (error) {
//
}
}, 60000)
Etag
也可以不请求整个 index.html,只请求 header 也是一种方案。
const res = await fetch('', { method: 'HEAD' })
console.log(res.headers.get('Etag'))
判断 Etag 的变化来提醒刷新。
Build Timestamp
还有一种思路是每次打包都创建一个文件,文件内容是打包时间戳,同样隔一段时间就请求这个文件,如果文件内容变化了就说明资源有了更新。
npm run build && node build-id.js
只需要在构建完成后跑一个脚本即可。
build-id.js
代码如下,将当前时间戳写到 dist/build-id.js
中,写入的是 36 进制的时间戳,稍微混淆下,太直白暴露构建时间也不太好。
const fs = require('fs')
fs.writeFileSync('./dist/build-id.js', Date.now().toString(36), 'utf-8')
dist/build-id.js
lruhqttv
每隔一定时间就请求这个文件,拿到时间戳判断是否有更新,这里用的是 js 类型文件,随便搞个类型也行。fetch 要加上参数 cache: 'reload'
或者 header 加上 'Cache-Control': 'no-cache'
不使用缓存。
setInterval(async () => {
try {
// const res = await fetch('build-id.js', {
// cache: 'reload'
// })
// or
const res = await fetch('build-id.js', {
headers: {
'Cache-Control': 'no-cache'
}
})
const id = await res.text()
if (window.buildId && window.buildId !== id) console.log('请刷新')
window.buildId = id
} catch (error) {
//
}
}, 60000)