mirror of
https://ghfast.top/https://github.com/zsjy/halo-theme-dream2.0-plus.git
synced 2025-03-16 12:29:41 +08:00
1 line
12 KiB
JavaScript
1 line
12 KiB
JavaScript
(()=>{var __webpack_modules__={"./src/js/sw.js":()=>{eval("(function () {\r\n if (self.document) {\r\n const currentScriptUrl = document.currentScript.src\r\n const uninstall = new URLSearchParams(currentScriptUrl.split('?')[1]).get('uninstall')\r\n if (uninstall) {\r\n console.log('uninstall service worker.')\r\n navigator.serviceWorker.getRegistrations().then(function (registrations) {\r\n for (let registration of registrations) {\r\n registration.active && registration.active.scriptURL && registration.active.scriptURL.indexOf('/sw.min.js') !== -1 && registration.unregister()\r\n }\r\n })\r\n window.caches && caches.keys && caches.keys().then(function (keys) {\r\n keys.forEach(function (key) {\r\n console.log('delete cache', key)\r\n caches.delete(key)\r\n })\r\n })\r\n } else {\r\n navigator.serviceWorker.register(document.currentScript.src)\r\n .catch(function (error) {\r\n console.log('cache failed with ' + error) // registration failed\r\n })\r\n }\r\n } else {\r\n //可以进行版本修改,删除缓存\r\n const version = '1.0.0'\r\n // 取得缓存名称\r\n const cacheName = `Dream2-plus-${version}`\r\n // 取得请求参数\r\n const envParams = new URLSearchParams(location.href.split('?')[1])\r\n // 是否开启多cdn源并发请求\r\n const isCdnConcurrentRequest = envParams.get('concurrent')\r\n // 是否开启全站缓存\r\n const isGlobalCache = envParams.get('cache')\r\n // 主题路径\r\n const themePath = location.origin + '/themes/theme-dream2-plus'\r\n // cdn源站点,一行一个\r\n const cdnSource = envParams.get('cdn').split(',').filter(item => item.length > 0 && item.indexOf('http') === 0)\r\n\r\n // 禁止被处理(优先级别最高)\r\n // 后端 api 不进行缓存\r\n const notHandleList = [\r\n location.origin + '/api',\r\n ]\r\n\r\n // 需要走cdn和缓存的请求(cdn优先于缓存)\r\n const cdnAndCacheList = [\r\n themePath,\r\n ...cdnSource\r\n ]\r\n\r\n //对这里面的请求只会走缓存,先缓存后下载\r\n // jsdeliver cdn 不稳定,只走缓存\r\n const onlyCacheList = [\r\n location.origin + '/upload',\r\n 'https://cdn.jsdelivr.net/'\r\n ]\r\n\r\n const cdnHandle = {\r\n theme: {\r\n handleRequest: url => {\r\n if (url.indexOf(themePath) !== 0) return\r\n const path = url.substring(themePath.length)\r\n const version = new URLSearchParams(url.split('?')[1]).get('mew') || 'latest'\r\n return [\r\n url,\r\n ...cdnSource.map(value => `${value}/halo-theme-dream2-plus@${version}${path}`)\r\n ]\r\n },\r\n },\r\n npm: {\r\n handleRequest: url => {\r\n for (let index in cdnSource) {\r\n if (url.indexOf(cdnSource[index]) === 0) {\r\n const path = url.substring(cdnSource[index].length)\r\n return cdnSource.map(value => value + path)\r\n }\r\n }\r\n }\r\n },\r\n }\r\n\r\n /**\r\n * 判断ur是否符合list列表中的要求\r\n *\r\n * @param list\r\n * @param url\r\n * @returns {boolean}\r\n */\r\n function isExitInUrlList(list, url) {\r\n return list.some(function (value) {\r\n return url.indexOf(value) === 0\r\n })\r\n }\r\n\r\n /**\r\n * 判断两个url是否属于同一个请求,过滤掉部分参数\r\n *\r\n * @param urla\r\n * @param urlb\r\n * @returns {boolean}\r\n */\r\n function isSameRequest(urla, urlb) {\r\n // 除了这这些参数,其它的查询参数必须要一致,才认为是同一个请求\r\n const white_query = new Set([\r\n 'mew', // 自定义的版本号\r\n 'v',\r\n 'version',\r\n 't',\r\n 'time',\r\n 'ts',\r\n 'timestamp'\r\n ])\r\n\r\n const a_url = urla.split('?')\r\n const b_url = urlb.split('?')\r\n if (a_url[0] !== b_url[0]) {\r\n return false\r\n }\r\n\r\n const a_params = new URLSearchParams('?' + a_url[1])\r\n const b_params = new URLSearchParams('?' + b_url[1])\r\n\r\n // 显示所有的键\r\n for (const key of a_params.keys()) {\r\n if (white_query.has(key)) {//对于版本号的key 忽略\r\n continue\r\n }\r\n if (a_params.get(key) !== b_params.get(key)) {//其它key的值必须相等,比如type=POST 这种\r\n return false\r\n }\r\n }\r\n\r\n return true\r\n }\r\n\r\n //添加缓存\r\n self.addEventListener('install', function (event) {\r\n console.log('install service worker.')\r\n event.waitUntil(self.skipWaiting()) //这样会触发activate事件\r\n })\r\n\r\n // 激活\r\n self.addEventListener('activate', function (event) {\r\n console.log('service worker activate.')\r\n const mainCache = [cacheName]\r\n event.waitUntil(\r\n caches.keys().then(function (cacheNames) {\r\n return Promise.all(\r\n cacheNames.map(function (cacheName) {\r\n if (mainCache.indexOf(cacheName) === -1) {//没有找到该版本号下面的缓存\r\n // When it doesn't match any condition, delete it.\r\n console.info('version changed, clean the cache, SW: deleting ' + cacheName)\r\n return caches.delete(cacheName)\r\n }\r\n })\r\n )\r\n })\r\n )\r\n return self.clients.claim()\r\n })\r\n\r\n // 拦截请求使用缓存的内容\r\n self.addEventListener('fetch', function (event) {\r\n // 非 get 请求不处理,被禁止处理的地址不处理\r\n if (event.request.method !== 'GET'\r\n || isExitInUrlList(notHandleList, event.request.url)) {\r\n return false\r\n }\r\n const isCdnAndCache = isExitInUrlList(cdnAndCacheList, event.request.url)\r\n const isOnlyCacheList = isExitInUrlList(onlyCacheList, event.request.url)\r\n // cdn并发请求未开启 或 请求没有被任何路由命中\r\n if (!isCdnConcurrentRequest || !(isCdnAndCache || isOnlyCacheList)) {\r\n // 不需要全站离线\r\n if (!isGlobalCache) {\r\n return false\r\n }\r\n // 先发起请求,如果请求失败则读取离线缓存\r\n event.respondWith(caches.open(cacheName)\r\n .then(cache => {\r\n return fetch(event.request)\r\n .then((response) => {\r\n if (response.status === 200) cache.put(event.request, response.clone())\r\n return response\r\n })\r\n .catch(() => cache.match(event.request))\r\n })\r\n )\r\n return true\r\n }\r\n // 劫持 HTTP Request\r\n event.respondWith(\r\n caches.open(cacheName).then(function (cache) {\r\n // 查找缓存\r\n return cache.match(event.request).then(function (cacheResponse) {\r\n // 直接返回缓存\r\n if (cacheResponse) return cacheResponse\r\n\r\n return handleRequest(event.request, isCdnAndCache)\r\n .then((response) => {\r\n const responseClone = response.clone()\r\n // ignoreSearch 忽略请求参数进行查找,用于匹配不同版本\r\n cache.matchAll(event.request, {'ignoreSearch': true})\r\n .then(function (cache_response_list) {\r\n // 删除旧版本的缓存文件\r\n if (cache_response_list) {\r\n for (const cache_response of cache_response_list) {\r\n const responseUrl = cache_response.url || cache_response.headers.get('service-worker-origin')\r\n if (isSameRequest(responseUrl, event.request.url)) {\r\n cache.delete(responseUrl)\r\n }\r\n }\r\n }\r\n cache.put(event.request, responseClone)\r\n })\r\n return response\r\n })\r\n .catch(error => {\r\n console.error(error)\r\n return cache.matchAll(event.request, {'ignoreSearch': true})\r\n .then(function (cache_response_list) {\r\n // 从缓存中取得历史版本的文件\r\n if (cache_response_list) {\r\n for (const cache_response of cache_response_list) {\r\n if (isSameRequest(cache_response.url || cache_response.headers.get('service-worker-origin'), event.request.url)) {\r\n return cache_response\r\n }\r\n }\r\n }\r\n })\r\n })\r\n })\r\n })\r\n )\r\n })\r\n\r\n /**\r\n * 处理匹配的请求\r\n * @param req\r\n * @param isCdnAndCache\r\n * @returns {Promise<Response>|*}\r\n */\r\n function handleRequest(req, isCdnAndCache) {\r\n // 不是cdn缓存或者未开启cdn并发,直接进行查询并返回\r\n if (!isCdnAndCache || !isCdnConcurrentRequest) return fetch(req)\r\n\r\n // 匹配 cdn\r\n for (const type in cdnHandle) {\r\n const urls = cdnHandle[type].handleRequest(req.url)\r\n if (urls) return fetchAny(req.url, urls)\r\n }\r\n // 没有匹配到url,直接发起请求\r\n return fetch(req)\r\n }\r\n\r\n // Promise.any 的 polyfill\r\n function createPromiseAny() {\r\n Promise.any = function (promises) {\r\n return new Promise((resolve, reject) => {\r\n promises = Array.isArray(promises) ? promises : []\r\n let len = promises.length\r\n let errs = []\r\n if (len === 0)\r\n return reject(new AggregateError('All promises were rejected'))\r\n promises.forEach((p) => {\r\n if (!(p instanceof Promise)) return reject(p)\r\n p.then(\r\n (res) => resolve(res),\r\n (err) => {\r\n len--\r\n errs.push(err)\r\n if (len === 0) reject(new AggregateError(errs))\r\n }\r\n )\r\n })\r\n })\r\n }\r\n }\r\n\r\n // 发送所有请求\r\n function fetchAny(originUrl, urls) {\r\n // 中断一个或多个请求\r\n const controller = new AbortController()\r\n const signal = controller.signal\r\n\r\n // 遍历将所有的请求地址转换为promise\r\n const PromiseAll = urls.map((url) => {\r\n // eslint-disable-next-line no-async-promise-executor\r\n return new Promise(async (resolve, reject) => {\r\n fetch(url, {signal})\r\n .then(async res => { // 重新封装响应\r\n const newHeaders = new Headers(res.headers)\r\n newHeaders.set('service-worker-origin', originUrl)\r\n return new Response(await res.arrayBuffer(), {\r\n status: res.status,\r\n headers: newHeaders,\r\n })\r\n })\r\n .then((res) => {\r\n if (res.status !== 200) {\r\n reject(res)\r\n return\r\n }\r\n controller.abort() // 中断\r\n resolve(res)\r\n })\r\n .catch(() => reject(null)) // 去除中断的错误信息\r\n })\r\n })\r\n\r\n // 判断浏览器是否支持 Promise.any\r\n if (!Promise.any) createPromiseAny()\r\n\r\n // 谁先返回\"成功状态\"则返回谁的内容\r\n return Promise.any(PromiseAll)\r\n }\r\n }\r\n})()\r\n\n\n//# sourceURL=webpack://halo-theme-dream2.0-plus/./src/js/sw.js?")}},__webpack_exports__={};__webpack_modules__["./src/js/sw.js"]()})(); |