UNPKG

universal-build-plugin-version-check-test

Version:

一个支持多种前端构建工具的通用插件框架,包括 Vite、Webpack、Rollup 等,提供版本检查、构建优化等功能

295 lines (255 loc) 7.45 kB
/** * 版本检查器模板文件 * 这个文件会被编译成 JavaScript 后注入到 HTML 页面中 */ // 版本检查器配置接口 interface VersionCheckConfig { currentVersion: string; checkInterval: number; enableNotify: boolean; versionFile: string; enableConsoleLog: boolean; maxRetries: number; retryDelay: number; onVersionChange?: (oldVersion: string, newVersion: string) => void; onError?: (error: Error) => void; } // 版本检查器类 class VersionChecker { private config: VersionCheckConfig; private timerId: number | null = null; private retryCount = 0; private isChecking = false; private lastCheckTime = 0; constructor(config: VersionCheckConfig) { this.config = { ...config, }; } /** * 启动版本检查 */ start(): void { if (this.timerId) { this.log('版本检查器已经在运行中'); return; } this.log( `启动版本检查器,当前版本: ${this.config.currentVersion},检查间隔: ${this.config.checkInterval}ms` ); // 立即执行一次检查 this.checkVersion(true); // 设置定时器 this.timerId = window.setInterval(() => { this.checkVersion(); }, this.config.checkInterval); } /** * 停止版本检查 */ stop(): void { if (this.timerId) { clearInterval(this.timerId); this.timerId = null; this.log('版本检查器已停止'); } } /** * 检查版本更新 */ private async checkVersion(isFirstCheck = false): Promise<void> { if (this.isChecking) { this.log('版本检查正在进行中,跳过本次检查'); return; } this.isChecking = true; this.lastCheckTime = Date.now(); try { const versionInfo = await this.fetchVersionInfo(); if (isFirstCheck) { this.updateVersion(versionInfo.version); this.log('开始首次版本检查'); return; } // 获取旧版本信息 const oldVersion = window.localStorage.getItem('version'); // 如果没有旧版本,则不进行检查 if (!oldVersion) { this.log('未找到旧版本信息,跳过本次检查'); this.isChecking = false; return; } if (versionInfo && versionInfo.version && versionInfo.version !== oldVersion) { // 触发版本变更回调 if (this.config.onVersionChange) { this.config.onVersionChange(this.config.currentVersion, versionInfo.version); } await this.handleVersionUpdate(versionInfo); } else { this.log('版本检查完成,无更新'); } // 重置重试计数 this.retryCount = 0; } catch (error) { this.handleError(error as Error); } finally { this.isChecking = false; } } /** * 获取版本信息 */ private async fetchVersionInfo(): Promise<any> { const controller = new AbortController(); const timeoutId = setTimeout(() => controller.abort(), 10000); // 10秒超时 try { const response = await fetch(`/${this.config.versionFile}?t=${Date.now()}`, { method: 'GET', headers: { 'Cache-Control': 'no-cache', Pragma: 'no-cache', }, signal: controller.signal, }); clearTimeout(timeoutId); if (!response.ok) { throw new Error(`HTTP ${response.status}: ${response.statusText}`); } const contentType = response.headers.get('content-type'); if (!contentType || !contentType.includes('application/json')) { throw new Error('响应不是有效的JSON格式'); } return await response.json(); } catch (error) { clearTimeout(timeoutId); throw error; } } /** * 处理版本更新 */ private async handleVersionUpdate(versionInfo: any): Promise<void> { // 显示通知 if (this.config.enableNotify) { await this.showUpdateNotification(versionInfo); } } /** * 显示更新通知 */ private async showUpdateNotification(versionInfo: any): Promise<void> { if (!('Notification' in window)) { this.log('浏览器不支持通知功能'); return; } try { let permission = Notification.permission; if (permission === 'default') { permission = await Notification.requestPermission(); } if (permission === 'granted') { const notification = new Notification('系统更新提示', { body: `检测到新版本 ${versionInfo.version}`, icon: '/favicon.ico', tag: 'version-update', requireInteraction: false, }); // 3秒后自动关闭通知 setTimeout(() => { notification.close(); this.updateVersion(versionInfo.version); }, 3000); } } catch (error) { this.log('显示通知失败:', error); } } /** * 更新版本号 */ private updateVersion(newVersion: string): void { window.localStorage.setItem('version', newVersion ?? ''); } /** * 处理错误 */ private handleError(error: Error): void { this.retryCount++; this.log(`版本检查失败 (${this.retryCount}/${this.config.maxRetries}):`, error.message); // 触发错误回调 if (this.config.onError) { this.config.onError(error); } // 如果达到最大重试次数,停止检查器 if (this.retryCount >= this.config.maxRetries) { this.log('达到最大重试次数,停止版本检查'); this.stop(); return; } // 延迟后重试 setTimeout(() => { this.log(`${this.config.retryDelay}ms 后重试版本检查`); this.checkVersion(); }, this.config.retryDelay); } /** * 日志输出 */ private log(message: string, ...args: any[]): void { if (this.config.enableConsoleLog) { const timestamp = new Date().toLocaleTimeString(); console.log(`[VersionChecker ${timestamp}] ${message}`, ...args); } } /** * 获取检查器状态 */ getStatus(): { isRunning: boolean; isChecking: boolean; retryCount: number; lastCheckTime: number; currentVersion: string; } { return { isRunning: this.timerId !== null, isChecking: this.isChecking, retryCount: this.retryCount, lastCheckTime: this.lastCheckTime, currentVersion: this.config.currentVersion, }; } } // 初始化版本检查器 (function () { 'use strict'; // 配置将在编译时被替换 const config: VersionCheckConfig = __VERSION_CHECK_CONFIG__; const versionChecker = new VersionChecker(config); // 页面加载完成后启动版本检查 if (document.readyState === 'loading') { document.addEventListener('DOMContentLoaded', function () { versionChecker.start(); }); } else { versionChecker.start(); } // 将版本检查器暴露到全局,方便调试 if (typeof window !== 'undefined') { (window as any).__versionChecker = versionChecker; } // 页面卸载时停止检查器 window.addEventListener('beforeunload', function () { versionChecker.stop(); }); // 页面可见性变化时的处理 document.addEventListener('visibilitychange', function () { if (document.hidden) { // 页面隐藏时停止检查 versionChecker.stop(); } else { // 页面显示时重新启动检查 versionChecker.start(); } }); })();