UNPKG

quicklink

Version:

Faster subsequent page-loads by prefetching in-viewport links during idle time

2 lines (1 loc) 4.06 kB
function e(e,r,n,t){const o={headers:{accept:"*/*"}};return r||(o.mode="no-cors"),n&&(o.credentials="include"),o.priority=t?"high":"low",window.fetch?fetch(e,o):function(e,r){return new Promise((n,t,o)=>{(o=new XMLHttpRequest).open("GET",e,o.withCredentials=r),o.setRequestHeader("Accept","*/*"),o.onload=()=>{200===o.status?n():t()},o.send()})}(e,n)}const r=(n=document.createElement("link")).relList&&n.relList.supports&&n.relList.supports("prefetch")?function(e,r){return new Promise((n,t,o)=>{(o=document.createElement("link")).rel="prefetch",o.href=e,r&&o.setAttribute("crossorigin","anonymous"),o.onload=n,o.onerror=t,document.head.appendChild(o)})}:e;var n;const t=window.requestIdleCallback||function(e){const r=Date.now();return setTimeout(()=>{e({didTimeout:!1,timeRemaining:()=>Math.max(0,50-(Date.now()-r))})},1)},o=new Set,s=new Set;let i=!1;function c(e,r){return Array.isArray(r)?r.some(r=>c(e,r)):(r.test||r).call(r,e.href,e)}function a(e){if(e){if(e.saveData)return new Error("Save-Data is enabled");if(/2g/.test(e.effectiveType))return new Error("network conditions are poor")}return!0}function u(e={}){if(!window.IntersectionObserver||!("isIntersecting"in IntersectionObserverEntry.prototype))return;const[r,n]=function(e){e=e||1;var r=[],n=0;function t(){n<e&&r.length>0&&(r.shift()(),n++)}return[function(e){r.push(e)>1||t()},function(){n--,t()}]}(e.throttle||1/0),a=e.limit||1/0,u=e.origins||[location.hostname],f=e.ignores||[],h=e.delay||0,m=[],p=e.timeoutFn||t,g="function"==typeof e.hrefFn&&e.hrefFn,w=e.prerender||!1;i=e.prerenderAndPrefetch||!1;const v=new IntersectionObserver(t=>{t.forEach(t=>{if(t.isIntersecting)m.push((t=t.target).href),((e,r)=>{r?setTimeout(e,r):e()})(()=>{m.includes(t.href)&&(v.unobserve(t),(i||w)&&s.size<a?d(g?g(t):t.href,e.eagerness).catch(r=>{if(!e.onError)throw r;e.onError(r)}):o.size<a&&!w&&r(()=>{l(g?g(t):t.href,e.priority,e.checkAccessControlAllowOrigin,e.checkAccessControlAllowCredentials,e.onlyOnMouseover).then(n).catch(r=>{n(),e.onError&&e.onError(r)})}))},h);else{const e=m.indexOf((t=t.target).href);e>-1&&m.splice(e)}})},{threshold:e.threshold||0});return p(()=>{(e.el&&e.el.length&&e.el.length>0&&"A"===e.el[0].nodeName?e.el:(e.el||document).querySelectorAll("a")).forEach(e=>{u.length&&!u.includes(e.hostname)||c(e,f)||v.observe(e)})},{timeout:e.timeout||2e3}),function(){o.clear(),v.disconnect()}}function l(n,t,c,u,l){const d=a(navigator.connection);return d instanceof Error?Promise.reject(new Error(`Cannot prefetch, ${d.message}`)):(s.size>0&&!i&&console.warn("[Warning] You are using both prefetching and prerendering on the same document"),Promise.all([].concat(n).map(n=>o.has(n)?[]:(o.add(n),function(e,r,n,...t){if(!n)return e(r,...t);const o=Array.from(document.querySelectorAll("a")).filter(e=>e.href===r),s=new Map;for(const n of o){const o=c=>{const a=setTimeout(()=>(n.removeEventListener("mouseenter",o),n.removeEventListener("mouseleave",i),e(r,...t)),200);s.set(n,a)},i=e=>{const r=s.get(n);r&&(clearTimeout(r),s.delete(n))};n.addEventListener("mouseenter",o),n.addEventListener("mouseleave",i)}}(t?e:r,new URL(n,location.href).toString(),l,c,u,t)))))}function d(e,r="immediate"){const n=a(navigator.connection);if(n instanceof Error)return Promise.reject(new Error(`Cannot prerender, ${n.message}`));if(!HTMLScriptElement.supports("speculationrules"))return l(e,!0,!1,!1,"moderate"===r||"conservative"===r),Promise.reject(new Error("This browser does not support the speculation rules API. Falling back to prefetch."));for(const r of[].concat(e))s.add(r);o.size>0&&!i&&console.warn("[Warning] You are using both prefetching and prerendering on the same document");const t=function(e,r){const n=document.createElement("script");n.type="speculationrules",n.text=`{"prerender":[{"source": "list",\n "urls": ["${Array.from(e).join('","')}"],\n "eagerness": "${r}"}]}`;try{document.head.appendChild(n)}catch(e){return e}return!0}(s,r);return!0===t?Promise.resolve():Promise.reject(t)}export{u as listen,l as prefetch,d as prerender};