一个轻量级的纯前端实现的版本更新自动检测和提示刷新插件。它能够自动监测应用的新版本发布,并通过友好的方式通知用户进行更新,确保用户始终使用最新版本的应用。
- 🎯 自动检测更新:定期轮询检测应用是否有新版本发布
- 🔄 手动/自动模式:支持自动轮询和手动触发两种工作模式
- 🎨 多种通知方式:支持系统原生confirm对话框或自定义通知UI
- 📱 页面可见性感知:可配置在页面隐藏时暂停检测,节省资源
- ⚡ 轻量高效:核心代码简洁,无第三方依赖
- 🔧 高度可配置:提供丰富的配置选项以满足不同需求
- 🌐 多框架支持:支持原生JavaScript、React、Vue等多种框架
# 使用 npm
npm install update-notify-js
# 使用 yarn
yarn add update-notify-js
# 使用 pnpm
pnpm add update-notify-js<!DOCTYPE html>
<html lang="zh-CN">
<head>
<meta charset="UTF-8">
<title>版本更新检测示例</title>
</head>
<body>
<script src="https://unpkg.com/update-notify-js/dist/index.umd.js"></script>
<script>
// 默认自动轮询:每分钟检测一次,并打印日志与回调
WebVersionChecker.createUpdateNotifier({
pollingInterval: 60000,
debug: true,
onDetected: () => {
console.log('[update-notify-js] 检测到新版本');
},
// 使用自定义提示:确认后手动刷新(演示 location.reload)
notifyType: 'custom',
onUpdate: () => {
console.log('[update-notify-js] 准备刷新页面以更新版本');
const ok = confirm('检测到新版本,是否立即刷新页面以更新?');
if (ok) {
// 手动刷新页面
location.reload();
// 返回 false,避免插件再次调用刷新(因为我们已手动刷新)
return false;
}
return false;
}
});
</script>
</body>
</html><!DOCTYPE html>
<html lang="zh-CN">
<head>
<meta charset="UTF-8">
<title>版本更新检测示例</title>
</head>
<body>
<script src="https://unpkg.com/update-notify-js/dist/index.umd.js"></script>
<script>
// 手动模式:禁用自动轮询,自己控制检测时机
const notifier = WebVersionChecker.createUpdateNotifier({
pollingInterval: null, // 禁用自动轮询
debug: true,
onDetected: () => {
console.log('[update-notify-js] 检测到新版本');
}
});
// 手动启动检测(例如点击按钮时)
document.getElementById('checkUpdateBtn').addEventListener('click', async () => {
const hasUpdate = await notifier.checkUpdate();
console.log('检测完成,是否有更新:', hasUpdate);
});
// 也可以使用 checkNow 静默检测
document.getElementById('checkSilentBtn').addEventListener('click', async () => {
const hasUpdate = await notifier.checkNow();
console.log('静默检测完成,是否有更新:', hasUpdate);
if (hasUpdate) {
// 自定义提示逻辑
if (confirm('发现新版本,是否刷新页面?')) {
location.reload();
}
}
});
</script>
<button id="checkUpdateBtn">检查更新并提示</button>
<button id="checkSilentBtn">静默检查更新</button>
</body>
</html>import { createApp } from 'vue';
import App from './App.vue';
import { createUpdateNotifier, type UpdateNotifierOptions } from 'update-notify-js';
createApp(App).mount('#app');
// 仅生产环境启用
if (import.meta.env.PROD) {
const options: UpdateNotifierOptions = {
pollingInterval: 60000,
notifyType: 'confirm',
promptMessage: '发现新版本,是否立即刷新?',
onDetected: () => {
console.log('检测到新版本');
}
};
createUpdateNotifier(options);
}import { createApp } from 'vue';
import App from './App.vue';
import { createUpdateNotifier, type UpdateNotifierOptions } from 'update-notify-js';
const app = createApp(App);
app.mount('#app');
// 仅生产环境启用
if (import.meta.env.PROD) {
// 手动模式:禁用自动轮询
const options: UpdateNotifierOptions = {
pollingInterval: null, // 禁用自动轮询
notifyType: 'confirm',
promptMessage: '发现新版本,是否立即刷新?',
onDetected: () => {
console.log('检测到新版本');
}
};
const notifier = createUpdateNotifier(options);
// 在需要时手动检测更新
window.checkForUpdate = async () => {
const hasUpdate = await notifier.checkUpdate();
console.log('检测完成,是否有更新:', hasUpdate);
};
// 静默检测
window.checkSilently = async () => {
const hasUpdate = await notifier.checkNow();
console.log('静默检测完成,是否有更新:', hasUpdate);
};
}import React from 'react';
import ReactDOM from 'react-dom/client';
import App from './App';
import { createUpdateNotifier, type UpdateNotifierOptions } from 'update-notify-js';
ReactDOM.createRoot(document.getElementById('root') as HTMLElement).render(
<React.StrictMode>
<App />
</React.StrictMode>
);
if (process.env.NODE_ENV === 'production') {
const options: UpdateNotifierOptions = {
pollingInterval: 60000,
notifyType: 'confirm',
promptMessage: '发现新版本,是否立即刷新?',
debug: false
};
createUpdateNotifier(options);
}import React from 'react';
import ReactDOM from 'react-dom/client';
import App from './App';
import { createUpdateNotifier, type UpdateNotifierOptions } from 'update-notify-js';
ReactDOM.createRoot(document.getElementById('root') as HTMLElement).render(
<React.StrictMode>
<App />
</React.StrictMode>
);
if (process.env.NODE_ENV === 'production') {
// 手动模式:禁用自动轮询
const options: UpdateNotifierOptions = {
pollingInterval: null, // 禁用自动轮询
notifyType: 'confirm',
promptMessage: '发现新版本,是否立即刷新?',
debug: false
};
const notifier = createUpdateNotifier(options);
// 暴露到全局供组件调用
window.versionNotifier = notifier;
}| 配置项 | 类型 | 默认值 | 说明 |
|---|---|---|---|
pollingInterval |
number | null |
10000 |
轮询间隔时间(毫秒)。设置为 null 或 0 则禁用自动轮询,进入手动模式 |
notifyType |
'confirm' | 'custom' |
'confirm' |
提示用户更新的方式。'confirm' 使用系统原生对话框,'custom' 使用自定义函数 |
onUpdate |
() => boolean | Promise<boolean> |
undefined |
自定义更新提示函数(当 notifyType='custom' 时使用),返回 true 表示确认刷新 |
onDetected |
() => void |
() => {} |
检测到更新时的回调函数 |
pauseOnHidden |
boolean |
true |
是否在页面隐藏时暂停检测(仅在自动轮询模式下有效) |
immediate |
boolean |
true |
是否立即开始检测(仅在自动轮询模式下有效) |
indexPath |
string | string[] |
'/' |
自定义请求路径,可以是单个路径字符串或路径数组。在微前端场景中,可以配置多个子应用入口路径进行统一检测 |
scriptRegex |
RegExp |
/<script.*src=["'](?<src>[^"']+)/gm |
script 标签正则匹配,用于自定义匹配规则 |
excludeScripts |
string[] | RegExp |
undefined |
需要排除的脚本路径列表,支持字符串数组(支持 * 和 ? 通配符)或正则表达式 |
debug |
boolean |
false |
是否在控制台输出日志 |
promptMessage |
string |
'检测到新版本,点击确定将刷新页面并更新' |
默认 confirm 提示文案(用于 notifyType='confirm') |
cacheControl |
RequestCache |
'no-cache' |
fetch 请求的缓存控制选项,默认为 'no-cache',确保获取最新内容 |
| 方法名 | 返回值 | 说明 |
|---|---|---|
start() |
void |
开始版本更新检测(仅在自动轮询模式下有效) |
stop() |
void |
停止版本更新检测(仅在自动轮询模式下有效) |
checkNow() |
Promise<boolean> |
手动触发一次静默检测,返回是否有更新,但不显示提示 |
checkUpdate() |
Promise<boolean> |
手动触发一次检测,如有更新会显示提示,返回是否有更新 |
reset() |
void |
重置状态,清空历史记录 |
createUpdateNotifier(options?: UpdateNotifierOptions): VersionUpdateNotifier创建并返回一个新的版本更新通知器实例。
该插件通过以下方式检测版本更新:
- 脚本资源对比:定期请求应用的入口HTML文件,提取其中的script标签src属性
- 变化检测:将提取到的资源列表与之前保存的列表进行对比
- 更新通知:当发现资源列表发生变化时,认为有新版本发布,通知用户
在微前端架构中,可以通过配置indexPath数组来同时监控多个子应用的更新情况:
// 监控多个子应用
const options = {
pollingInterval: 60000,
indexPath: [
'/', // 主应用
'/sub-app-1/index.html', // 子应用1
'/sub-app-2/index.html' // 子应用2
],
// 其他配置...
};
createUpdateNotifier(options);提示:对于大多数现代前端应用,构建过程会在文件名中注入哈希值。当代码变更时,生成的文件名也会改变,因此可以通过检测script标签src的变化来判断是否有新版本。
- 合理配置路径:根据子应用的实际部署路径配置
indexPath数组 - 统一管理更新:在主应用中集中管理所有子应用的更新检测,提供一致的用户体验
- 差异化配置:可以通过多次调用
createUpdateNotifier为不同子应用创建不同的检测实例,实现差异化的更新策略 - 使用手动模式:对于微前端场景,建议使用手动模式并结合用户操作或应用生命周期事件触发检测
// 为不同子应用创建不同的检测实例
const mainAppNotifier = createUpdateNotifier({
indexPath: '/',
pollingInterval: null,
notifyType: 'custom',
onUpdate: () => {
// 主应用更新提示,可能需要更谨慎的处理
return confirm('主应用有更新,确定要刷新吗?这将影响所有正在使用的子应用');
}
});
const subAppNotifier = createUpdateNotifier({
indexPath: ['/sub-app-1', '/sub-app-2'],
pollingInterval: null,
notifyType: 'custom',
onUpdate: () => {
// 子应用更新提示
return confirm('检测到子应用有更新,确定要刷新页面吗?');
}
});
// 在合适的时机触发检测
function checkAllUpdates() {
mainAppNotifier.checkUpdate();
subAppNotifier.checkUpdate();
}
### 仅在生产环境启用
建议只在生产环境中启用更新检测,以避免开发过程中的干扰:
```ts
// Vue + Vite
if (import.meta.env.PROD) {
createUpdateNotifier(/* options */);
}
// React + Webpack
if (process.env.NODE_ENV === 'production') {
createUpdateNotifier(/* options */);
}轮询间隔不宜过短,建议至少30秒以上,以避免过多的网络请求:
const options = {
pollingInterval: 60000, // 1分钟
// 其他配置...
};对于需要更美观的用户界面,可以使用自定义通知:
const options = {
notifyType: 'custom',
onUpdate: async () => {
// 显示自定义通知UI
// 例如:使用Toast、Modal等组件
return await showCustomNotification(); // 返回用户是否确认更新
}
};欢迎通过以下方式参与贡献:
- 提交Issue报告bug或建议新功能
- Fork仓库并提交Pull Request
- 完善文档和示例
感谢使用 update-notify-js!如有任何问题,欢迎在GitHub上提交Issue。