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