Skip to content

一个用于实时检测 web 应用更新的 JavaScript 库

License

Notifications You must be signed in to change notification settings

JoeshuTT/version-polling

Repository files navigation

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作为版本标识符来判断应用是否有更新。
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作为版本标识符来判断应用是否有更新。
chunkHash说明:因为前端 spa 项目都是打包后再部署,这里以 vite 为例,打包产物 index.html 文件内容中会存在一个 script 标签,格式类似<script type="module" crossorigin src="/assets/index.065a65a6.js"></script>,其中index是 chunk 名称,后面的065a65a6是 chunk 哈希值,每次项目代码有改动再打包这里的chunkHash哈希值都会发生变化,以这个为依据判断是否有更新。

  1. 使用Web WorkerAPI 在浏览器后台轮询请求index.html文件,不会影响主线程运行。
  2. 请求index.html文件,对比当前文件和最新文件中的chunkHash的哈希值。
  3. 如果chunkHash哈希值不一致,说明有更新,则弹出更新提示,并引导用户手动刷新页面(例如弹窗提示),完成应用更新。
  4. 其他逻辑和方式一保持一致。

使用version.json 文件管理版本号

使用 version.json 文件管理版本内容,由开发者手动控制应用版本更新。 缺点是需要开发者手动维护 version.json 文件

  1. 使用Web WorkerAPI 在浏览器后台轮询请求version.json文件,不会影响主线程运行。
  2. 请求version.json文件,对比当前文件和最新文件中的 version 字段值。
  3. 版本号比较遵循 Semver 语义化版本规范,如果有高版本则弹出更新提示,并引导用户手动刷新页面(例如弹窗提示),完成应用更新。
  4. 其他逻辑和方式一保持一致。

浏览器兼容性

适用于支持原生 ES Modules 的浏览器

chrome >= 87
edge >= 88
firefox >= 78
safari >= 14

安装

  • 通过 npm 引入,并通过构建工具进行打包
# 本地项目安装
npm install version-polling --save
  • 通过 CDN 方式引入,直接插入到 HTML

无侵入用法,接入成本最低

<script src="https://unpkg.com/version-polling/dist/version-polling.min.js"></script>

使用参考前端静态 HTML 页面自动检测更新示例

使用示例

基础用法

当检测到有新版本时,会触发onUpdate回调函数,弹出提示用户有更新,点击确定刷新页面。

// 在应用入口文件中使用: 如 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();
    }
  },
});

使用第三方组件提示更新

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();
      });
  },
});

使用轮询,并且设置轮询间隔

如果觉得前端轮询请求太频繁,可以设置轮询间隔为半小时。

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上触发的事件。

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();
    }
  },
});

通过前端自定义事件触发检测

由开发者自行决定触发检测的时机。

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触发版本检测。

dispatchEvent(new CustomEvent('myEvent'));

还可以在路由跳转时触发,以Vue Router为例,借助导航守卫来触发版本检测。

router.afterEach((to, from) => {
  dispatchEvent(new CustomEvent('myEvent'));
});

设置版本控制方式为chunkHash

使用chunkHash作为版本标识符,控制应用版本更新。以打包构建工具 vite 为例。

import { createVersionPolling } from 'version-polling';

createVersionPolling({
  vcType: 'chunkHash',
  silent: import.meta.env.MODE === 'development', // 开发环境下不检测
  onUpdate: (self) => {
    const result = confirm('页面有更新,点击确定刷新页面!');
    if (result) {
      self.onRefresh();
    } else {
      self.onCancel();
    }
  },
});

chunkName 也可能是其他值,例如 Vue CLI 是app,查看打包产物里index.html文件内容来确定。

设置版本控制方式为versionJson

使用version.json 文件管理版本号,控制应用版本更新。

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字段值

{
  "version": "2.1.0",
  "versionContent": "更新内容: 修复已知存在的问题"
}

version.json文件跟index.html文件放在同一个服务器目录下。

API

options

参数 说明 类型 默认值
vcType 版本控制方式,可选值有etagchunkHashversionJson string etag
htmlFileUrl index.html文件地址 string ${location.origin}${location.pathname}
chunkName chunk 名称 string index
versionFileUrl version.json文件地址 string ${location.origin}${location.pathname}version.json
eventTriggerList 触发版本检测的事件名称列表 string[] -
pollingInterval 轮询间隔,单位为毫秒,默认为 5 分钟 number 5 * 60 * 1000
silent true时,不进行版本检测 boolean false
silentPollingInterval true时,不做轮询版本检测 boolean false
silentPageVisibility true时,visibilitychange事件不会触发版本检测 boolean false
onUpdate 检测到版本更新触发的回调函数 (self) => void -

deprecated

  • v1.3.0移除appETagKeyforceUpdate配置项,移除原因使用鸡肋

开源协议

MIT