@gitlon/version 0.1.0 → 0.1.1
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 +5 -0
- package/dist/client.cjs +1 -1
- package/dist/client.cjs.map +1 -1
- package/dist/client.d.ts +1 -0
- package/dist/client.js +5 -1
- package/dist/client.js.map +1 -1
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -215,11 +215,16 @@ await clearUrlCache({
|
|
|
215
215
|
urls: ['/vue-app/', '/vue-app/index.html'],
|
|
216
216
|
redirectUrl: '/vue-app/',
|
|
217
217
|
time: 5,
|
|
218
|
+
onBeforeRedirect: async () => {
|
|
219
|
+
await reportUpdate()
|
|
220
|
+
},
|
|
218
221
|
})
|
|
219
222
|
```
|
|
220
223
|
|
|
221
224
|
`time` 单位为秒,默认 `5`。调用时显示全屏倒计时;依次使用无缓存请求、`reload` 请求和隐藏 iframe 刷新各 URL,完成或超时后携带随机参数跳转。
|
|
222
225
|
|
|
226
|
+
`onBeforeRedirect` 在跳转前调用并被 `await`,适合收尾工作(存状态、埋点、清理登录态)。回调抛错或刷新超时都不影响跳转。
|
|
227
|
+
|
|
223
228
|
无参数时处理当前页面路径及其 `index.html`:
|
|
224
229
|
|
|
225
230
|
```ts
|
package/dist/client.cjs
CHANGED
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
Object.defineProperty(exports,Symbol.toStringTag,{value:`Module`});var e=`_`,t=`gitlon-version-cache-iframe`,n=`gitlon-version-loading`,r=5e3,i=5;function a(e){document.getElementById(n)?.remove();let t=document.createElement(`div`),r=document.createElement(`div`),i=document.createElement(`div`),a=Date.now()+e*1e3;t.id=n,t.style.cssText=`position:fixed;inset:0;z-index:2147483647;display:flex;flex-direction:column;align-items:center;justify-content:center;background:rgba(0,0,0,.65);color:#fff;font:14px/1.5 sans-serif;`,r.style.cssText=`width:36px;height:36px;margin-bottom:16px;border:3px solid rgba(255,255,255,.35);border-top-color:#fff;border-radius:50%;animation:gitlon-version-loading .8s linear infinite;`,i.textContent=`请稍等,正在检测更新...(${Math.ceil(e)}秒)`;let o=document.createElement(`style`);o.textContent=`@keyframes gitlon-version-loading{to{transform:rotate(360deg)}}`,t.append(o,r,i),document.documentElement.appendChild(t);let s=window.setInterval(()=>{let e=Math.max(0,Math.ceil((a-Date.now())/1e3));i.textContent=`请稍等,正在检测更新...(${e}秒)`},1e3);return()=>{window.clearInterval(s),t.remove()}}function o(t){let n=new URL(t,window.location.href),r=n.hash;return n.hash=``,n.searchParams.set(e,`${Date.now()}-${Math.random().toString(36).slice(2)}`),n.hash=r,n.href}function s(e){let t=new URL(e);return t.pathname.endsWith(`/`)||(t.pathname+=`/`),t.pathname+=`index.html`,t.href}function c(e){return new Promise(n=>{document.getElementById(t)?.remove();let i=document.createElement(`iframe`),a=!1,o=()=>{a||(a=!0,window.clearTimeout(s),n())},s=window.setTimeout(o,r);i.hidden=!0,i.id=t,i.addEventListener(`load`,o,{once:!0}),i.addEventListener(`error`,o,{once:!0}),i.src=e,document.documentElement.appendChild(i)})}async function l(e){let t=new URL(e,window.location.href).href;console.info(`[@gitlon/version] Clear cache for ${t}`),c(o(t)),await Promise.allSettled([fetch(o(t),{cache:`no-store`}).then(e=>e.arrayBuffer()),fetch(t,{cache:`reload`}).then(e=>e.arrayBuffer())])}async function u(e={}){let t=window.location.origin+window.location.pathname,n=e.urls??[t,s(t)],r=e.time,o=typeof r==`number`&&Number.isFinite(r)&&r>0?r:i,c=new URL(e.redirectUrl??n[0]??t,window.location.href).href,u=a(o),d=0;try{await Promise.race([(async()=>{for(let e of n)try{await l(e)}catch{}})(),new Promise(e=>{d=window.setTimeout(e,o*1e3)})])}finally{window.clearTimeout(d),u()
|
|
1
|
+
Object.defineProperty(exports,Symbol.toStringTag,{value:`Module`});var e=`_`,t=`gitlon-version-cache-iframe`,n=`gitlon-version-loading`,r=5e3,i=5;function a(e){document.getElementById(n)?.remove();let t=document.createElement(`div`),r=document.createElement(`div`),i=document.createElement(`div`),a=Date.now()+e*1e3;t.id=n,t.style.cssText=`position:fixed;inset:0;z-index:2147483647;display:flex;flex-direction:column;align-items:center;justify-content:center;background:rgba(0,0,0,.65);color:#fff;font:14px/1.5 sans-serif;`,r.style.cssText=`width:36px;height:36px;margin-bottom:16px;border:3px solid rgba(255,255,255,.35);border-top-color:#fff;border-radius:50%;animation:gitlon-version-loading .8s linear infinite;`,i.textContent=`请稍等,正在检测更新...(${Math.ceil(e)}秒)`;let o=document.createElement(`style`);o.textContent=`@keyframes gitlon-version-loading{to{transform:rotate(360deg)}}`,t.append(o,r,i),document.documentElement.appendChild(t);let s=window.setInterval(()=>{let e=Math.max(0,Math.ceil((a-Date.now())/1e3));i.textContent=`请稍等,正在检测更新...(${e}秒)`},1e3);return()=>{window.clearInterval(s),t.remove()}}function o(t){let n=new URL(t,window.location.href),r=n.hash;return n.hash=``,n.searchParams.set(e,`${Date.now()}-${Math.random().toString(36).slice(2)}`),n.hash=r,n.href}function s(e){let t=new URL(e);return t.pathname.endsWith(`/`)||(t.pathname+=`/`),t.pathname+=`index.html`,t.href}function c(e){return new Promise(n=>{document.getElementById(t)?.remove();let i=document.createElement(`iframe`),a=!1,o=()=>{a||(a=!0,window.clearTimeout(s),n())},s=window.setTimeout(o,r);i.hidden=!0,i.id=t,i.addEventListener(`load`,o,{once:!0}),i.addEventListener(`error`,o,{once:!0}),i.src=e,document.documentElement.appendChild(i)})}async function l(e){let t=new URL(e,window.location.href).href;console.info(`[@gitlon/version] Clear cache for ${t}`),c(o(t)),await Promise.allSettled([fetch(o(t),{cache:`no-store`}).then(e=>e.arrayBuffer()),fetch(t,{cache:`reload`}).then(e=>e.arrayBuffer())])}async function u(e={}){let t=window.location.origin+window.location.pathname,n=e.urls??[t,s(t)],r=e.time,o=typeof r==`number`&&Number.isFinite(r)&&r>0?r:i,c=new URL(e.redirectUrl??n[0]??t,window.location.href).href,u=a(o),d=0;try{await Promise.race([(async()=>{for(let e of n)try{await l(e)}catch{}})(),new Promise(e=>{d=window.setTimeout(e,o*1e3)})])}finally{window.clearTimeout(d),u();try{await e.onBeforeRedirect?.()}catch{}window.location.replace(c)}}exports.clearUrlCache=u;
|
|
2
2
|
//# sourceMappingURL=client.cjs.map
|
package/dist/client.cjs.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"client.cjs","names":[],"sources":["../src/client.ts"],"sourcesContent":["const CACHE_BUST_PARAM = '_'\nconst IFRAME_ID = 'gitlon-version-cache-iframe'\nconst LOADING_ID = 'gitlon-version-loading'\nconst IFRAME_TIMEOUT = 5_000\nconst DEFAULT_REFRESH_TIME = 5\n\nexport interface ClearUrlCacheOptions {\n urls?: string[]\n redirectUrl?: string\n time?: number\n}\n\nfunction showLoading(time: number): () => void {\n document.getElementById(LOADING_ID)?.remove()\n\n const loading = document.createElement('div')\n const spinner = document.createElement('div')\n const text = document.createElement('div')\n const deadline = Date.now() + time * 1_000\n\n loading.id = LOADING_ID\n loading.style.cssText =\n 'position:fixed;inset:0;z-index:2147483647;display:flex;flex-direction:column;align-items:center;justify-content:center;background:rgba(0,0,0,.65);color:#fff;font:14px/1.5 sans-serif;'\n spinner.style.cssText =\n 'width:36px;height:36px;margin-bottom:16px;border:3px solid rgba(255,255,255,.35);border-top-color:#fff;border-radius:50%;animation:gitlon-version-loading .8s linear infinite;'\n text.textContent = `请稍等,正在检测更新...(${Math.ceil(time)}秒)`\n\n const style = document.createElement('style')\n style.textContent = '@keyframes gitlon-version-loading{to{transform:rotate(360deg)}}'\n loading.append(style, spinner, text)\n document.documentElement.appendChild(loading)\n\n const countdown = window.setInterval(() => {\n const seconds = Math.max(0, Math.ceil((deadline - Date.now()) / 1_000))\n text.textContent = `请稍等,正在检测更新...(${seconds}秒)`\n }, 1_000)\n\n return () => {\n window.clearInterval(countdown)\n loading.remove()\n }\n}\n\nfunction cacheBustedUrl(url: string): string {\n const target = new URL(url, window.location.href)\n const hash = target.hash\n\n target.hash = ''\n target.searchParams.set(\n CACHE_BUST_PARAM,\n `${Date.now()}-${Math.random().toString(36).slice(2)}`,\n )\n target.hash = hash\n\n return target.href\n}\n\nfunction indexUrl(url: string): string {\n const target = new URL(url)\n if (!target.pathname.endsWith('/')) target.pathname += '/'\n target.pathname += 'index.html'\n return target.href\n}\n\nfunction loadIframe(url: string): Promise<void> {\n return new Promise((resolve) => {\n document.getElementById(IFRAME_ID)?.remove()\n\n const iframe = document.createElement('iframe')\n let completed = false\n\n const complete = () => {\n if (completed) return\n completed = true\n window.clearTimeout(timeout)\n resolve()\n }\n\n const timeout = window.setTimeout(complete, IFRAME_TIMEOUT)\n iframe.hidden = true\n iframe.id = IFRAME_ID\n iframe.addEventListener('load', complete, { once: true })\n iframe.addEventListener('error', complete, { once: true })\n iframe.src = url\n document.documentElement.appendChild(iframe)\n })\n}\n\nasync function refreshUrlCache(url: string): Promise<void> {\n const target = new URL(url, window.location.href).href\n console.info(`[@gitlon/version] Clear cache for ${target}`)\n\n loadIframe(cacheBustedUrl(target))\n await Promise.allSettled([\n fetch(cacheBustedUrl(target), { cache: 'no-store' }).then((response) =>\n response.arrayBuffer(),\n ),\n fetch(target, { cache: 'reload' }).then((response) => response.arrayBuffer()),\n ])\n\n}\n\nexport async function clearUrlCache(options: ClearUrlCacheOptions = {}): Promise<void> {\n const defaultUrl = window.location.origin + window.location.pathname\n const urls = options.urls ?? [defaultUrl, indexUrl(defaultUrl)]\n const configuredTime = options.time\n const time =\n typeof configuredTime === 'number' &&\n Number.isFinite(configuredTime) &&\n configuredTime > 0\n ? configuredTime\n : DEFAULT_REFRESH_TIME\n const redirectUrl = new URL(\n options.redirectUrl ?? urls[0] ?? defaultUrl,\n window.location.href,\n ).href\n const hideLoading = showLoading(time)\n let refreshTimeout = 0\n\n try {\n await Promise.race([\n (async () => {\n for (const url of urls) {\n try {\n await refreshUrlCache(url)\n } catch {\n // 单个 URL 失败不阻断后续 URL。\n }\n }\n })(),\n new Promise<void>((resolve) => {\n refreshTimeout = window.setTimeout(resolve, time * 1_000)\n }),\n ])\n } finally {\n window.clearTimeout(refreshTimeout)\n hideLoading()\n window.location.replace(redirectUrl)\n }\n}\n"],"mappings":"mEAAA,IAAM,EAAmB,IACnB,EAAY,8BACZ,EAAa,yBACb,EAAiB,IACjB,EAAuB,
|
|
1
|
+
{"version":3,"file":"client.cjs","names":[],"sources":["../src/client.ts"],"sourcesContent":["const CACHE_BUST_PARAM = '_'\nconst IFRAME_ID = 'gitlon-version-cache-iframe'\nconst LOADING_ID = 'gitlon-version-loading'\nconst IFRAME_TIMEOUT = 5_000\nconst DEFAULT_REFRESH_TIME = 5\n\nexport interface ClearUrlCacheOptions {\n urls?: string[]\n redirectUrl?: string\n time?: number\n onBeforeRedirect?: () => void | Promise<void>\n}\n\nfunction showLoading(time: number): () => void {\n document.getElementById(LOADING_ID)?.remove()\n\n const loading = document.createElement('div')\n const spinner = document.createElement('div')\n const text = document.createElement('div')\n const deadline = Date.now() + time * 1_000\n\n loading.id = LOADING_ID\n loading.style.cssText =\n 'position:fixed;inset:0;z-index:2147483647;display:flex;flex-direction:column;align-items:center;justify-content:center;background:rgba(0,0,0,.65);color:#fff;font:14px/1.5 sans-serif;'\n spinner.style.cssText =\n 'width:36px;height:36px;margin-bottom:16px;border:3px solid rgba(255,255,255,.35);border-top-color:#fff;border-radius:50%;animation:gitlon-version-loading .8s linear infinite;'\n text.textContent = `请稍等,正在检测更新...(${Math.ceil(time)}秒)`\n\n const style = document.createElement('style')\n style.textContent = '@keyframes gitlon-version-loading{to{transform:rotate(360deg)}}'\n loading.append(style, spinner, text)\n document.documentElement.appendChild(loading)\n\n const countdown = window.setInterval(() => {\n const seconds = Math.max(0, Math.ceil((deadline - Date.now()) / 1_000))\n text.textContent = `请稍等,正在检测更新...(${seconds}秒)`\n }, 1_000)\n\n return () => {\n window.clearInterval(countdown)\n loading.remove()\n }\n}\n\nfunction cacheBustedUrl(url: string): string {\n const target = new URL(url, window.location.href)\n const hash = target.hash\n\n target.hash = ''\n target.searchParams.set(\n CACHE_BUST_PARAM,\n `${Date.now()}-${Math.random().toString(36).slice(2)}`,\n )\n target.hash = hash\n\n return target.href\n}\n\nfunction indexUrl(url: string): string {\n const target = new URL(url)\n if (!target.pathname.endsWith('/')) target.pathname += '/'\n target.pathname += 'index.html'\n return target.href\n}\n\nfunction loadIframe(url: string): Promise<void> {\n return new Promise((resolve) => {\n document.getElementById(IFRAME_ID)?.remove()\n\n const iframe = document.createElement('iframe')\n let completed = false\n\n const complete = () => {\n if (completed) return\n completed = true\n window.clearTimeout(timeout)\n resolve()\n }\n\n const timeout = window.setTimeout(complete, IFRAME_TIMEOUT)\n iframe.hidden = true\n iframe.id = IFRAME_ID\n iframe.addEventListener('load', complete, { once: true })\n iframe.addEventListener('error', complete, { once: true })\n iframe.src = url\n document.documentElement.appendChild(iframe)\n })\n}\n\nasync function refreshUrlCache(url: string): Promise<void> {\n const target = new URL(url, window.location.href).href\n console.info(`[@gitlon/version] Clear cache for ${target}`)\n\n loadIframe(cacheBustedUrl(target))\n await Promise.allSettled([\n fetch(cacheBustedUrl(target), { cache: 'no-store' }).then((response) =>\n response.arrayBuffer(),\n ),\n fetch(target, { cache: 'reload' }).then((response) => response.arrayBuffer()),\n ])\n\n}\n\nexport async function clearUrlCache(options: ClearUrlCacheOptions = {}): Promise<void> {\n const defaultUrl = window.location.origin + window.location.pathname\n const urls = options.urls ?? [defaultUrl, indexUrl(defaultUrl)]\n const configuredTime = options.time\n const time =\n typeof configuredTime === 'number' &&\n Number.isFinite(configuredTime) &&\n configuredTime > 0\n ? configuredTime\n : DEFAULT_REFRESH_TIME\n const redirectUrl = new URL(\n options.redirectUrl ?? urls[0] ?? defaultUrl,\n window.location.href,\n ).href\n const hideLoading = showLoading(time)\n let refreshTimeout = 0\n\n try {\n await Promise.race([\n (async () => {\n for (const url of urls) {\n try {\n await refreshUrlCache(url)\n } catch {\n // 单个 URL 失败不阻断后续 URL。\n }\n }\n })(),\n new Promise<void>((resolve) => {\n refreshTimeout = window.setTimeout(resolve, time * 1_000)\n }),\n ])\n } finally {\n window.clearTimeout(refreshTimeout)\n hideLoading()\n try {\n await options.onBeforeRedirect?.()\n } catch {\n // 回调失败不阻断跳转。\n }\n window.location.replace(redirectUrl)\n }\n}\n"],"mappings":"mEAAA,IAAM,EAAmB,IACnB,EAAY,8BACZ,EAAa,yBACb,EAAiB,IACjB,EAAuB,EAS7B,SAAS,EAAY,EAA0B,CAC7C,SAAS,eAAe,CAAU,CAAC,EAAE,OAAO,EAE5C,IAAM,EAAU,SAAS,cAAc,KAAK,EACtC,EAAU,SAAS,cAAc,KAAK,EACtC,EAAO,SAAS,cAAc,KAAK,EACnC,EAAW,KAAK,IAAI,EAAI,EAAO,IAErC,EAAQ,GAAK,EACb,EAAQ,MAAM,QACZ,yLACF,EAAQ,MAAM,QACZ,iLACF,EAAK,YAAc,iBAAiB,KAAK,KAAK,CAAI,EAAE,IAEpD,IAAM,EAAQ,SAAS,cAAc,OAAO,EAC5C,EAAM,YAAc,kEACpB,EAAQ,OAAO,EAAO,EAAS,CAAI,EACnC,SAAS,gBAAgB,YAAY,CAAO,EAE5C,IAAM,EAAY,OAAO,gBAAkB,CACzC,IAAM,EAAU,KAAK,IAAI,EAAG,KAAK,MAAM,EAAW,KAAK,IAAI,GAAK,GAAK,CAAC,EACtE,EAAK,YAAc,iBAAiB,EAAQ,GAC9C,EAAG,GAAK,EAER,UAAa,CACX,OAAO,cAAc,CAAS,EAC9B,EAAQ,OAAO,CACjB,CACF,CAEA,SAAS,EAAe,EAAqB,CAC3C,IAAM,EAAS,IAAI,IAAI,EAAK,OAAO,SAAS,IAAI,EAC1C,EAAO,EAAO,KASpB,MAPA,GAAO,KAAO,GACd,EAAO,aAAa,IAClB,EACA,GAAG,KAAK,IAAI,EAAE,GAAG,KAAK,OAAO,CAAC,CAAC,SAAS,EAAE,CAAC,CAAC,MAAM,CAAC,GACrD,EACA,EAAO,KAAO,EAEP,EAAO,IAChB,CAEA,SAAS,EAAS,EAAqB,CACrC,IAAM,EAAS,IAAI,IAAI,CAAG,EAG1B,OAFK,EAAO,SAAS,SAAS,GAAG,IAAG,EAAO,UAAY,KACvD,EAAO,UAAY,aACZ,EAAO,IAChB,CAEA,SAAS,EAAW,EAA4B,CAC9C,OAAO,IAAI,QAAS,GAAY,CAC9B,SAAS,eAAe,CAAS,CAAC,EAAE,OAAO,EAE3C,IAAM,EAAS,SAAS,cAAc,QAAQ,EAC1C,EAAY,GAEV,MAAiB,CACjB,IACJ,EAAY,GACZ,OAAO,aAAa,CAAO,EAC3B,EAAQ,EACV,EAEM,EAAU,OAAO,WAAW,EAAU,CAAc,EAC1D,EAAO,OAAS,GAChB,EAAO,GAAK,EACZ,EAAO,iBAAiB,OAAQ,EAAU,CAAE,KAAM,EAAK,CAAC,EACxD,EAAO,iBAAiB,QAAS,EAAU,CAAE,KAAM,EAAK,CAAC,EACzD,EAAO,IAAM,EACb,SAAS,gBAAgB,YAAY,CAAM,CAC7C,CAAC,CACH,CAEA,eAAe,EAAgB,EAA4B,CACzD,IAAM,EAAS,IAAI,IAAI,EAAK,OAAO,SAAS,IAAI,CAAC,CAAC,KAClD,QAAQ,KAAK,qCAAqC,GAAQ,EAE1D,EAAW,EAAe,CAAM,CAAC,EACjC,MAAM,QAAQ,WAAW,CACvB,MAAM,EAAe,CAAM,EAAG,CAAE,MAAO,UAAW,CAAC,CAAC,CAAC,KAAM,GACzD,EAAS,YAAY,CACvB,EACA,MAAM,EAAQ,CAAE,MAAO,QAAS,CAAC,CAAC,CAAC,KAAM,GAAa,EAAS,YAAY,CAAC,CAC9E,CAAC,CAEH,CAEA,eAAsB,EAAc,EAAgC,CAAC,EAAkB,CACrF,IAAM,EAAa,OAAO,SAAS,OAAS,OAAO,SAAS,SACtD,EAAO,EAAQ,MAAQ,CAAC,EAAY,EAAS,CAAU,CAAC,EACxD,EAAiB,EAAQ,KACzB,EACJ,OAAO,GAAmB,UAC1B,OAAO,SAAS,CAAc,GAC9B,EAAiB,EACb,EACA,EACA,EAAc,IAAI,IACtB,EAAQ,aAAe,EAAK,IAAM,EAClC,OAAO,SAAS,IAClB,CAAC,CAAC,KACI,EAAc,EAAY,CAAI,EAChC,EAAiB,EAErB,GAAI,CACF,MAAM,QAAQ,KAAK,EAChB,SAAY,CACX,IAAK,IAAM,KAAO,EAChB,GAAI,CACF,MAAM,EAAgB,CAAG,CAC3B,MAAQ,CAER,CAEJ,EAAA,CAAG,EACH,IAAI,QAAe,GAAY,CAC7B,EAAiB,OAAO,WAAW,EAAS,EAAO,GAAK,CAC1D,CAAC,CACH,CAAC,CACH,QAAU,CACR,OAAO,aAAa,CAAc,EAClC,EAAY,EACZ,GAAI,CACF,MAAM,EAAQ,mBAAmB,CACnC,MAAQ,CAER,CACA,OAAO,SAAS,QAAQ,CAAW,CACrC,CACF"}
|
package/dist/client.d.ts
CHANGED
package/dist/client.js
CHANGED
|
@@ -46,7 +46,11 @@ async function s(e = {}) {
|
|
|
46
46
|
u = window.setTimeout(e, s * 1e3);
|
|
47
47
|
})]);
|
|
48
48
|
} finally {
|
|
49
|
-
window.clearTimeout(u), l()
|
|
49
|
+
window.clearTimeout(u), l();
|
|
50
|
+
try {
|
|
51
|
+
await e.onBeforeRedirect?.();
|
|
52
|
+
} catch {}
|
|
53
|
+
window.location.replace(c);
|
|
50
54
|
}
|
|
51
55
|
}
|
|
52
56
|
//#endregion
|
package/dist/client.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"client.js","names":[],"sources":["../src/client.ts"],"sourcesContent":["const CACHE_BUST_PARAM = '_'\nconst IFRAME_ID = 'gitlon-version-cache-iframe'\nconst LOADING_ID = 'gitlon-version-loading'\nconst IFRAME_TIMEOUT = 5_000\nconst DEFAULT_REFRESH_TIME = 5\n\nexport interface ClearUrlCacheOptions {\n urls?: string[]\n redirectUrl?: string\n time?: number\n}\n\nfunction showLoading(time: number): () => void {\n document.getElementById(LOADING_ID)?.remove()\n\n const loading = document.createElement('div')\n const spinner = document.createElement('div')\n const text = document.createElement('div')\n const deadline = Date.now() + time * 1_000\n\n loading.id = LOADING_ID\n loading.style.cssText =\n 'position:fixed;inset:0;z-index:2147483647;display:flex;flex-direction:column;align-items:center;justify-content:center;background:rgba(0,0,0,.65);color:#fff;font:14px/1.5 sans-serif;'\n spinner.style.cssText =\n 'width:36px;height:36px;margin-bottom:16px;border:3px solid rgba(255,255,255,.35);border-top-color:#fff;border-radius:50%;animation:gitlon-version-loading .8s linear infinite;'\n text.textContent = `请稍等,正在检测更新...(${Math.ceil(time)}秒)`\n\n const style = document.createElement('style')\n style.textContent = '@keyframes gitlon-version-loading{to{transform:rotate(360deg)}}'\n loading.append(style, spinner, text)\n document.documentElement.appendChild(loading)\n\n const countdown = window.setInterval(() => {\n const seconds = Math.max(0, Math.ceil((deadline - Date.now()) / 1_000))\n text.textContent = `请稍等,正在检测更新...(${seconds}秒)`\n }, 1_000)\n\n return () => {\n window.clearInterval(countdown)\n loading.remove()\n }\n}\n\nfunction cacheBustedUrl(url: string): string {\n const target = new URL(url, window.location.href)\n const hash = target.hash\n\n target.hash = ''\n target.searchParams.set(\n CACHE_BUST_PARAM,\n `${Date.now()}-${Math.random().toString(36).slice(2)}`,\n )\n target.hash = hash\n\n return target.href\n}\n\nfunction indexUrl(url: string): string {\n const target = new URL(url)\n if (!target.pathname.endsWith('/')) target.pathname += '/'\n target.pathname += 'index.html'\n return target.href\n}\n\nfunction loadIframe(url: string): Promise<void> {\n return new Promise((resolve) => {\n document.getElementById(IFRAME_ID)?.remove()\n\n const iframe = document.createElement('iframe')\n let completed = false\n\n const complete = () => {\n if (completed) return\n completed = true\n window.clearTimeout(timeout)\n resolve()\n }\n\n const timeout = window.setTimeout(complete, IFRAME_TIMEOUT)\n iframe.hidden = true\n iframe.id = IFRAME_ID\n iframe.addEventListener('load', complete, { once: true })\n iframe.addEventListener('error', complete, { once: true })\n iframe.src = url\n document.documentElement.appendChild(iframe)\n })\n}\n\nasync function refreshUrlCache(url: string): Promise<void> {\n const target = new URL(url, window.location.href).href\n console.info(`[@gitlon/version] Clear cache for ${target}`)\n\n loadIframe(cacheBustedUrl(target))\n await Promise.allSettled([\n fetch(cacheBustedUrl(target), { cache: 'no-store' }).then((response) =>\n response.arrayBuffer(),\n ),\n fetch(target, { cache: 'reload' }).then((response) => response.arrayBuffer()),\n ])\n\n}\n\nexport async function clearUrlCache(options: ClearUrlCacheOptions = {}): Promise<void> {\n const defaultUrl = window.location.origin + window.location.pathname\n const urls = options.urls ?? [defaultUrl, indexUrl(defaultUrl)]\n const configuredTime = options.time\n const time =\n typeof configuredTime === 'number' &&\n Number.isFinite(configuredTime) &&\n configuredTime > 0\n ? configuredTime\n : DEFAULT_REFRESH_TIME\n const redirectUrl = new URL(\n options.redirectUrl ?? urls[0] ?? defaultUrl,\n window.location.href,\n ).href\n const hideLoading = showLoading(time)\n let refreshTimeout = 0\n\n try {\n await Promise.race([\n (async () => {\n for (const url of urls) {\n try {\n await refreshUrlCache(url)\n } catch {\n // 单个 URL 失败不阻断后续 URL。\n }\n }\n })(),\n new Promise<void>((resolve) => {\n refreshTimeout = window.setTimeout(resolve, time * 1_000)\n }),\n ])\n } finally {\n window.clearTimeout(refreshTimeout)\n hideLoading()\n window.location.replace(redirectUrl)\n }\n}\n"],"mappings":";AAAA,IACM,IAAY,+BACZ,IAAa;
|
|
1
|
+
{"version":3,"file":"client.js","names":[],"sources":["../src/client.ts"],"sourcesContent":["const CACHE_BUST_PARAM = '_'\nconst IFRAME_ID = 'gitlon-version-cache-iframe'\nconst LOADING_ID = 'gitlon-version-loading'\nconst IFRAME_TIMEOUT = 5_000\nconst DEFAULT_REFRESH_TIME = 5\n\nexport interface ClearUrlCacheOptions {\n urls?: string[]\n redirectUrl?: string\n time?: number\n onBeforeRedirect?: () => void | Promise<void>\n}\n\nfunction showLoading(time: number): () => void {\n document.getElementById(LOADING_ID)?.remove()\n\n const loading = document.createElement('div')\n const spinner = document.createElement('div')\n const text = document.createElement('div')\n const deadline = Date.now() + time * 1_000\n\n loading.id = LOADING_ID\n loading.style.cssText =\n 'position:fixed;inset:0;z-index:2147483647;display:flex;flex-direction:column;align-items:center;justify-content:center;background:rgba(0,0,0,.65);color:#fff;font:14px/1.5 sans-serif;'\n spinner.style.cssText =\n 'width:36px;height:36px;margin-bottom:16px;border:3px solid rgba(255,255,255,.35);border-top-color:#fff;border-radius:50%;animation:gitlon-version-loading .8s linear infinite;'\n text.textContent = `请稍等,正在检测更新...(${Math.ceil(time)}秒)`\n\n const style = document.createElement('style')\n style.textContent = '@keyframes gitlon-version-loading{to{transform:rotate(360deg)}}'\n loading.append(style, spinner, text)\n document.documentElement.appendChild(loading)\n\n const countdown = window.setInterval(() => {\n const seconds = Math.max(0, Math.ceil((deadline - Date.now()) / 1_000))\n text.textContent = `请稍等,正在检测更新...(${seconds}秒)`\n }, 1_000)\n\n return () => {\n window.clearInterval(countdown)\n loading.remove()\n }\n}\n\nfunction cacheBustedUrl(url: string): string {\n const target = new URL(url, window.location.href)\n const hash = target.hash\n\n target.hash = ''\n target.searchParams.set(\n CACHE_BUST_PARAM,\n `${Date.now()}-${Math.random().toString(36).slice(2)}`,\n )\n target.hash = hash\n\n return target.href\n}\n\nfunction indexUrl(url: string): string {\n const target = new URL(url)\n if (!target.pathname.endsWith('/')) target.pathname += '/'\n target.pathname += 'index.html'\n return target.href\n}\n\nfunction loadIframe(url: string): Promise<void> {\n return new Promise((resolve) => {\n document.getElementById(IFRAME_ID)?.remove()\n\n const iframe = document.createElement('iframe')\n let completed = false\n\n const complete = () => {\n if (completed) return\n completed = true\n window.clearTimeout(timeout)\n resolve()\n }\n\n const timeout = window.setTimeout(complete, IFRAME_TIMEOUT)\n iframe.hidden = true\n iframe.id = IFRAME_ID\n iframe.addEventListener('load', complete, { once: true })\n iframe.addEventListener('error', complete, { once: true })\n iframe.src = url\n document.documentElement.appendChild(iframe)\n })\n}\n\nasync function refreshUrlCache(url: string): Promise<void> {\n const target = new URL(url, window.location.href).href\n console.info(`[@gitlon/version] Clear cache for ${target}`)\n\n loadIframe(cacheBustedUrl(target))\n await Promise.allSettled([\n fetch(cacheBustedUrl(target), { cache: 'no-store' }).then((response) =>\n response.arrayBuffer(),\n ),\n fetch(target, { cache: 'reload' }).then((response) => response.arrayBuffer()),\n ])\n\n}\n\nexport async function clearUrlCache(options: ClearUrlCacheOptions = {}): Promise<void> {\n const defaultUrl = window.location.origin + window.location.pathname\n const urls = options.urls ?? [defaultUrl, indexUrl(defaultUrl)]\n const configuredTime = options.time\n const time =\n typeof configuredTime === 'number' &&\n Number.isFinite(configuredTime) &&\n configuredTime > 0\n ? configuredTime\n : DEFAULT_REFRESH_TIME\n const redirectUrl = new URL(\n options.redirectUrl ?? urls[0] ?? defaultUrl,\n window.location.href,\n ).href\n const hideLoading = showLoading(time)\n let refreshTimeout = 0\n\n try {\n await Promise.race([\n (async () => {\n for (const url of urls) {\n try {\n await refreshUrlCache(url)\n } catch {\n // 单个 URL 失败不阻断后续 URL。\n }\n }\n })(),\n new Promise<void>((resolve) => {\n refreshTimeout = window.setTimeout(resolve, time * 1_000)\n }),\n ])\n } finally {\n window.clearTimeout(refreshTimeout)\n hideLoading()\n try {\n await options.onBeforeRedirect?.()\n } catch {\n // 回调失败不阻断跳转。\n }\n window.location.replace(redirectUrl)\n }\n}\n"],"mappings":"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"}
|