UNPKG

web-vitals

Version:

Easily measure performance metrics in JavaScript

2 lines (1 loc) 11.6 kB
class t{t;o=0;i=[];u(t){if(t.hadRecentInput)return;const e=this.i[0],n=this.i.at(-1);this.o&&e&&n&&t.startTime-n.startTime<1e3&&t.startTime-e.startTime<5e3?(this.o+=t.value,this.i.push(t)):(this.o=t.value,this.i=[t]),this.t?.(t)}}const e=()=>{const t=performance.getEntriesByType("navigation")[0];if(t&&t.responseStart>0&&t.responseStart<performance.now())return t},n=t=>{if("loading"===document.readyState)return"loading";{const n=e();if(n){if(t<n.domInteractive)return"loading";if(0===n.domContentLoadedEventStart||t<n.domContentLoadedEventStart)return"dom-interactive";if(0===n.domComplete||t<n.domComplete)return"dom-content-loaded"}}return"complete"},o=t=>{const e=t.nodeName;return 1===t.nodeType?e.toLowerCase():e.toUpperCase().replace(/^#/,"")},i=t=>{let e="";try{for(;9!==t?.nodeType;){const n=t,i=n.id?"#"+n.id:[o(n),...Array.from(n.classList).sort()].join(".");if(e.length+i.length>99)return e||i;if(e=e?i+">"+e:i,n.id)break;t=n.parentNode}}catch{}return e},r=new WeakMap;function s(t,e){return r.get(t)||r.set(t,new e),r.get(t)}let a=-1;const c=()=>a,f=t=>{addEventListener("pageshow",(e=>{e.persisted&&(a=e.timeStamp,t(e))}),!0)},u=(t,e,n,o)=>{let i,r;return s=>{e.value>=0&&(s||o)&&(r=e.value-(i??0),(r||void 0===i)&&(i=e.value,e.delta=r,e.rating=((t,e)=>t>e[1]?"poor":t>e[0]?"needs-improvement":"good")(e.value,n),t(e)))}},d=t=>{requestAnimationFrame((()=>requestAnimationFrame((()=>t()))))},l=()=>{const t=e();return t?.activationStart??0},h=(t,n=-1)=>{const o=e();let i="navigate";c()>=0?i="back-forward-cache":o&&(document.prerendering||l()>0?i="prerender":document.wasDiscarded?i="restore":o.type&&(i=o.type.replace(/_/g,"-")));return{name:t,value:n,rating:"good",delta:0,entries:[],id:`v5-${Date.now()}-${Math.floor(8999999999999*Math.random())+1e12}`,navigationType:i}},m=(t,e,n={})=>{try{if(PerformanceObserver.supportedEntryTypes.includes(t)){const o=new PerformanceObserver((t=>{Promise.resolve().then((()=>{e(t.getEntries())}))}));return o.observe({type:t,buffered:!0,...n}),o}}catch{}},p=t=>{let e=!1;return()=>{e||(t(),e=!0)}};let g=-1;const y=new Set,v=()=>"hidden"!==document.visibilityState||document.prerendering?1/0:0,b=t=>{if("hidden"===document.visibilityState){if("visibilitychange"===t.type)for(const t of y)t();isFinite(g)||(g="visibilitychange"===t.type?t.timeStamp:0,removeEventListener("prerenderingchange",b,!0))}},M=()=>{if(g<0){const t=l(),e=document.prerendering?void 0:globalThis.performance.getEntriesByType("visibility-state").filter((e=>"hidden"===e.name&&e.startTime>t))[0]?.startTime;g=e??v(),addEventListener("visibilitychange",b,!0),addEventListener("prerenderingchange",b,!0),f((()=>{setTimeout((()=>{g=v()}))}))}return{get firstHiddenTime(){return g},onHidden(t){y.add(t)}}},T=t=>{document.prerendering?addEventListener("prerenderingchange",(()=>t()),!0):t()},E=[1800,3e3],D=(t,e={})=>{T((()=>{const n=M();let o,i=h("FCP");const r=m("paint",(t=>{for(const e of t)"first-contentful-paint"===e.name&&(r.disconnect(),e.startTime<n.firstHiddenTime&&(i.value=Math.max(e.startTime-l(),0),i.entries.push(e),o(!0)))}));r&&(o=u(t,i,E,e.reportAllChanges),f((n=>{i=h("FCP"),o=u(t,i,E,e.reportAllChanges),d((()=>{i.value=performance.now()-n.timeStamp,o(!0)}))})))}))},L=[.1,.25],P=t=>t.find((t=>1===t.node?.nodeType))||t[0],S=(e,o={})=>{const r=s(o=Object.assign({},o),t),a=new WeakMap;r.t=t=>{if(t?.sources?.length){const e=P(t.sources),n=e?.node;if(n){const t=o.generateTarget?.(n)??i(n);a.set(e,t)}}};((e,n={})=>{const o=M();D(p((()=>{let i,r=h("CLS",0);const a=s(n,t),c=t=>{for(const e of t)a.u(e);a.o>r.value&&(r.value=a.o,r.entries=a.i,i())},l=m("layout-shift",c);l&&(i=u(e,r,L,n.reportAllChanges),o.onHidden((()=>{c(l.takeRecords()),i(!0)})),f((()=>{a.o=0,r=h("CLS",0),i=u(e,r,L,n.reportAllChanges),d((()=>i()))})),setTimeout(i))})))})((t=>{const o=(t=>{let e={};if(t.entries.length){const o=t.entries.reduce(((t,e)=>t.value>e.value?t:e));if(o?.sources?.length){const t=P(o.sources);t&&(e={largestShiftTarget:a.get(t),largestShiftTime:o.startTime,largestShiftValue:o.value,largestShiftSource:t,largestShiftEntry:o,loadState:n(o.startTime)})}}return Object.assign(t,{attribution:e})})(t);e(o)}),o)},w=(t,o={})=>{D((o=>{const i=(t=>{let o={timeToFirstByte:0,firstByteToFCP:t.value,loadState:n(c())};if(t.entries.length){const i=e(),r=t.entries.at(-1);if(i){const e=i.activationStart||0,s=Math.max(0,i.responseStart-e);o={timeToFirstByte:s,firstByteToFCP:t.value-s,loadState:n(t.entries[0].startTime),navigationEntry:i,fcpEntry:r}}}return Object.assign(t,{attribution:o})})(o);t(i)}),o)};let _=0,F=1/0,k=0;const B=t=>{for(const e of t)e.interactionId&&(F=Math.min(F,e.interactionId),k=Math.max(k,e.interactionId),_=k?(k-F)/7+1:0)};let C;const O=()=>C?_:performance.interactionCount??0,j=()=>{"interactionCount"in performance||C||(C=m("event",B,{type:"event",buffered:!0,durationThreshold:0}))};let I=0;class A{l=[];h=new Map;m;p;v(){I=O(),this.l.length=0,this.h.clear()}M(){const t=Math.min(this.l.length-1,Math.floor((O()-I)/50));return this.l[t]}u(t){if(this.m?.(t),!t.interactionId&&"first-input"!==t.entryType)return;const e=this.l.at(-1);let n=this.h.get(t.interactionId);if(n||this.l.length<10||t.duration>e.T){if(n?t.duration>n.T?(n.entries=[t],n.T=t.duration):t.duration===n.T&&t.startTime===n.entries[0].startTime&&n.entries.push(t):(n={id:t.interactionId,entries:[t],T:t.duration},this.h.set(n.id,n),this.l.push(n)),this.l.sort(((t,e)=>e.T-t.T)),this.l.length>10){const t=this.l.splice(10);for(const e of t)this.h.delete(e.id)}this.p?.(n)}}}const W=t=>{const e=globalThis.requestIdleCallback||setTimeout;"hidden"===document.visibilityState?t():(t=p(t),addEventListener("visibilitychange",t,{once:!0,capture:!0}),e((()=>{t(),removeEventListener("visibilitychange",t,{capture:!0})})))},q=[200,500],x=(t,e={})=>{const o=s(e=Object.assign({},e),A);let r=[],a=[],c=0;const d=new WeakMap,l=new WeakMap;let p=!1;const g=()=>{p||(W(y),p=!0)},y=()=>{const t=o.l.map((t=>d.get(t.entries[0]))),e=a.length-50;a=a.filter(((n,o)=>o>=e||t.includes(n)));const n=new Set;for(const t of a){const e=v(t.startTime,t.processingEnd);for(const t of e)n.add(t)}const i=r.length-1-50;r=r.filter(((t,e)=>t.startTime>c&&e>i||n.has(t))),p=!1};o.m=t=>{const e=t.startTime+t.duration;let n;c=Math.max(c,t.processingEnd);for(let o=a.length-1;o>=0;o--){const i=a[o];if(Math.abs(e-i.renderTime)<=8){n=i,n.startTime=Math.min(t.startTime,n.startTime),n.processingStart=Math.min(t.processingStart,n.processingStart),n.processingEnd=Math.max(t.processingEnd,n.processingEnd),n.entries.push(t);break}}n||(n={startTime:t.startTime,processingStart:t.processingStart,processingEnd:t.processingEnd,renderTime:e,entries:[t]},a.push(n)),(t.interactionId||"first-input"===t.entryType)&&d.set(t,n),g()},o.p=t=>{if(!l.get(t)){const n=t.entries[0].target;if(n){const o=e.generateTarget?.(n)??i(n);l.set(t,o)}}};const v=(t,e)=>{const n=[];for(const o of r)if(!(o.startTime+o.duration<t)){if(o.startTime>e)break;n.push(o)}return n},b=t=>{const e=t.entries[0],i=d.get(e),r=e.processingStart,s=Math.max(e.startTime+e.duration,r),a=Math.min(i.processingEnd,s),c=i.entries.sort(((t,e)=>t.processingStart-e.processingStart)),f=v(e.startTime,a),u=o.h.get(e.interactionId),h={interactionTarget:l.get(u),interactionType:e.name.startsWith("key")?"keyboard":"pointer",interactionTime:e.startTime,nextPaintTime:s,processedEventEntries:c,longAnimationFrameEntries:f,inputDelay:r-e.startTime,processingDuration:a-r,presentationDelay:s-a,loadState:n(e.startTime),longestScript:void 0,totalScriptDuration:void 0,totalStyleAndLayoutDuration:void 0,totalPaintDuration:void 0,totalUnattributedDuration:void 0};(t=>{if(!t.longAnimationFrameEntries?.length)return;const e=t.interactionTime,n=t.inputDelay,o=t.processingDuration;let i,r,s=0,a=0,c=0,f=0;for(const c of t.longAnimationFrameEntries){a=a+c.startTime+c.duration-c.styleAndLayoutStart;for(const t of c.scripts){const c=t.startTime+t.duration;if(c<e)continue;const u=c-Math.max(e,t.startTime),d=t.duration?u/t.duration*t.forcedStyleAndLayoutDuration:0;s+=u-d,a+=d,u>f&&(r=t.startTime<e+n?"input-delay":t.startTime>=e+n+o?"presentation-delay":"processing-duration",i=t,f=u)}}const u=t.longAnimationFrameEntries.at(-1),d=u?u.startTime+u.duration:0;d>=e+n+o&&(c=t.nextPaintTime-d),i&&r&&(t.longestScript={entry:i,subpart:r,intersectingDuration:f}),t.totalScriptDuration=s,t.totalStyleAndLayoutDuration=a,t.totalPaintDuration=c,t.totalUnattributedDuration=t.nextPaintTime-e-s-a-c})(h);return Object.assign(t,{attribution:h})};m("long-animation-frame",(t=>{r=r.concat(t),g()})),((t,e={})=>{if(!globalThis.PerformanceEventTiming||!("interactionId"in PerformanceEventTiming.prototype))return;const n=M();T((()=>{j();let o,i=h("INP");const r=s(e,A),a=t=>{W((()=>{for(const e of t)r.u(e);const e=r.M();e&&e.T!==i.value&&(i.value=e.T,i.entries=e.entries,o())}))},c=m("event",a,{durationThreshold:e.durationThreshold??40});o=u(t,i,q,e.reportAllChanges),c&&(c.observe({type:"first-input",buffered:!0}),n.onHidden((()=>{a(c.takeRecords()),o(!0)})),f((()=>{r.v(),i=h("INP"),o=u(t,i,q,e.reportAllChanges)})))}))})((e=>{const n=b(e);t(n)}),e)};class N{m;u(t){this.m?.(t)}}const H=[2500,4e3],R=(t,n={})=>{const o=s(n=Object.assign({},n),N),r=new WeakMap;o.m=t=>{const e=t.element;if(e){const o=n.generateTarget?.(e)??i(e);r.set(t,o)}};((t,e={})=>{T((()=>{const n=M();let o,i=h("LCP");const r=s(e,N),a=t=>{e.reportAllChanges||(t=t.slice(-1));for(const e of t)r.u(e),e.startTime<n.firstHiddenTime&&(i.value=Math.max(e.startTime-l(),0),i.entries=[e],o())},c=m("largest-contentful-paint",a);if(c){o=u(t,i,H,e.reportAllChanges);const n=p((()=>{a(c.takeRecords()),c.disconnect(),o(!0)})),r=t=>{t.isTrusted&&(W(n),removeEventListener(t.type,r,{capture:!0}))};for(const t of["keydown","click","visibilitychange"])addEventListener(t,r,{capture:!0});f((n=>{i=h("LCP"),o=u(t,i,H,e.reportAllChanges),d((()=>{i.value=performance.now()-n.timeStamp,o(!0)}))}))}}))})((n=>{const o=(t=>{let n={timeToFirstByte:0,resourceLoadDelay:0,resourceLoadDuration:0,elementRenderDelay:t.value};if(t.entries.length){const o=e();if(o){const e=o.activationStart||0,i=t.entries.at(-1),s=i.url&&performance.getEntriesByType("resource").filter((t=>t.name===i.url))[0],a=Math.max(0,o.responseStart-e),c=Math.max(a,s?(s.requestStart||s.startTime)-e:0),f=Math.min(t.value,Math.max(c,s?s.responseEnd-e:0));n={target:r.get(i),timeToFirstByte:a,resourceLoadDelay:c-a,resourceLoadDuration:f-c,elementRenderDelay:t.value-f,navigationEntry:o,lcpEntry:i},i.url&&(n.url=i.url),s&&(n.lcpResourceEntry=s)}}return Object.assign(t,{attribution:n})})(n);t(o)}),n)},U=[800,1800],V=t=>{document.prerendering?T((()=>V(t))):"complete"!==document.readyState?addEventListener("load",(()=>V(t)),!0):setTimeout(t)},$=(t,n={})=>{((t,n={})=>{let o=h("TTFB"),i=u(t,o,U,n.reportAllChanges);V((()=>{const r=e();r&&(o.value=Math.max(r.responseStart-l(),0),o.entries=[r],i(!0),f((()=>{o=h("TTFB",0),i=u(t,o,U,n.reportAllChanges),i(!0)})))}))})((e=>{const n=(t=>{let e={waitingDuration:0,cacheDuration:0,dnsDuration:0,connectionDuration:0,requestDuration:0};if(t.entries.length){const n=t.entries[0],o=n.activationStart||0,i=Math.max((n.workerStart||n.fetchStart)-o,0),r=Math.max(n.domainLookupStart-o,0),s=Math.max(n.connectStart-o,0),a=Math.max(n.connectEnd-o,0);e={waitingDuration:i,cacheDuration:r-i,dnsDuration:s-r,connectionDuration:a-s,requestDuration:t.value-a,navigationEntry:n}}return Object.assign(t,{attribution:e})})(e);t(n)}),n)};export{L as CLSThresholds,E as FCPThresholds,q as INPThresholds,H as LCPThresholds,U as TTFBThresholds,S as onCLS,w as onFCP,x as onINP,R as onLCP,$ as onTTFB};