A JavaScript library for web application updates
npm install version-polling> 一个用于实时检测 web 应用更新的 JavaScript 库
> 以下内容是通过 GitHub Copilot 生成的 😊
在现代 web 应用开发中,前端代码的更新频率较高,尤其是单页应用(SPA)。当应用发布新版本时,如何及时通知用户并引导其刷新页面以加载最新资源,成为了一个亟待解决的问题。version-polling 库应运而生,旨在提供一种简单高效的方式来检测前端应用的版本更新,并提示用户进行页面刷新。
用户在浏览器中打开某 web 应用(通常是后台管理系统)很长时间且未刷新页面时,如果应用有新功能添加或问题修复,用户可能无法及时知道有新版发布。这样会导致用户继续使用旧版,影响用户体验和数据准确性,甚至出现程序报错。
- 针对前端 web 单页应用(SPA)而设计
- 纯前端技术实现,使用简单无需后端支持
- 提供三种版本控制方式
1.使用HTTP ETag作为版本标识符
2.使用chunkHash作为版本标识符 v1.3.0
3.使用version.json 文件管理版本号 v1.3.0
- 支持 TypeScript
> 使用HTTP ETag作为版本标识符来判断应用是否有更新。
> HTTP ETag说明:每次请求index.html文件时,HTTP 响应头上会有一个 ETag 字段,
> 格式类似ETag: W/"0815"该字段的值是服务器资源的唯一标识符,通过比较前后两次请求的 Etag 字段值,可以判断资源是否发生变化,以这个为依据判断是否有更新。
> 缺点是HTTP ETag是由服务器生成的,前端不可控。
1. 使用Web WorkerAPI 在浏览器后台轮询请求index.html文件,不会影响主线程运行。
2. 请求index.html文件,对比本地和请求响应头的 ETag 的字段值。
3. 如果 ETag 字段值不一致,说明有更新,则弹出更新提示,并引导用户手动刷新页面(例如弹窗提示),完成应用更新。
4. 当页面不可见时(例如切换标签页或最小化窗口),停止实时检测任务;再次可见时(例如切换回标签页或还原窗口),恢复实时检测任务。
5. 支持添加其他前端事件(例如页面导航或自定义事件)触发检测,由开发者自行决定检测时机。
> 使用chunkHash作为版本标识符来判断应用是否有更新。
> chunkHash说明:因为前端 spa 项目都是打包后再部署,这里以 vite 为例,打包产物 index.html 文件内容中会存在一个 script 标签,格式类似,其中index是 chunk 名称,后面的065a65a6是 chunk 哈希值,每次项目代码有改动再打包这里的chunkHash哈希值都会发生变化,以这个为依据判断是否有更新。
1. 使用Web WorkerAPI 在浏览器后台轮询请求index.html文件,不会影响主线程运行。
2. 请求index.html文件,对比当前文件和最新文件中的chunkHash的哈希值。
3. 如果chunkHash哈希值不一致,说明有更新,则弹出更新提示,并引导用户手动刷新页面(例如弹窗提示),完成应用更新。
4. 其他逻辑和方式一保持一致。
> 使用 version.json 文件管理版本内容,由开发者手动控制应用版本更新。
> 缺点是需要开发者手动维护 version.json 文件
1. 使用Web WorkerAPI 在浏览器后台轮询请求version.json文件,不会影响主线程运行。
2. 请求version.json文件,对比当前文件和最新文件中的 version 字段值。
3. 版本号比较遵循 Semver 语义化版本规范,如果有高版本则弹出更新提示,并引导用户手动刷新页面(例如弹窗提示),完成应用更新。
4. 其他逻辑和方式一保持一致。
适用于支持原生 ES Modules 的浏览器
``yaml title=".browserslistrc"`
chrome >= 87
edge >= 88
firefox >= 78
safari >= 14
- 通过 npm 引入,并通过构建工具进行打包
`bash`本地项目安装
npm install version-polling --save
- 通过 CDN 方式引入,直接插入到 HTML
> 无侵入用法,接入成本最低
`html`
当检测到有新版本时,会触发onUpdate回调函数,弹出提示用户有更新,点击确定刷新页面。
`js
// 在应用入口文件中使用: 如 main.js, app.jsx
import { createVersionPolling } from 'version-polling';
createVersionPolling({
silent: process.env.NODE_ENV === 'development', // 开发环境下不检测
onUpdate: (self) => {
const result = confirm('页面有更新,点击确定刷新页面!');
if (result) {
self.onRefresh();
} else {
self.onCancel();
}
},
});
`
`js
import { createVersionPolling } from 'version-polling';
import { MessageBox } from 'element-ui';
createVersionPolling({
silent: process.env.NODE_ENV === 'development', // 开发环境下不检测
onUpdate: (self) => {
MessageBox.confirm('检测到网页有更新, 是否刷新页面加载最新版本?', '提示', {
confirmButtonText: '确定',
cancelButtonText: '取消',
})
.then(() => {
self.onRefresh();
})
.catch(() => {
self.onCancel();
});
},
});
`
如果觉得前端轮询请求太频繁,可以设置轮询间隔为半小时。
`js
import { createVersionPolling } from 'version-polling';
createVersionPolling({
pollingInterval: 30 60 1000, // 每 30 分钟检测一次
silent: process.env.NODE_ENV === 'development', // 开发环境下不检测
onUpdate: (self) => {
const result = confirm('页面有更新,点击确定刷新页面!');
if (result) {
self.onRefresh();
} else {
self.onCancel();
}
},
});
`
在浏览器页面导航跳转时、页面显示切换时,触发检测任务。
在Window上触发的事件。
`js
import { createVersionPolling } from 'version-polling';
createVersionPolling({
eventTriggerList: ['popstate'],
silent: process.env.NODE_ENV === 'development', // 开发环境下不检测
silentPollingInterval: true,
onUpdate: (self) => {
const result = confirm('页面有更新,点击确定刷新页面!');
if (result) {
self.onRefresh();
} else {
self.onCancel();
}
},
});
`
由开发者自行决定触发检测的时机。
`js
import { createVersionPolling } from 'version-polling';
createVersionPolling({
eventTriggerList: ['myEvent'],
silent: process.env.NODE_ENV === 'development', // 开发环境下不检测
onUpdate: (self) => {
const result = confirm('页面有更新,点击确定刷新页面!');
if (result) {
self.onRefresh();
} else {
self.onCancel();
}
},
});
`
通过dispatchEvent触发版本检测。
`js`
dispatchEvent(new CustomEvent('myEvent'));
还可以在路由跳转时触发,以Vue Router为例,借助导航守卫来触发版本检测。
`js`
router.afterEach((to, from) => {
dispatchEvent(new CustomEvent('myEvent'));
});
使用chunkHash作为版本标识符,控制应用版本更新。以打包构建工具 vite 为例。
`js
import { createVersionPolling } from 'version-polling';
createVersionPolling({
vcType: 'chunkHash',
chunkName: 'index',
silent: import.meta.env.MODE === 'development', // 开发环境下不检测
onUpdate: (self) => {
const result = confirm('页面有更新,点击确定刷新页面!');
if (result) {
self.onRefresh();
} else {
self.onCancel();
}
},
});
`
chunkName 也可能是其他值,例如 Vue CLI 是app,查看打包产物里index.html文件内容来确定。
使用version.json 文件管理版本号,控制应用版本更新。
`js
import { createVersionPolling } from 'version-polling';
createVersionPolling({
vcType: 'versionJson',
silent: import.meta.env.MODE === 'development', // 开发环境下不检测
onUpdate: (self) => {
const result = confirm('页面有更新,点击确定刷新页面!');
if (result) {
self.onRefresh();
} else {
self.onCancel();
}
},
});
`
修改version.json文件,配置version字段值
`json`
{
"version": "2.1.0",
"versionContent": "更新内容: 修复已知存在的问题"
}
version.json文件跟index.html文件放在同一个服务器目录下。
| 参数 | 说明 | 类型 | 默认值 |
| --------------------- | -------------------------------------------------------- | ---------------- | ---------------------------------------------------- |
| vcType | 版本控制方式,可选值有etag、chunkHash、versionJson | string | etag |index.html
| htmlFileUrl | 文件地址 | string | ${location.origin}${location.pathname} |string
| chunkName | chunk 名称 | | index |version.json
| versionFileUrl | 文件地址 | string | ${location.origin}${location.pathname}version.json |string[]
| eventTriggerList | 触发版本检测的事件名称列表 | | - |number
| pollingInterval | 轮询间隔,单位为毫秒,默认为 5 分钟 | | 5 60 1000 |true
| silent | 为时,不进行版本检测 | boolean | false |true
| silentPollingInterval | 为时,不做轮询版本检测 | boolean | false |true
| silentPageVisibility | 为时,visibilitychange事件不会触发版本检测 | boolean | false |(self) => void
| onUpdate | 检测到版本更新触发的回调函数 | | - |
- v1.3.0移除appETagKey、forceUpdate`配置项,移除原因使用鸡肋