applying transfer to react app

This commit is contained in:
Tyler Koenig
2021-09-20 16:54:47 -04:00
parent 8819f31dd0
commit c612b7d702
37373 changed files with 3775588 additions and 2871 deletions
+2
View File
@@ -0,0 +1,2 @@
import { ReportHandler } from './types.js';
export declare const getCLS: (onReport: ReportHandler, reportAllChanges?: boolean | undefined) => void;
+44
View File
@@ -0,0 +1,44 @@
/*
* Copyright 2020 Google LLC
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* https://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
import { initMetric } from './lib/initMetric.js';
import { observe } from './lib/observe.js';
import { onHidden } from './lib/onHidden.js';
import { onBFCacheRestore } from './lib/onBFCacheRestore.js';
import { bindReporter } from './lib/bindReporter.js';
export const getCLS = (onReport, reportAllChanges) => {
let metric = initMetric('CLS', 0);
let report;
const entryHandler = (entry) => {
// Only count layout shifts without recent user input.
if (!entry.hadRecentInput) {
metric.value += entry.value;
metric.entries.push(entry);
report();
}
};
const po = observe('layout-shift', entryHandler);
if (po) {
report = bindReporter(onReport, metric, reportAllChanges);
onHidden(() => {
po.takeRecords().map(entryHandler);
report();
});
onBFCacheRestore(() => {
metric = initMetric('CLS', 0);
report = bindReporter(onReport, metric, reportAllChanges);
});
}
};
+2
View File
@@ -0,0 +1,2 @@
import { ReportHandler } from './types.js';
export declare const getFCP: (onReport: ReportHandler, reportAllChanges?: boolean | undefined) => void;
+61
View File
@@ -0,0 +1,61 @@
/*
* Copyright 2020 Google LLC
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* https://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
import { bindReporter } from './lib/bindReporter.js';
import { finalMetrics } from './lib/finalMetrics.js';
import { getFirstHidden } from './lib/getFirstHidden.js';
import { initMetric } from './lib/initMetric.js';
import { observe } from './lib/observe.js';
import { onBFCacheRestore } from './lib/onBFCacheRestore.js';
export const getFCP = (onReport, reportAllChanges) => {
const firstHidden = getFirstHidden();
let metric = initMetric('FCP');
let report;
const entryHandler = (entry) => {
if (entry.name === 'first-contentful-paint') {
if (po) {
po.disconnect();
}
// Only report if the page wasn't hidden prior to the first paint.
if (entry.startTime < firstHidden.timeStamp) {
metric.value = entry.startTime;
metric.entries.push(entry);
finalMetrics.add(metric);
report();
}
}
};
// TODO(philipwalton): remove the use of `fcpEntry` once this bug is fixed.
// https://bugs.webkit.org/show_bug.cgi?id=225305
const fcpEntry = performance.getEntriesByName('first-contentful-paint')[0];
const po = fcpEntry ? null : observe('paint', entryHandler);
if (fcpEntry || po) {
report = bindReporter(onReport, metric, reportAllChanges);
if (fcpEntry) {
entryHandler(fcpEntry);
}
onBFCacheRestore((event) => {
metric = initMetric('FCP');
report = bindReporter(onReport, metric, reportAllChanges);
requestAnimationFrame(() => {
requestAnimationFrame(() => {
metric.value = performance.now() - event.timeStamp;
finalMetrics.add(metric);
report();
});
});
});
}
};
+2
View File
@@ -0,0 +1,2 @@
import { ReportHandler } from './types.js';
export declare const getFID: (onReport: ReportHandler, reportAllChanges?: boolean | undefined) => void;
+68
View File
@@ -0,0 +1,68 @@
/*
* Copyright 2020 Google LLC
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* https://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
import { bindReporter } from './lib/bindReporter.js';
import { finalMetrics } from './lib/finalMetrics.js';
import { getFirstHidden } from './lib/getFirstHidden.js';
import { initMetric } from './lib/initMetric.js';
import { observe } from './lib/observe.js';
import { onBFCacheRestore } from './lib/onBFCacheRestore.js';
import { onHidden } from './lib/onHidden.js';
import { firstInputPolyfill, resetFirstInputPolyfill } from './lib/polyfills/firstInputPolyfill.js';
export const getFID = (onReport, reportAllChanges) => {
const firstHidden = getFirstHidden();
let metric = initMetric('FID');
let report;
const entryHandler = (entry) => {
// Only report if the page wasn't hidden prior to the first input.
if (entry.startTime < firstHidden.timeStamp) {
metric.value = entry.processingStart - entry.startTime;
metric.entries.push(entry);
finalMetrics.add(metric);
report();
}
};
const po = observe('first-input', entryHandler);
report = bindReporter(onReport, metric, reportAllChanges);
if (po) {
onHidden(() => {
po.takeRecords().map(entryHandler);
po.disconnect();
}, true);
}
if (self.__WEB_VITALS_POLYFILL__) {
// Prefer the native implementation if available,
if (!po) {
window.webVitals.firstInputPolyfill(entryHandler);
}
onBFCacheRestore(() => {
metric = initMetric('FID');
report = bindReporter(onReport, metric, reportAllChanges);
window.webVitals.resetFirstInputPolyfill();
window.webVitals.firstInputPolyfill(entryHandler);
});
}
else {
// Only monitor bfcache restores if the browser supports FID natively.
if (po) {
onBFCacheRestore(() => {
metric = initMetric('FID');
report = bindReporter(onReport, metric, reportAllChanges);
resetFirstInputPolyfill();
firstInputPolyfill(entryHandler);
});
}
}
};
+2
View File
@@ -0,0 +1,2 @@
import { ReportHandler } from './types.js';
export declare const getLCP: (onReport: ReportHandler, reportAllChanges?: boolean | undefined) => void;
+69
View File
@@ -0,0 +1,69 @@
/*
* Copyright 2020 Google LLC
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* https://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
import { bindReporter } from './lib/bindReporter.js';
import { finalMetrics } from './lib/finalMetrics.js';
import { getFirstHidden } from './lib/getFirstHidden.js';
import { initMetric } from './lib/initMetric.js';
import { observe } from './lib/observe.js';
import { onBFCacheRestore } from './lib/onBFCacheRestore.js';
import { onHidden } from './lib/onHidden.js';
export const getLCP = (onReport, reportAllChanges) => {
const firstHidden = getFirstHidden();
let metric = initMetric('LCP');
let report;
const entryHandler = (entry) => {
// The startTime attribute returns the value of the renderTime if it is not 0,
// and the value of the loadTime otherwise.
const value = entry.startTime;
// If the page was hidden prior to paint time of the entry,
// ignore it and mark the metric as final, otherwise add the entry.
if (value < firstHidden.timeStamp) {
metric.value = value;
metric.entries.push(entry);
}
report();
};
const po = observe('largest-contentful-paint', entryHandler);
if (po) {
report = bindReporter(onReport, metric, reportAllChanges);
const stopListening = () => {
if (!finalMetrics.has(metric)) {
po.takeRecords().map(entryHandler);
po.disconnect();
finalMetrics.add(metric);
report();
}
};
// Stop listening after input. Note: while scrolling is an input that
// stop LCP observation, it's unreliable since it can be programmatically
// generated. See: https://github.com/GoogleChrome/web-vitals/issues/75
['keydown', 'click'].forEach((type) => {
addEventListener(type, stopListening, { once: true, capture: true });
});
onHidden(stopListening, true);
onBFCacheRestore((event) => {
metric = initMetric('LCP');
report = bindReporter(onReport, metric, reportAllChanges);
requestAnimationFrame(() => {
requestAnimationFrame(() => {
metric.value = performance.now() - event.timeStamp;
finalMetrics.add(metric);
report();
});
});
});
}
};
+2
View File
@@ -0,0 +1,2 @@
import { ReportHandler } from './types.js';
export declare const getTTFB: (onReport: ReportHandler) => void;
+62
View File
@@ -0,0 +1,62 @@
/*
* Copyright 2020 Google LLC
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* https://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
import { initMetric } from './lib/initMetric.js';
const afterLoad = (callback) => {
if (document.readyState === 'complete') {
// Queue a task so the callback runs after `loadEventEnd`.
setTimeout(callback, 0);
}
else {
// Use `pageshow` so the callback runs after `loadEventEnd`.
addEventListener('pageshow', callback);
}
};
const getNavigationEntryFromPerformanceTiming = () => {
// Really annoying that TypeScript errors when using `PerformanceTiming`.
const timing = performance.timing;
const navigationEntry = {
entryType: 'navigation',
startTime: 0,
};
for (const key in timing) {
if (key !== 'navigationStart' && key !== 'toJSON') {
navigationEntry[key] = Math.max(timing[key] -
timing.navigationStart, 0);
}
}
return navigationEntry;
};
export const getTTFB = (onReport) => {
const metric = initMetric('TTFB');
afterLoad(() => {
try {
// Use the NavigationTiming L2 entry if available.
const navigationEntry = performance.getEntriesByType('navigation')[0] ||
getNavigationEntryFromPerformanceTiming();
metric.value = metric.delta =
navigationEntry.responseStart;
// In some cases the value reported is negative. Ignore these cases:
// https://github.com/GoogleChrome/web-vitals/issues/137
if (metric.value < 0)
return;
metric.entries = [navigationEntry];
onReport(metric);
}
catch (error) {
// Do nothing.
}
});
};
+6
View File
@@ -0,0 +1,6 @@
export { getCLS } from './getCLS.js';
export { getFCP } from './getFCP.js';
export { getFID } from './getFID.js';
export { getLCP } from './getLCP.js';
export { getTTFB } from './getTTFB.js';
export * from './types.js';
+21
View File
@@ -0,0 +1,21 @@
/*
* Copyright 2020 Google LLC
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* https://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
export { getCLS } from './getCLS.js';
export { getFCP } from './getFCP.js';
export { getFID } from './getFID.js';
export { getLCP } from './getLCP.js';
export { getTTFB } from './getTTFB.js';
export * from './types.js';
+2
View File
@@ -0,0 +1,2 @@
import { Metric, ReportHandler } from '../types.js';
export declare const bindReporter: (callback: ReportHandler, metric: Metric, reportAllChanges?: boolean | undefined) => () => void;
+36
View File
@@ -0,0 +1,36 @@
/*
* Copyright 2020 Google LLC
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* https://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
import { finalMetrics } from './finalMetrics.js';
export const bindReporter = (callback, metric, reportAllChanges) => {
let prevValue;
return () => {
if (metric.value >= 0) {
if (reportAllChanges ||
finalMetrics.has(metric) ||
document.visibilityState === 'hidden') {
metric.delta = metric.value - (prevValue || 0);
// Report the metric if there's a non-zero delta, if the metric is
// final, or if no previous value exists (which can happen in the case
// of the document becoming hidden when the metric value is 0).
// See: https://github.com/GoogleChrome/web-vitals/issues/14
if (metric.delta || prevValue === undefined) {
prevValue = metric.value;
callback(metric);
}
}
}
};
};
+2
View File
@@ -0,0 +1,2 @@
import { Metric } from '../types.js';
export declare const finalMetrics: WeakSet<Metric> | Set<Metric>;
+16
View File
@@ -0,0 +1,16 @@
/*
* Copyright 2020 Google LLC
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* https://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
export const finalMetrics = typeof WeakSet === 'function' ? new WeakSet() : new Set();
+6
View File
@@ -0,0 +1,6 @@
/**
* Performantly generate a unique, 30-char string by combining a version
* number, the current timestamp with a 13-digit number integer.
* @return {string}
*/
export declare const generateUniqueID: () => string;
+23
View File
@@ -0,0 +1,23 @@
/*
* Copyright 2020 Google LLC
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* https://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
/**
* Performantly generate a unique, 30-char string by combining a version
* number, the current timestamp with a 13-digit number integer.
* @return {string}
*/
export const generateUniqueID = () => {
return `v1-${Date.now()}-${Math.floor(Math.random() * (9e12 - 1)) + 1e12}`;
};
+3
View File
@@ -0,0 +1,3 @@
export declare const getFirstHidden: () => {
readonly timeStamp: number;
};
+60
View File
@@ -0,0 +1,60 @@
/*
* Copyright 2020 Google LLC
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* https://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
import { onBFCacheRestore } from './onBFCacheRestore.js';
import { onHidden } from './onHidden.js';
let firstHiddenTime = -1;
const initHiddenTime = () => {
return document.visibilityState === 'hidden' ? 0 : Infinity;
};
const trackChanges = () => {
// Update the time if/when the document becomes hidden.
onHidden(({ timeStamp }) => {
firstHiddenTime = timeStamp;
}, true);
};
export const getFirstHidden = () => {
if (firstHiddenTime < 0) {
// If the document is hidden when this code runs, assume it was hidden
// since navigation start. This isn't a perfect heuristic, but it's the
// best we can do until an API is available to support querying past
// visibilityState.
if (self.__WEB_VITALS_POLYFILL__) {
firstHiddenTime = self.webVitals.firstHiddenTime;
if (firstHiddenTime === Infinity) {
trackChanges();
}
}
else {
firstHiddenTime = initHiddenTime();
trackChanges();
}
// Reset the time on bfcache restores.
onBFCacheRestore(() => {
// Schedule a task in order to track the `visibilityState` once it's
// had an opportunity to change to visible in all browsers.
// https://bugs.chromium.org/p/chromium/issues/detail?id=1133363
setTimeout(() => {
firstHiddenTime = initHiddenTime();
trackChanges();
}, 0);
});
}
return {
get timeStamp() {
return firstHiddenTime;
}
};
};
+2
View File
@@ -0,0 +1,2 @@
import { Metric } from '../types.js';
export declare const initMetric: (name: Metric['name'], value?: number | undefined) => Metric;
+25
View File
@@ -0,0 +1,25 @@
/*
* Copyright 2020 Google LLC
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* https://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
import { generateUniqueID } from './generateUniqueID.js';
export const initMetric = (name, value) => {
return {
name,
value: typeof value === 'undefined' ? -1 : value,
delta: 0,
entries: [],
id: generateUniqueID()
};
};
+12
View File
@@ -0,0 +1,12 @@
export interface PerformanceEntryHandler {
(entry: PerformanceEntry): void;
}
/**
* Takes a performance entry type and a callback function, and creates a
* `PerformanceObserver` instance that will observe the specified entry type
* with buffering enabled and call the callback _for each entry_.
*
* This function also feature-detects entry support and wraps the logic in a
* try/catch to avoid errors in unsupporting browsers.
*/
export declare const observe: (type: string, callback: PerformanceEntryHandler) => PerformanceObserver | undefined;
+41
View File
@@ -0,0 +1,41 @@
/*
* Copyright 2020 Google LLC
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* https://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
/**
* Takes a performance entry type and a callback function, and creates a
* `PerformanceObserver` instance that will observe the specified entry type
* with buffering enabled and call the callback _for each entry_.
*
* This function also feature-detects entry support and wraps the logic in a
* try/catch to avoid errors in unsupporting browsers.
*/
export const observe = (type, callback) => {
try {
if (PerformanceObserver.supportedEntryTypes.includes(type)) {
// More extensive feature detect needed for Firefox due to:
// https://github.com/GoogleChrome/web-vitals/issues/142
if (type === 'first-input' && !('PerformanceEventTiming' in self)) {
return;
}
const po = new PerformanceObserver((l) => l.getEntries().map(callback));
po.observe({ type, buffered: true });
return po;
}
}
catch (e) {
// Do nothing.
}
return;
};
+5
View File
@@ -0,0 +1,5 @@
interface onBFCacheRestoreCallback {
(event: PageTransitionEvent): void;
}
export declare const onBFCacheRestore: (cb: onBFCacheRestoreCallback) => void;
export {};
+22
View File
@@ -0,0 +1,22 @@
/*
* Copyright 2020 Google LLC
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* https://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
export const onBFCacheRestore = (cb) => {
addEventListener('pageshow', (event) => {
if (event.persisted) {
cb(event);
}
}, true);
};
+4
View File
@@ -0,0 +1,4 @@
export interface OnHiddenCallback {
(event: Event): void;
}
export declare const onHidden: (cb: OnHiddenCallback, once?: boolean | undefined) => void;
+30
View File
@@ -0,0 +1,30 @@
/*
* Copyright 2020 Google LLC
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* https://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
export const onHidden = (cb, once) => {
const onHiddenOrPageHide = (event) => {
if (event.type === 'pagehide' || document.visibilityState === 'hidden') {
cb(event);
if (once) {
removeEventListener('visibilitychange', onHiddenOrPageHide, true);
removeEventListener('pagehide', onHiddenOrPageHide, true);
}
}
};
addEventListener('visibilitychange', onHiddenOrPageHide, true);
// Some browsers have buggy implementations of visibilitychange,
// so we use pagehide in addition, just to be safe.
addEventListener('pagehide', onHiddenOrPageHide, true);
};
@@ -0,0 +1,7 @@
import { FirstInputPolyfillCallback } from '../../types.js';
/**
* Accepts a callback to be invoked once the first input delay and event
* are known.
*/
export declare const firstInputPolyfill: (onFirstInput: FirstInputPolyfillCallback) => void;
export declare const resetFirstInputPolyfill: () => void;
@@ -0,0 +1,152 @@
/*
* Copyright 2020 Google LLC
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* https://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
let firstInputEvent;
let firstInputDelay;
let firstInputTimeStamp;
let callbacks;
const listenerOpts = { passive: true, capture: true };
const startTimeStamp = new Date();
/**
* Accepts a callback to be invoked once the first input delay and event
* are known.
*/
export const firstInputPolyfill = (onFirstInput) => {
callbacks.push(onFirstInput);
reportFirstInputDelayIfRecordedAndValid();
};
export const resetFirstInputPolyfill = () => {
callbacks = [];
firstInputDelay = -1;
firstInputEvent = null;
eachEventType(addEventListener);
};
/**
* Records the first input delay and event, so subsequent events can be
* ignored. All added event listeners are then removed.
*/
const recordFirstInputDelay = (delay, event) => {
if (!firstInputEvent) {
firstInputEvent = event;
firstInputDelay = delay;
firstInputTimeStamp = new Date;
eachEventType(removeEventListener);
reportFirstInputDelayIfRecordedAndValid();
}
};
/**
* Reports the first input delay and event (if they're recorded and valid)
* by running the array of callback functions.
*/
const reportFirstInputDelayIfRecordedAndValid = () => {
// In some cases the recorded delay is clearly wrong, e.g. it's negative
// or it's larger than the delta between now and initialization.
// - https://github.com/GoogleChromeLabs/first-input-delay/issues/4
// - https://github.com/GoogleChromeLabs/first-input-delay/issues/6
// - https://github.com/GoogleChromeLabs/first-input-delay/issues/7
if (firstInputDelay >= 0 &&
// @ts-ignore (subtracting two dates always returns a number)
firstInputDelay < firstInputTimeStamp - startTimeStamp) {
const entry = {
entryType: 'first-input',
name: firstInputEvent.type,
target: firstInputEvent.target,
cancelable: firstInputEvent.cancelable,
startTime: firstInputEvent.timeStamp,
processingStart: firstInputEvent.timeStamp + firstInputDelay,
};
callbacks.forEach(function (callback) {
callback(entry);
});
callbacks = [];
}
};
/**
* Handles pointer down events, which are a special case.
* Pointer events can trigger main or compositor thread behavior.
* We differentiate these cases based on whether or not we see a
* 'pointercancel' event, which are fired when we scroll. If we're scrolling
* we don't need to report input delay since FID excludes scrolling and
* pinch/zooming.
*/
const onPointerDown = (delay, event) => {
/**
* Responds to 'pointerup' events and records a delay. If a pointer up event
* is the next event after a pointerdown event, then it's not a scroll or
* a pinch/zoom.
*/
const onPointerUp = () => {
recordFirstInputDelay(delay, event);
removePointerEventListeners();
};
/**
* Responds to 'pointercancel' events and removes pointer listeners.
* If a 'pointercancel' is the next event to fire after a pointerdown event,
* it means this is a scroll or pinch/zoom interaction.
*/
const onPointerCancel = () => {
removePointerEventListeners();
};
/**
* Removes added pointer event listeners.
*/
const removePointerEventListeners = () => {
removeEventListener('pointerup', onPointerUp, listenerOpts);
removeEventListener('pointercancel', onPointerCancel, listenerOpts);
};
addEventListener('pointerup', onPointerUp, listenerOpts);
addEventListener('pointercancel', onPointerCancel, listenerOpts);
};
/**
* Handles all input events and records the time between when the event
* was received by the operating system and when it's JavaScript listeners
* were able to run.
*/
const onInput = (event) => {
// Only count cancelable events, which should trigger behavior
// important to the user.
if (event.cancelable) {
// In some browsers `event.timeStamp` returns a `DOMTimeStamp` value
// (epoch time) instead of the newer `DOMHighResTimeStamp`
// (document-origin time). To check for that we assume any timestamp
// greater than 1 trillion is a `DOMTimeStamp`, and compare it using
// the `Date` object rather than `performance.now()`.
// - https://github.com/GoogleChromeLabs/first-input-delay/issues/4
const isEpochTime = event.timeStamp > 1e12;
const now = isEpochTime ? new Date : performance.now();
// Input delay is the delta between when the system received the event
// (e.g. event.timeStamp) and when it could run the callback (e.g. `now`).
const delay = now - event.timeStamp;
if (event.type == 'pointerdown') {
onPointerDown(delay, event);
}
else {
recordFirstInputDelay(delay, event);
}
}
};
/**
* Invokes the passed callback const for = each event type with t =>he
* `onInput` const and = `listenerOpts =>`.
*/
const eachEventType = (callback) => {
const eventTypes = [
'mousedown',
'keydown',
'touchstart',
'pointerdown',
];
eventTypes.forEach((type) => callback(type, onInput, listenerOpts));
};
@@ -0,0 +1 @@
export declare const getFirstHiddenTime: () => number;
@@ -0,0 +1,25 @@
/*
* Copyright 2020 Google LLC
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* https://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
let firstHiddenTime = document.visibilityState === 'hidden' ? 0 : Infinity;
const onVisibilityChange = (event) => {
if (document.visibilityState === 'hidden') {
firstHiddenTime = event.timeStamp;
removeEventListener('visibilitychange', onVisibilityChange, true);
}
};
// Note: do not add event listeners unconditionally (outside of polyfills).
addEventListener('visibilitychange', onVisibilityChange, true);
export const getFirstHiddenTime = () => firstHiddenTime;
+1
View File
@@ -0,0 +1 @@
export {};
+27
View File
@@ -0,0 +1,27 @@
/*
* Copyright 2020 Google LLC
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* https://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
import { firstInputPolyfill, resetFirstInputPolyfill } from './lib/polyfills/firstInputPolyfill.js';
import { getFirstHiddenTime } from './lib/polyfills/getFirstHiddenTimePolyfill.js';
resetFirstInputPolyfill();
self.webVitals = {
firstInputPolyfill: firstInputPolyfill,
resetFirstInputPolyfill: resetFirstInputPolyfill,
// TODO: in v2 this should just be `getFirstHiddenTime()`,
// but in v1 it needs to be a getter to avoid creating a breaking change.
get firstHiddenTime() {
return getFirstHiddenTime();
},
};
+33
View File
@@ -0,0 +1,33 @@
export interface Metric {
name: 'CLS' | 'FCP' | 'FID' | 'LCP' | 'TTFB';
value: number;
delta: number;
id: string;
entries: (PerformanceEntry | FirstInputPolyfillEntry | NavigationTimingPolyfillEntry)[];
}
export interface ReportHandler {
(metric: Metric): void;
}
export interface PerformanceEventTiming extends PerformanceEntry {
processingStart: DOMHighResTimeStamp;
processingEnd: DOMHighResTimeStamp;
duration: DOMHighResTimeStamp;
cancelable?: boolean;
target?: Element;
}
export declare type FirstInputPolyfillEntry = Omit<PerformanceEventTiming, 'processingEnd' | 'toJSON'>;
export interface FirstInputPolyfillCallback {
(entry: FirstInputPolyfillEntry): void;
}
export declare type NavigationTimingPolyfillEntry = Omit<PerformanceNavigationTiming, 'initiatorType' | 'nextHopProtocol' | 'redirectCount' | 'transferSize' | 'encodedBodySize' | 'decodedBodySize' | 'toJSON'>;
export interface WebVitalsGlobal {
firstInputPolyfill: (onFirstInput: FirstInputPolyfillCallback) => void;
resetFirstInputPolyfill: () => void;
firstHiddenTime: number;
}
declare global {
interface Window {
webVitals: WebVitalsGlobal;
__WEB_VITALS_POLYFILL__: boolean;
}
}
+16
View File
@@ -0,0 +1,16 @@
/*
* Copyright 2020 Google LLC
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* https://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
export {};
+1
View File
@@ -0,0 +1 @@
!function(){var e,t,n,i,r={passive:!0,capture:!0},a=new Date,o=function(){i=[],t=-1,e=null,f(addEventListener)},c=function(i,r){e||(e=r,t=i,n=new Date,f(removeEventListener),u())},u=function(){if(t>=0&&t<n-a){var r={entryType:"first-input",name:e.type,target:e.target,cancelable:e.cancelable,startTime:e.timeStamp,processingStart:e.timeStamp+t};i.forEach((function(e){e(r)})),i=[]}},s=function(e){if(e.cancelable){var t=(e.timeStamp>1e12?new Date:performance.now())-e.timeStamp;"pointerdown"==e.type?function(e,t){var n=function(){c(e,t),a()},i=function(){a()},a=function(){removeEventListener("pointerup",n,r),removeEventListener("pointercancel",i,r)};addEventListener("pointerup",n,r),addEventListener("pointercancel",i,r)}(t,e):c(t,e)}},f=function(e){["mousedown","keydown","touchstart","pointerdown"].forEach((function(t){return e(t,s,r)}))},p="hidden"===document.visibilityState?0:1/0;addEventListener("visibilitychange",(function e(t){"hidden"===document.visibilityState&&(p=t.timeStamp,removeEventListener("visibilitychange",e,!0))}),!0);o(),self.webVitals={firstInputPolyfill:function(e){i.push(e),u()},resetFirstInputPolyfill:o,get firstHiddenTime(){return p}}}();
+1
View File
@@ -0,0 +1 @@
var t=function(t,e){return{name:t,value:void 0===e?-1:e,delta:0,entries:[],id:"v1-".concat(Date.now(),"-").concat(Math.floor(8999999999999*Math.random())+1e12)}},e=function(t,e){try{if(PerformanceObserver.supportedEntryTypes.includes(t)){if("first-input"===t&&!("PerformanceEventTiming"in self))return;var n=new PerformanceObserver((function(t){return t.getEntries().map(e)}));return n.observe({type:t,buffered:!0}),n}}catch(t){}},n=function(t,e){var n=function n(i){"pagehide"!==i.type&&"hidden"!==document.visibilityState||(t(i),e&&(removeEventListener("visibilitychange",n,!0),removeEventListener("pagehide",n,!0)))};addEventListener("visibilitychange",n,!0),addEventListener("pagehide",n,!0)},i=function(t){addEventListener("pageshow",(function(e){e.persisted&&t(e)}),!0)},a="function"==typeof WeakSet?new WeakSet:new Set,r=function(t,e,n){var i;return function(){e.value>=0&&(n||a.has(e)||"hidden"===document.visibilityState)&&(e.delta=e.value-(i||0),(e.delta||void 0===i)&&(i=e.value,t(e)))}},o=function(a,o){var u,c=t("CLS",0),s=function(t){t.hadRecentInput||(c.value+=t.value,c.entries.push(t),u())},f=e("layout-shift",s);f&&(u=r(a,c,o),n((function(){f.takeRecords().map(s),u()})),i((function(){c=t("CLS",0),u=r(a,c,o)})))},u=-1,c=function(){n((function(t){var e=t.timeStamp;u=e}),!0)},s=function(){return u<0&&((u=self.webVitals.firstHiddenTime)===1/0&&c(),i((function(){setTimeout((function(){u="hidden"===document.visibilityState?0:1/0,c()}),0)}))),{get timeStamp(){return u}}},f=function(n,o){var u,c=s(),f=t("FCP"),d=function(t){"first-contentful-paint"===t.name&&(v&&v.disconnect(),t.startTime<c.timeStamp&&(f.value=t.startTime,f.entries.push(t),a.add(f),u()))},m=performance.getEntriesByName("first-contentful-paint")[0],v=m?null:e("paint",d);(m||v)&&(u=r(n,f,o),m&&d(m),i((function(e){f=t("FCP"),u=r(n,f,o),requestAnimationFrame((function(){requestAnimationFrame((function(){f.value=performance.now()-e.timeStamp,a.add(f),u()}))}))})))},d=function(o,u){var c,f=s(),d=t("FID"),m=function(t){t.startTime<f.timeStamp&&(d.value=t.processingStart-t.startTime,d.entries.push(t),a.add(d),c())},v=e("first-input",m);c=r(o,d,u),v&&n((function(){v.takeRecords().map(m),v.disconnect()}),!0),v||window.webVitals.firstInputPolyfill(m),i((function(){d=t("FID"),c=r(o,d,u),window.webVitals.resetFirstInputPolyfill(),window.webVitals.firstInputPolyfill(m)}))},m=function(o,u){var c,f=s(),d=t("LCP"),m=function(t){var e=t.startTime;e<f.timeStamp&&(d.value=e,d.entries.push(t)),c()},v=e("largest-contentful-paint",m);if(v){c=r(o,d,u);var p=function(){a.has(d)||(v.takeRecords().map(m),v.disconnect(),a.add(d),c())};["keydown","click"].forEach((function(t){addEventListener(t,p,{once:!0,capture:!0})})),n(p,!0),i((function(e){d=t("LCP"),c=r(o,d,u),requestAnimationFrame((function(){requestAnimationFrame((function(){d.value=performance.now()-e.timeStamp,a.add(d),c()}))}))}))}},v=function(e){var n,i=t("TTFB");n=function(){try{var t=performance.getEntriesByType("navigation")[0]||function(){var t=performance.timing,e={entryType:"navigation",startTime:0};for(var n in t)"navigationStart"!==n&&"toJSON"!==n&&(e[n]=Math.max(t[n]-t.navigationStart,0));return e}();if(i.value=i.delta=t.responseStart,i.value<0)return;i.entries=[t],e(i)}catch(t){}},"complete"===document.readyState?setTimeout(n,0):addEventListener("pageshow",n)};export{o as getCLS,f as getFCP,d as getFID,m as getLCP,v as getTTFB};
+1
View File
@@ -0,0 +1 @@
!function(e,t){"object"==typeof exports&&"undefined"!=typeof module?t(exports):"function"==typeof define&&define.amd?define(["exports"],t):t((e="undefined"!=typeof globalThis?globalThis:e||self).webVitals=e.webVitals||{})}(this,(function(e){"use strict";var t=function(e,t){return{name:e,value:void 0===t?-1:t,delta:0,entries:[],id:"v1-".concat(Date.now(),"-").concat(Math.floor(8999999999999*Math.random())+1e12)}},n=function(e,t){try{if(PerformanceObserver.supportedEntryTypes.includes(e)){if("first-input"===e&&!("PerformanceEventTiming"in self))return;var n=new PerformanceObserver((function(e){return e.getEntries().map(t)}));return n.observe({type:e,buffered:!0}),n}}catch(e){}},i=function(e,t){var n=function n(i){"pagehide"!==i.type&&"hidden"!==document.visibilityState||(e(i),t&&(removeEventListener("visibilitychange",n,!0),removeEventListener("pagehide",n,!0)))};addEventListener("visibilitychange",n,!0),addEventListener("pagehide",n,!0)},a=function(e){addEventListener("pageshow",(function(t){t.persisted&&e(t)}),!0)},r="function"==typeof WeakSet?new WeakSet:new Set,o=function(e,t,n){var i;return function(){t.value>=0&&(n||r.has(t)||"hidden"===document.visibilityState)&&(t.delta=t.value-(i||0),(t.delta||void 0===i)&&(i=t.value,e(t)))}},u=-1,s=function(){i((function(e){var t=e.timeStamp;u=t}),!0)},c=function(){return u<0&&((u=self.webVitals.firstHiddenTime)===1/0&&s(),a((function(){setTimeout((function(){u="hidden"===document.visibilityState?0:1/0,s()}),0)}))),{get timeStamp(){return u}}};e.getCLS=function(e,r){var u,s=t("CLS",0),c=function(e){e.hadRecentInput||(s.value+=e.value,s.entries.push(e),u())},f=n("layout-shift",c);f&&(u=o(e,s,r),i((function(){f.takeRecords().map(c),u()})),a((function(){s=t("CLS",0),u=o(e,s,r)})))},e.getFCP=function(e,i){var u,s=c(),f=t("FCP"),d=function(e){"first-contentful-paint"===e.name&&(l&&l.disconnect(),e.startTime<s.timeStamp&&(f.value=e.startTime,f.entries.push(e),r.add(f),u()))},m=performance.getEntriesByName("first-contentful-paint")[0],l=m?null:n("paint",d);(m||l)&&(u=o(e,f,i),m&&d(m),a((function(n){f=t("FCP"),u=o(e,f,i),requestAnimationFrame((function(){requestAnimationFrame((function(){f.value=performance.now()-n.timeStamp,r.add(f),u()}))}))})))},e.getFID=function(e,u){var s,f=c(),d=t("FID"),m=function(e){e.startTime<f.timeStamp&&(d.value=e.processingStart-e.startTime,d.entries.push(e),r.add(d),s())},l=n("first-input",m);s=o(e,d,u),l&&i((function(){l.takeRecords().map(m),l.disconnect()}),!0),l||window.webVitals.firstInputPolyfill(m),a((function(){d=t("FID"),s=o(e,d,u),window.webVitals.resetFirstInputPolyfill(),window.webVitals.firstInputPolyfill(m)}))},e.getLCP=function(e,u){var s,f=c(),d=t("LCP"),m=function(e){var t=e.startTime;t<f.timeStamp&&(d.value=t,d.entries.push(e)),s()},l=n("largest-contentful-paint",m);if(l){s=o(e,d,u);var p=function(){r.has(d)||(l.takeRecords().map(m),l.disconnect(),r.add(d),s())};["keydown","click"].forEach((function(e){addEventListener(e,p,{once:!0,capture:!0})})),i(p,!0),a((function(n){d=t("LCP"),s=o(e,d,u),requestAnimationFrame((function(){requestAnimationFrame((function(){d.value=performance.now()-n.timeStamp,r.add(d),s()}))}))}))}},e.getTTFB=function(e){var n,i=t("TTFB");n=function(){try{var t=performance.getEntriesByType("navigation")[0]||function(){var e=performance.timing,t={entryType:"navigation",startTime:0};for(var n in e)"navigationStart"!==n&&"toJSON"!==n&&(t[n]=Math.max(e[n]-e.navigationStart,0));return t}();if(i.value=i.delta=t.responseStart,i.value<0)return;i.entries=[t],e(i)}catch(e){}},"complete"===document.readyState?setTimeout(n,0):addEventListener("pageshow",n)},Object.defineProperty(e,"__esModule",{value:!0})}));
+1
View File
@@ -0,0 +1 @@
var e,t,n,i,a=function(e,t){return{name:e,value:void 0===t?-1:t,delta:0,entries:[],id:"v1-".concat(Date.now(),"-").concat(Math.floor(8999999999999*Math.random())+1e12)}},r=function(e,t){try{if(PerformanceObserver.supportedEntryTypes.includes(e)){if("first-input"===e&&!("PerformanceEventTiming"in self))return;var n=new PerformanceObserver((function(e){return e.getEntries().map(t)}));return n.observe({type:e,buffered:!0}),n}}catch(e){}},o=function(e,t){var n=function n(i){"pagehide"!==i.type&&"hidden"!==document.visibilityState||(e(i),t&&(removeEventListener("visibilitychange",n,!0),removeEventListener("pagehide",n,!0)))};addEventListener("visibilitychange",n,!0),addEventListener("pagehide",n,!0)},c=function(e){addEventListener("pageshow",(function(t){t.persisted&&e(t)}),!0)},u="function"==typeof WeakSet?new WeakSet:new Set,f=function(e,t,n){var i;return function(){t.value>=0&&(n||u.has(t)||"hidden"===document.visibilityState)&&(t.delta=t.value-(i||0),(t.delta||void 0===i)&&(i=t.value,e(t)))}},s=function(e,t){var n,i=a("CLS",0),u=function(e){e.hadRecentInput||(i.value+=e.value,i.entries.push(e),n())},s=r("layout-shift",u);s&&(n=f(e,i,t),o((function(){s.takeRecords().map(u),n()})),c((function(){i=a("CLS",0),n=f(e,i,t)})))},m=-1,p=function(){return"hidden"===document.visibilityState?0:1/0},v=function(){o((function(e){var t=e.timeStamp;m=t}),!0)},d=function(){return m<0&&(m=p(),v(),c((function(){setTimeout((function(){m=p(),v()}),0)}))),{get timeStamp(){return m}}},l=function(e,t){var n,i=d(),o=a("FCP"),s=function(e){"first-contentful-paint"===e.name&&(p&&p.disconnect(),e.startTime<i.timeStamp&&(o.value=e.startTime,o.entries.push(e),u.add(o),n()))},m=performance.getEntriesByName("first-contentful-paint")[0],p=m?null:r("paint",s);(m||p)&&(n=f(e,o,t),m&&s(m),c((function(i){o=a("FCP"),n=f(e,o,t),requestAnimationFrame((function(){requestAnimationFrame((function(){o.value=performance.now()-i.timeStamp,u.add(o),n()}))}))})))},h={passive:!0,capture:!0},S=new Date,y=function(i,a){e||(e=a,t=i,n=new Date,w(removeEventListener),g())},g=function(){if(t>=0&&t<n-S){var a={entryType:"first-input",name:e.type,target:e.target,cancelable:e.cancelable,startTime:e.timeStamp,processingStart:e.timeStamp+t};i.forEach((function(e){e(a)})),i=[]}},E=function(e){if(e.cancelable){var t=(e.timeStamp>1e12?new Date:performance.now())-e.timeStamp;"pointerdown"==e.type?function(e,t){var n=function(){y(e,t),a()},i=function(){a()},a=function(){removeEventListener("pointerup",n,h),removeEventListener("pointercancel",i,h)};addEventListener("pointerup",n,h),addEventListener("pointercancel",i,h)}(t,e):y(t,e)}},w=function(e){["mousedown","keydown","touchstart","pointerdown"].forEach((function(t){return e(t,E,h)}))},L=function(n,s){var m,p=d(),v=a("FID"),l=function(e){e.startTime<p.timeStamp&&(v.value=e.processingStart-e.startTime,v.entries.push(e),u.add(v),m())},h=r("first-input",l);m=f(n,v,s),h&&o((function(){h.takeRecords().map(l),h.disconnect()}),!0),h&&c((function(){var r;v=a("FID"),m=f(n,v,s),i=[],t=-1,e=null,w(addEventListener),r=l,i.push(r),g()}))},T=function(e,t){var n,i=d(),s=a("LCP"),m=function(e){var t=e.startTime;t<i.timeStamp&&(s.value=t,s.entries.push(e)),n()},p=r("largest-contentful-paint",m);if(p){n=f(e,s,t);var v=function(){u.has(s)||(p.takeRecords().map(m),p.disconnect(),u.add(s),n())};["keydown","click"].forEach((function(e){addEventListener(e,v,{once:!0,capture:!0})})),o(v,!0),c((function(i){s=a("LCP"),n=f(e,s,t),requestAnimationFrame((function(){requestAnimationFrame((function(){s.value=performance.now()-i.timeStamp,u.add(s),n()}))}))}))}},b=function(e){var t,n=a("TTFB");t=function(){try{var t=performance.getEntriesByType("navigation")[0]||function(){var e=performance.timing,t={entryType:"navigation",startTime:0};for(var n in e)"navigationStart"!==n&&"toJSON"!==n&&(t[n]=Math.max(e[n]-e.navigationStart,0));return t}();if(n.value=n.delta=t.responseStart,n.value<0)return;n.entries=[t],e(n)}catch(e){}},"complete"===document.readyState?setTimeout(t,0):addEventListener("pageshow",t)};export{s as getCLS,l as getFCP,L as getFID,T as getLCP,b as getTTFB};
+1
View File
@@ -0,0 +1 @@
!function(e,t){"object"==typeof exports&&"undefined"!=typeof module?t(exports):"function"==typeof define&&define.amd?define(["exports"],t):t((e="undefined"!=typeof globalThis?globalThis:e||self).webVitals={})}(this,(function(e){"use strict";var t,n,i,a,r=function(e,t){return{name:e,value:void 0===t?-1:t,delta:0,entries:[],id:"v1-".concat(Date.now(),"-").concat(Math.floor(8999999999999*Math.random())+1e12)}},o=function(e,t){try{if(PerformanceObserver.supportedEntryTypes.includes(e)){if("first-input"===e&&!("PerformanceEventTiming"in self))return;var n=new PerformanceObserver((function(e){return e.getEntries().map(t)}));return n.observe({type:e,buffered:!0}),n}}catch(e){}},u=function(e,t){var n=function n(i){"pagehide"!==i.type&&"hidden"!==document.visibilityState||(e(i),t&&(removeEventListener("visibilitychange",n,!0),removeEventListener("pagehide",n,!0)))};addEventListener("visibilitychange",n,!0),addEventListener("pagehide",n,!0)},c=function(e){addEventListener("pageshow",(function(t){t.persisted&&e(t)}),!0)},f="function"==typeof WeakSet?new WeakSet:new Set,s=function(e,t,n){var i;return function(){t.value>=0&&(n||f.has(t)||"hidden"===document.visibilityState)&&(t.delta=t.value-(i||0),(t.delta||void 0===i)&&(i=t.value,e(t)))}},d=-1,p=function(){return"hidden"===document.visibilityState?0:1/0},m=function(){u((function(e){var t=e.timeStamp;d=t}),!0)},v=function(){return d<0&&(d=p(),m(),c((function(){setTimeout((function(){d=p(),m()}),0)}))),{get timeStamp(){return d}}},l={passive:!0,capture:!0},h=new Date,y=function(e,a){t||(t=a,n=e,i=new Date,E(removeEventListener),g())},g=function(){if(n>=0&&n<i-h){var e={entryType:"first-input",name:t.type,target:t.target,cancelable:t.cancelable,startTime:t.timeStamp,processingStart:t.timeStamp+n};a.forEach((function(t){t(e)})),a=[]}},S=function(e){if(e.cancelable){var t=(e.timeStamp>1e12?new Date:performance.now())-e.timeStamp;"pointerdown"==e.type?function(e,t){var n=function(){y(e,t),a()},i=function(){a()},a=function(){removeEventListener("pointerup",n,l),removeEventListener("pointercancel",i,l)};addEventListener("pointerup",n,l),addEventListener("pointercancel",i,l)}(t,e):y(t,e)}},E=function(e){["mousedown","keydown","touchstart","pointerdown"].forEach((function(t){return e(t,S,l)}))};e.getCLS=function(e,t){var n,i=r("CLS",0),a=function(e){e.hadRecentInput||(i.value+=e.value,i.entries.push(e),n())},f=o("layout-shift",a);f&&(n=s(e,i,t),u((function(){f.takeRecords().map(a),n()})),c((function(){i=r("CLS",0),n=s(e,i,t)})))},e.getFCP=function(e,t){var n,i=v(),a=r("FCP"),u=function(e){"first-contentful-paint"===e.name&&(p&&p.disconnect(),e.startTime<i.timeStamp&&(a.value=e.startTime,a.entries.push(e),f.add(a),n()))},d=performance.getEntriesByName("first-contentful-paint")[0],p=d?null:o("paint",u);(d||p)&&(n=s(e,a,t),d&&u(d),c((function(i){a=r("FCP"),n=s(e,a,t),requestAnimationFrame((function(){requestAnimationFrame((function(){a.value=performance.now()-i.timeStamp,f.add(a),n()}))}))})))},e.getFID=function(e,i){var d,p=v(),m=r("FID"),l=function(e){e.startTime<p.timeStamp&&(m.value=e.processingStart-e.startTime,m.entries.push(e),f.add(m),d())},h=o("first-input",l);d=s(e,m,i),h&&u((function(){h.takeRecords().map(l),h.disconnect()}),!0),h&&c((function(){var o;m=r("FID"),d=s(e,m,i),a=[],n=-1,t=null,E(addEventListener),o=l,a.push(o),g()}))},e.getLCP=function(e,t){var n,i=v(),a=r("LCP"),d=function(e){var t=e.startTime;t<i.timeStamp&&(a.value=t,a.entries.push(e)),n()},p=o("largest-contentful-paint",d);if(p){n=s(e,a,t);var m=function(){f.has(a)||(p.takeRecords().map(d),p.disconnect(),f.add(a),n())};["keydown","click"].forEach((function(e){addEventListener(e,m,{once:!0,capture:!0})})),u(m,!0),c((function(i){a=r("LCP"),n=s(e,a,t),requestAnimationFrame((function(){requestAnimationFrame((function(){a.value=performance.now()-i.timeStamp,f.add(a),n()}))}))}))}},e.getTTFB=function(e){var t,n=r("TTFB");t=function(){try{var t=performance.getEntriesByType("navigation")[0]||function(){var e=performance.timing,t={entryType:"navigation",startTime:0};for(var n in e)"navigationStart"!==n&&"toJSON"!==n&&(t[n]=Math.max(e[n]-e.navigationStart,0));return t}();if(n.value=n.delta=t.responseStart,n.value<0)return;n.entries=[t],e(n)}catch(e){}},"complete"===document.readyState?setTimeout(t,0):addEventListener("pageshow",t)},Object.defineProperty(e,"__esModule",{value:!0})}));