vue-sw-updater 0.0.4 → 0.0.5

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -1,106 +1,142 @@
1
- # Vue Service Worker Updater
2
-
3
- 一个基于 Vue 2 和 Ant Design Vue 的项目更新通知与缓存清理方案。
4
-
5
- ## 功能特性
6
-
7
- * **自动检测更新**: 基于 Service Worker API,自动感知应用版本更新。
8
- * **零侵入集成**: Service Worker 逻辑由本库维护,无需手动编写复杂的 SW 代码。
9
- * **多环境隔离**: 支持 `appName` `env` 参数,生成独立的缓存空间,避免多应用或多环境缓存冲突。
10
- * **全局提示**: 使用 Ant Design Vue Modal 全局弹窗提示用户,样式醒目(警告图标+加粗文字)。
11
- * **强制刷新**: 用户点击“立即更新”后,自动清理当前应用缓存并重载页面,确保加载最新资源。
12
- * **环境检测**: 自动检测浏览器版本,如果不支持 Service Worker 或版本过低,会显示阻断性提示。
13
-
14
- ## 安装
15
-
16
- ```bash
17
- npm install vue-sw-updater --save
18
- # 确保项目中已安装 ant-design-vue 和 vue
19
- npm install ant-design-vue vue --save
20
- ```
21
-
22
- ## 快速使用
23
-
24
- ### 1. 引入插件
25
-
26
- 在你的 `main.js` 或入口文件中:
27
-
28
- ```javascript
29
- import Vue from 'vue';
30
- import VueSWUpdater from 'vue-sw-updater';
31
- import 'ant-design-vue/dist/antd.css';
32
-
33
- // 从你的配置或环境变量中获取信息
34
- const version = process.env.VUE_APP_VERSION || '1.0.0';
35
- const appName = process.env.VUE_APP_NAME || 'my-app';
36
- const env = process.env.NODE_ENV || 'production';
37
-
38
- Vue.use(VueSWUpdater, {
39
- // 必须:应用版本号
40
- version: version,
41
-
42
- // 必须:应用名称(用于隔离缓存)
43
- appName: appName,
44
-
45
- // 必须:部署环境(用于隔离缓存,如 production, staging)
46
- env: env,
47
-
48
- // 可选:Service Worker 文件路径,默认为 /service-worker.js
49
- swUrl: '/service-worker.js',
50
-
51
- // 可选:调试模式
52
- debug: false
53
- });
54
- ```
55
-
56
- ### 2. 部署 Service Worker 文件
57
-
58
- 本库提供了一个通用的 `service-worker.js`,你需要将其包含在你的项目根目录(`public` 目录)中。
59
-
60
- **方式 A:构建时复制 (推荐)**
61
-
62
- 如果你使用 Webpack (Vue CLI),可以使用 `copy-webpack-plugin` 将本库的 SW 文件复制到你的构建目录。
63
-
64
- ```javascript
65
- // vue.config.js
66
- const CopyWebpackPlugin = require('copy-webpack-plugin');
67
- const path = require('path');
68
-
69
- module.exports = {
70
- configureWebpack: {
71
- plugins: [
72
- new CopyWebpackPlugin({
73
- patterns: [
74
- {
75
- from: path.resolve(__dirname, 'node_modules/vue-sw-updater/dist/service-worker.js'),
76
- to: 'service-worker.js' // 输出到 dist 根目录
77
- }
78
- ]
79
- })
80
- ]
81
- }
82
- }
83
- ```
84
-
85
- ## 更新机制说明
86
-
87
- 1. 当传入的 `version` 发生变化时,插件会注册带有新参数的 Service Worker(例如 `/service-worker.js?v=1.0.1&app=my-app&env=production`)。
88
- 2. 浏览器检测到 URL 变化,重新下载并安装 Service Worker。
89
- 3. 新 SW 初始化时,会根据 `appName` + `env` + `version` 生成全新的 Cache Key。
90
- 4. 当检测到新版本等待激活(Waiting)时,弹出**警告样式**的更新提示框。
91
- 5. 用户点击“立即更新”:
92
- * 发送 `SKIP_WAITING` 消息给 SW。
93
- * SW 收到消息后,**立即清理当前应用环境下的旧缓存**。
94
- * SW 执行 `self.skipWaiting()` 激活新版本。
95
- * 页面监听到 `controllerchange` 事件,执行 `window.location.reload()` 刷新页面。
96
-
97
- ## 浏览器支持
98
-
99
- 插件会自动检测以下浏览器版本要求:
100
-
101
- * Chrome: 45+
102
- * Firefox: 44+
103
- * Safari: 11+
104
- * Edge: 17+
105
-
106
- 如果用户浏览器版本低于上述要求,将自动显示全屏提示,建议用户升级。
1
+ # Vue Service Worker Updater
2
+
3
+ 一个基于 Vue 2 和 Ant Design Vue 的项目更新通知与缓存清理方案。支持 Service Worker 自动更新和 HTTP 轮询检测更新双重机制,确保在 HTTPS 和 HTTP 环境下均能可靠运行。
4
+
5
+ ## 功能特性
6
+
7
+ * **双模更新检测**:
8
+ * **Service Worker 模式**: 在 HTTPS 环境下,利用 SW 自动感知应用更新,支持离线缓存和增量更新。
9
+ * **HTTP 轮询模式**: HTTP 环境或不支持 SW 的浏览器中,自动降级为 ETag / Last-Modified 轮询检测。
10
+ * **零侵入集成**: 核心逻辑封装在库内,无需手动编写复杂的 SW 或轮询代码。
11
+ * **多环境隔离**: 支持 `appName` 和 `env` 参数,生成独立的缓存空间,避免多应用或多环境缓存冲突。
12
+ * **全局提示**: 使用 Ant Design Vue Modal 全局弹窗提示用户,样式醒目(警告图标+加粗文字)。
13
+ * **强制刷新**: 用户点击“立即更新”后,自动清理当前应用缓存并重载页面,确保加载最新资源。
14
+ * **环境自适应**: 自动检测环境安全性(HTTPS/localhost),如果环境不安全且配置了轮询参数,自动切换至轮询模式;否则显示环境不支持提示。
15
+
16
+ ## 安装
17
+
18
+ ```bash
19
+ npm install vue-sw-updater --save
20
+ # 确保项目中已安装 ant-design-vue 和 vue
21
+ npm install ant-design-vue vue --save
22
+ ```
23
+
24
+ ## 快速使用
25
+
26
+ ### 1. 引入插件
27
+
28
+ 在你的 `main.js` 或入口文件中:
29
+
30
+ ```javascript
31
+ import Vue from 'vue';
32
+ import VueSWUpdater from 'vue-sw-updater';
33
+ import 'ant-design-vue/dist/antd.css';
34
+
35
+ // 从你的配置或环境变量中获取信息
36
+ const version = process.env.VUE_APP_VERSION || '1.0.0';
37
+ const appName = process.env.VUE_APP_NAME || 'my-app';
38
+ const env = process.env.NODE_ENV || 'production';
39
+
40
+ Vue.use(VueSWUpdater, {
41
+ // [必填] 应用版本号 (当前运行的版本)
42
+ version: version,
43
+
44
+ // [必填] 应用名称(用于 SW 缓存隔离)
45
+ appName: appName,
46
+
47
+ // [必填] 部署环境(用于 SW 缓存隔离)
48
+ env: env,
49
+
50
+ // [可选] Service Worker 文件路径,默认为 /service-worker.js
51
+ swUrl: '/service-worker.js',
52
+
53
+ // [可选] 轮询检测间隔(分钟)。
54
+ // 如果设置为 > 0,当 SW 不可用(如 HTTP 环境)时,将启用轮询模式。
55
+ // 建议设置为 10 或 30。
56
+ pollingInterval: 10,
57
+
58
+ // [可选] 检测更新的目标 URL (仅轮询模式使用)
59
+ // 默认为空字符串 '',即检测当前页面 (index.html) 的 Header 变化
60
+ checkUrl: '',
61
+
62
+ // [可选] 调试模式,开启后控制台会输出更多日志
63
+ debug: false
64
+ });
65
+ ```
66
+
67
+ ### 2. 构建配置 (针对不同模式)
68
+
69
+ #### A. 准备 Service Worker (HTTPS 模式推荐)
70
+
71
+ 本库提供了一个通用的 `service-worker.js`,你需要将其包含在你的项目根目录(`public` 目录)中。
72
+
73
+ **Webpack / Vue CLI 配置:**
74
+
75
+ ```javascript
76
+ // vue.config.js
77
+ const CopyWebpackPlugin = require('copy-webpack-plugin');
78
+ const path = require('path');
79
+
80
+ module.exports = {
81
+ configureWebpack: {
82
+ plugins: [
83
+ new CopyWebpackPlugin({
84
+ patterns: [
85
+ {
86
+ from: path.resolve(__dirname, 'node_modules/vue-sw-updater/dist/service-worker.js'),
87
+ to: 'service-worker.js' // 输出到 dist 根目录
88
+ }
89
+ ]
90
+ })
91
+ ]
92
+ }
93
+ }
94
+ ```
95
+
96
+ #### B. HTTP 轮询模式配置
97
+
98
+ 无需额外文件。插件会自动轮询当前页面(或指定的 `checkUrl`)的 HTTP 响应头:
99
+ * **ETag**: 资源唯一标识
100
+ * **Last-Modified**: 资源最后修改时间
101
+
102
+ **注意**: 请确保你的 Web 服务器(Nginx/Apache/IIS)已配置为返回这些 Header。对于 SPA 应用的入口文件 (`index.html`),通常默认都会返回。
103
+
104
+ ## 运行机制
105
+
106
+ ### 自动模式选择
107
+
108
+ 插件初始化时会执行以下判断:
109
+
110
+ 1. **检查 Service Worker 支持**:
111
+ * 如果是 HTTPS 或 localhost,且浏览器支持 SW -> **启用 SW 模式**。
112
+ * 如果是 HTTP (非 localhost) 或浏览器不支持 SW -> **进入降级判断**。
113
+
114
+ 2. **降级判断**:
115
+ * 如果配置了 `pollingInterval > 0` -> **启用 HTTP 轮询模式**。
116
+ * 如果没有配置轮询 -> **显示“环境不支持”错误提示** (BrowserError Modal)。
117
+
118
+ ### SW 模式工作流
119
+
120
+ 1. 插件注册 `service-worker.js?v=1.0.0&app=my-app...`。
121
+ 2. 浏览器发现 URL 变化,下载新 SW。
122
+ 3. 新 SW 安装并等待激活。
123
+ 4. 插件检测到 `waiting` 状态,弹出更新提示框。
124
+ 5. 用户点击更新 -> 清理缓存 -> 强制刷新。
125
+
126
+ ### HTTP 轮询模式工作流
127
+
128
+ 1. 插件启动定时器 (例如每 10 分钟)。
129
+ 2. 定时发送 `HEAD` 请求检测目标 URL (默认当前页面)。
130
+ 3. 对比响应头中的 `ETag` 或 `Last-Modified` 与页面加载时是否一致。
131
+ 4. 如果发现 Header 变更,视为有新版本发布,弹出更新提示框。
132
+ 5. 用户点击更新 -> 强制刷新 (`window.location.reload(true)`).
133
+
134
+ ## 浏览器支持
135
+
136
+ 插件会自动处理兼容性,最低要求:
137
+ * **Edge**: 17+
138
+ * **Chrome**: 45+
139
+ * **Firefox**: 44+
140
+ * **Safari**: 11.1+
141
+
142
+ 如果浏览器版本过低,无论哪种模式都会显示阻断性提示。
@@ -22,7 +22,7 @@ const BLACKLIST = [
22
22
  console.log(`[VueSWUpdater] Service Worker 初始化. App: ${APP_NAME}, Env: ${ENV}, Version: ${VERSION}, Cache: ${CACHE_NAME}`);
23
23
 
24
24
  self.addEventListener('install', (event) => {
25
- console.log('[VueSWUpdater] Installing...');
25
+ console.log('[VueSWUpdater] 正在安装...');
26
26
  event.waitUntil(
27
27
  caches.open(CACHE_NAME).then((cache) => {
28
28
  // 仅缓存核心入口文件,其他资源依赖运行时缓存
@@ -30,7 +30,7 @@ self.addEventListener('install', (event) => {
30
30
  './',
31
31
  './index.html'
32
32
  ]).catch(err => {
33
- console.warn('[VueSWUpdater] Pre-caching failed:', err);
33
+ console.warn('[VueSWUpdater] 预缓存失败:', err);
34
34
  });
35
35
  })
36
36
  );
@@ -38,14 +38,14 @@ self.addEventListener('install', (event) => {
38
38
  });
39
39
 
40
40
  self.addEventListener('activate', (event) => {
41
- console.log('[VueSWUpdater] Activating...');
41
+ console.log('[VueSWUpdater] 正在激活...');
42
42
  event.waitUntil(
43
43
  caches.keys().then((keyList) => {
44
44
  return Promise.all(keyList.map((key) => {
45
45
  // 清理旧版本缓存 (只清理本插件前缀的缓存)
46
46
  // 逻辑:如果是同一个 App 和 Env,但是版本不同,则清理
47
47
  if (key.startsWith(CACHE_PREFIX) && key !== CACHE_NAME) {
48
- console.log('[VueSWUpdater] Removing old cache:', key);
48
+ console.log('[VueSWUpdater] 移除旧缓存:', key);
49
49
  return caches.delete(key);
50
50
  }
51
51
  }));
@@ -57,7 +57,7 @@ self.addEventListener('activate', (event) => {
57
57
  // 监听 skipWaiting 消息(由 UI 组件触发)
58
58
  self.addEventListener('message', (event) => {
59
59
  if (event.data && event.data.type === 'SKIP_WAITING') {
60
- console.log('[VueSWUpdater] Skip Waiting received');
60
+ console.log('[VueSWUpdater] 收到 Skip Waiting 指令');
61
61
 
62
62
  // 强制清理所有缓存(不仅仅是旧版本,确保彻底)
63
63
  // 注意:这里只清理当前 APP_NAME 和 ENV 下的缓存,防止误删其他应用缓存
@@ -65,7 +65,7 @@ self.addEventListener('message', (event) => {
65
65
  caches.keys().then(keys => {
66
66
  keys.forEach(key => {
67
67
  if (key.startsWith(CACHE_PREFIX)) {
68
- console.log('[VueSWUpdater] Force clearing cache before update:', key);
68
+ console.log('[VueSWUpdater] 更新前强制清理缓存:', key);
69
69
  caches.delete(key);
70
70
  }
71
71
  });
@@ -9842,6 +9842,7 @@ __webpack_require__.r(__webpack_exports__);
9842
9842
  // EXPORTS
9843
9843
  __webpack_require__.d(__webpack_exports__, {
9844
9844
  BrowserError: function() { return /* reexport */ BrowserError; },
9845
+ PollingUpdater: function() { return /* reexport */ PollingUpdater; },
9845
9846
  ServiceWorkerUpdater: function() { return /* reexport */ ServiceWorkerUpdater; },
9846
9847
  UpdateModal: function() { return /* reexport */ UpdateModal; },
9847
9848
  checkBrowserSupport: function() { return /* reexport */ checkBrowserSupport; },
@@ -10038,7 +10039,7 @@ class ServiceWorkerUpdater {
10038
10039
  updated: registration => {
10039
10040
  console.log('新内容可用,请刷新。');
10040
10041
  this.registration = registration;
10041
- // Trigger the update callback (Show UI)
10042
+ // 触发更新回调 (显示 UI)
10042
10043
  this.onUpdateFound(this);
10043
10044
  },
10044
10045
  offline: () => {
@@ -10050,7 +10051,7 @@ class ServiceWorkerUpdater {
10050
10051
  }
10051
10052
  });
10052
10053
 
10053
- // Handle controller change (reload page)
10054
+ // 处理 controller 变更 (刷新页面)
10054
10055
  let refreshing = false;
10055
10056
  if (navigator.serviceWorker) {
10056
10057
  navigator.serviceWorker.addEventListener('controllerchange', () => {
@@ -10066,7 +10067,7 @@ class ServiceWorkerUpdater {
10066
10067
  }
10067
10068
  }
10068
10069
 
10069
- // Called when user accepts the update
10070
+ // 当用户接受更新时调用
10070
10071
  applyUpdate() {
10071
10072
  if (!this.registration || !this.registration.waiting) {
10072
10073
  console.warn('未找到等待中的 Service Worker。');
@@ -10074,7 +10075,7 @@ class ServiceWorkerUpdater {
10074
10075
  window.location.reload();
10075
10076
  return;
10076
10077
  }
10077
- // Send message to SW to skip waiting
10078
+ // 发送消息给 SW 以跳过等待
10078
10079
  // 这会触发 SW 中的 message 监听,执行 self.skipWaiting()
10079
10080
  // 进而触发 controllerchange,最终执行上面的 window.location.reload()
10080
10081
  this.registration.waiting.postMessage({
@@ -10082,6 +10083,90 @@ class ServiceWorkerUpdater {
10082
10083
  });
10083
10084
  }
10084
10085
  }
10086
+ ;// ./src/lib/utils/PollingUpdater.js
10087
+ class PollingUpdater {
10088
+ constructor(options = {}) {
10089
+ this.checkUrl = options.checkUrl || ''; // 默认为当前页面
10090
+ this.intervalMinutes = options.interval || 0; // 0 表示禁用
10091
+ this.onUpdateFound = options.onUpdateFound || (() => {});
10092
+ this.onError = options.onError || (() => {});
10093
+ this.timer = null;
10094
+
10095
+ // 记录 ETag/Last-Modified 状态
10096
+ this.lastEtag = null;
10097
+ this.lastModified = null;
10098
+ }
10099
+ init() {
10100
+ if (this.intervalMinutes <= 0) {
10101
+ console.log('[VueSWUpdater] 轮询时间未设置或为0,不启用轮询。');
10102
+ return;
10103
+ }
10104
+ console.log(`[VueSWUpdater] 启用 HTTP ETag/Last-Modified 检测,轮询间隔: ${this.intervalMinutes} 分钟`);
10105
+
10106
+ // 执行初始检测以建立基准
10107
+ this.checkUpdate(true);
10108
+ this.startPolling();
10109
+ }
10110
+ startPolling() {
10111
+ const ms = this.intervalMinutes * 60 * 1000;
10112
+ this.timer = setInterval(() => {
10113
+ this.checkUpdate(false);
10114
+ }, ms);
10115
+ }
10116
+ checkUpdate(isInit = false) {
10117
+ // 添加时间戳防止缓存
10118
+ // 处理 checkUrl 已包含查询参数的情况
10119
+ const separator = this.checkUrl.includes('?') ? '&' : '?';
10120
+ // 使用 'check_t' 避免与可能存在的 't' 参数冲突
10121
+ const url = `${this.checkUrl}${separator}check_t=${Date.now()}`;
10122
+ fetch(url, {
10123
+ method: 'HEAD',
10124
+ cache: 'no-cache'
10125
+ }).then(response => {
10126
+ if (!response.ok) {
10127
+ // 如果网络错误或 404,跳过此次检测
10128
+ return;
10129
+ }
10130
+ const etag = response.headers.get('ETag');
10131
+ const lastModified = response.headers.get('Last-Modified');
10132
+ if (isInit) {
10133
+ this.lastEtag = etag;
10134
+ this.lastModified = lastModified;
10135
+ // console.log(`[VueSWUpdater] 初始版本信息 - ETag: ${etag}, Last-Modified: ${lastModified}`);
10136
+ } else {
10137
+ let changed = false;
10138
+
10139
+ // 检查 ETag
10140
+ if (etag && this.lastEtag && etag !== this.lastEtag) {
10141
+ changed = true;
10142
+ console.log(`[VueSWUpdater] 检测到更新 (ETag变化): ${this.lastEtag} -> ${etag}`);
10143
+ }
10144
+ // 检查 Last-Modified (作为后备或补充)
10145
+ else if (lastModified && this.lastModified && lastModified !== this.lastModified) {
10146
+ changed = true;
10147
+ console.log(`[VueSWUpdater] 检测到更新 (Last-Modified变化): ${this.lastModified} -> ${lastModified}`);
10148
+ }
10149
+ if (changed) {
10150
+ this.stopPolling(); // 一旦发现更新,停止轮询
10151
+ this.onUpdateFound(this);
10152
+ }
10153
+ }
10154
+ }).catch(err => {
10155
+ console.error('[VueSWUpdater] 版本检测失败:', err);
10156
+ });
10157
+ }
10158
+ stopPolling() {
10159
+ if (this.timer) {
10160
+ clearInterval(this.timer);
10161
+ this.timer = null;
10162
+ }
10163
+ }
10164
+ applyUpdate() {
10165
+ console.log('[VueSWUpdater] 正在刷新页面以应用更新...');
10166
+ // 强制从服务器重新加载以获取新的 index.html 和资源
10167
+ window.location.reload(true);
10168
+ }
10169
+ }
10085
10170
  // EXTERNAL MODULE: ./node_modules/ua-parser-js/src/ua-parser.js
10086
10171
  var ua_parser = __webpack_require__(5135);
10087
10172
  var ua_parser_default = /*#__PURE__*/__webpack_require__.n(ua_parser);
@@ -10089,7 +10174,7 @@ var ua_parser_default = /*#__PURE__*/__webpack_require__.n(ua_parser);
10089
10174
 
10090
10175
  const MIN_VERSIONS = {
10091
10176
  Chrome: 45,
10092
- // Service Worker supported since 40, but safer to say 45+
10177
+ // Service Worker 40 起支持,但建议 45+
10093
10178
  Firefox: 44,
10094
10179
  Safari: 11,
10095
10180
  // Safari 11.1+
@@ -10108,22 +10193,29 @@ function checkBrowserSupport() {
10108
10193
  browserVersion: browser.version
10109
10194
  };
10110
10195
 
10111
- // 1. Check Service Worker API
10196
+ // 1. 检查 Service Worker API
10112
10197
  if (!('serviceWorker' in navigator)) {
10113
10198
  result.supported = false;
10114
- result.message = '当前浏览器不支持 Service Worker API。';
10199
+ // 检查是否由于不安全上下文导致
10200
+ const isLocalhost = window.location.hostname === 'localhost' || window.location.hostname === '127.0.0.1';
10201
+ const isHttps = window.location.protocol === 'https:';
10202
+ if (!isLocalhost && !isHttps) {
10203
+ result.message = 'Service Worker 需要 HTTPS 环境或 localhost。请检查您的访问地址是否安全。';
10204
+ } else {
10205
+ result.message = '当前浏览器不支持 Service Worker API。请尝试升级浏览器或检查浏览器设置。';
10206
+ }
10115
10207
  return result;
10116
10208
  }
10117
10209
 
10118
- // 2. Check Version
10210
+ // 2. 检查版本
10119
10211
  if (MIN_VERSIONS[name]) {
10120
10212
  if (version < MIN_VERSIONS[name]) {
10121
10213
  result.supported = false;
10122
10214
  result.message = `浏览器版本过低。${name} ${version} < 需要 ${MIN_VERSIONS[name]}+`;
10123
10215
  }
10124
10216
  } else {
10125
- // Unknown browser, but supports SW (passed step 1)
10126
- // We can assume it's okay or warn user. Let's assume okay if SW API exists.
10217
+ // 未知浏览器,但支持 SW (通过了步骤 1)
10218
+ // 我们假设它是可用的。如果存在 SW API,则通过。
10127
10219
  console.warn('检测到未知浏览器,但存在 Service Worker API。');
10128
10220
  }
10129
10221
  return result;
@@ -15479,55 +15571,86 @@ var BrowserError_component = normalizeComponent(
15479
15571
 
15480
15572
 
15481
15573
 
15574
+
15482
15575
  // 导出单独的组件和工具,以便高级用户按需使用
15483
15576
 
15484
15577
  const Plugin = {
15485
15578
  install(Vue, options = {}) {
15486
- // 1. Browser Check
15579
+ // 1. 浏览器环境检测
15487
15580
  const checkResult = checkBrowserSupport();
15581
+ let usePolling = false;
15582
+
15583
+ // 检查是否需要降级到轮询模式
15584
+ // 降级条件:不支持 SW 且设置了轮询间隔
15488
15585
  if (!checkResult.supported) {
15489
- // Mount BrowserError
15490
- const ErrorConstructor = Vue.extend(BrowserError);
15491
- const errorInstance = new ErrorConstructor();
15492
- errorInstance.$mount();
15493
- document.body.appendChild(errorInstance.$el);
15494
-
15495
- // Delay show slightly to ensure mount
15496
- Vue.nextTick(() => {
15497
- errorInstance.show(checkResult);
15498
- });
15499
- return; // Stop initialization of SW
15586
+ if (options.pollingInterval && options.pollingInterval > 0) {
15587
+ usePolling = true;
15588
+ // 如果通过轮询处理,则不在控制台显示错误信息
15589
+ console.warn('[VueSWUpdater] Service Worker 不可用 (' + checkResult.message + '),切换到 HTTP 轮询模式。');
15590
+ } else {
15591
+ // 挂载 BrowserError 组件
15592
+ const ErrorConstructor = Vue.extend(BrowserError);
15593
+ const errorInstance = new ErrorConstructor();
15594
+ errorInstance.$mount();
15595
+ document.body.appendChild(errorInstance.$el);
15596
+
15597
+ // 稍作延迟以确保挂载完成
15598
+ Vue.nextTick(() => {
15599
+ errorInstance.show(checkResult);
15600
+ });
15601
+ return; // 停止初始化
15602
+ }
15500
15603
  }
15501
15604
 
15502
- // 2. Prepare UpdateModal Instance
15605
+ // 2. 准备更新弹窗实例
15503
15606
  let modalInstance = null;
15504
-
15505
- // 3. Service Worker Updater
15506
- // 构造带参数的 SW URL
15507
- let swUrl = options.swUrl || '/service-worker.js';
15508
- const params = new URLSearchParams();
15509
- if (options.version) params.append('v', options.version);
15510
- if (options.appName) params.append('app', options.appName);
15511
- if (options.env) params.append('env', options.env);
15512
- const queryString = params.toString();
15513
- if (queryString) {
15514
- swUrl += (swUrl.indexOf('?') === -1 ? '?' : '&') + queryString;
15515
- }
15516
- const updater = new ServiceWorkerUpdater({
15517
- swUrl: swUrl,
15518
- onUpdateFound: () => {
15519
- if (modalInstance) {
15520
- modalInstance.show();
15607
+ let updater = null;
15608
+
15609
+ // 3. 初始化更新器
15610
+ if (usePolling) {
15611
+ updater = new PollingUpdater({
15612
+ version: options.version,
15613
+ checkUrl: options.checkUrl,
15614
+ interval: options.pollingInterval,
15615
+ onUpdateFound: () => {
15616
+ if (modalInstance) {
15617
+ modalInstance.show();
15618
+ }
15619
+ },
15620
+ onError: err => {
15621
+ if (options.debug) {
15622
+ console.error('[VueSWUpdater] 轮询错误:', err);
15623
+ }
15521
15624
  }
15522
- },
15523
- onError: err => {
15524
- if (options.debug) {
15525
- console.error('[VueSWUpdater] SW 注册错误:', err);
15625
+ });
15626
+ } else {
15627
+ // Service Worker Updater
15628
+ // 构造带参数的 SW URL
15629
+ let swUrl = options.swUrl || '/service-worker.js';
15630
+ const params = new URLSearchParams();
15631
+ if (options.version) params.append('v', options.version);
15632
+ if (options.appName) params.append('app', options.appName);
15633
+ if (options.env) params.append('env', options.env);
15634
+ const queryString = params.toString();
15635
+ if (queryString) {
15636
+ swUrl += (swUrl.indexOf('?') === -1 ? '?' : '&') + queryString;
15637
+ }
15638
+ updater = new ServiceWorkerUpdater({
15639
+ swUrl: swUrl,
15640
+ onUpdateFound: () => {
15641
+ if (modalInstance) {
15642
+ modalInstance.show();
15643
+ }
15644
+ },
15645
+ onError: err => {
15646
+ if (options.debug) {
15647
+ console.error('[VueSWUpdater] SW 注册错误:', err);
15648
+ }
15526
15649
  }
15527
- }
15528
- });
15650
+ });
15651
+ }
15529
15652
 
15530
- // 4. Mount UpdateModal
15653
+ // 4. 挂载更新弹窗组件
15531
15654
  const ModalConstructor = Vue.extend(UpdateModal);
15532
15655
  modalInstance = new ModalConstructor({
15533
15656
  propsData: {
@@ -15537,13 +15660,13 @@ const Plugin = {
15537
15660
  modalInstance.$mount();
15538
15661
  document.body.appendChild(modalInstance.$el);
15539
15662
 
15540
- // 5. Init Updater
15541
- // Wait for window load to avoid affecting page load performance
15663
+ // 5. 启动更新器
15664
+ // 等待页面加载完成,避免影响首屏性能
15542
15665
  window.addEventListener('load', () => {
15543
15666
  updater.init();
15544
15667
  });
15545
15668
 
15546
- // 6. Expose to Vue prototype
15669
+ // 6. 挂载到 Vue 原型
15547
15670
  Vue.prototype.$swUpdater = updater;
15548
15671
  }
15549
15672
  };