Skip to content

Commit

Permalink
Export metric thresholds, add MetricThreshold type
Browse files Browse the repository at this point in the history
  • Loading branch information
robatron committed Feb 26, 2023
1 parent 9f11c4c commit cb26090
Show file tree
Hide file tree
Showing 10 changed files with 103 additions and 45 deletions.
14 changes: 14 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -761,6 +761,20 @@ Metric-specific subclasses:
- [`LCPMetricWithAttribution`](/src/types/lcp.ts#:~:text=interface%20LCPMetricWithAttribution)
- [`TTFBMetricWithAttribution`](/src/types/ttfb.ts#:~:text=interface%20TTFBMetricWithAttribution)

#### `MetricThresholds`

```ts
/**
* The ranges defining a metric's "good", "needs improvement", and "poor"
* thresholds:
*
* - Metric values ≦ [0] are "good"
* - Metric values > [0] and ≦ [1] are "needs improvement"
* - Metric values > [1] are "poor".
*/
type MetricThresholds = [number, number];
```

#### `ReportCallback`

```ts
Expand Down
12 changes: 6 additions & 6 deletions src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -14,12 +14,12 @@
* limitations under the License.
*/

export {onCLS} from './onCLS.js';
export {onFCP} from './onFCP.js';
export {onFID} from './onFID.js';
export {onINP} from './onINP.js';
export {onLCP} from './onLCP.js';
export {onTTFB} from './onTTFB.js';
export {onCLS, CLSThresholds} from './onCLS.js';
export {onFCP, FCPThresholds} from './onFCP.js';
export {onFID, FIDThresholds} from './onFID.js';
export {onINP, INPThresholds} from './onINP.js';
export {onLCP, LCPThresholds} from './onLCP.js';
export {onTTFB, TTFBThresholds} from './onTTFB.js';

export * from './deprecated.js';
export * from './types.js';
9 changes: 6 additions & 3 deletions src/lib/bindReporter.ts
Original file line number Diff line number Diff line change
Expand Up @@ -14,9 +14,12 @@
* limitations under the License.
*/

import {Metric, ReportCallback} from '../types.js';
import {Metric, MetricThresholds, ReportCallback} from '../types.js';

const getRating = (value: number, thresholds: number[]) => {
const getRating = (
value: number,
thresholds: MetricThresholds
): Metric['rating'] => {
if (value > thresholds[1]) {
return 'poor';
}
Expand All @@ -29,7 +32,7 @@ const getRating = (value: number, thresholds: number[]) => {
export const bindReporter = (
callback: ReportCallback,
metric: Metric,
thresholds: number[],
thresholds: MetricThresholds,
reportAllChanges?: boolean
) => {
let prevValue: number;
Expand Down
17 changes: 11 additions & 6 deletions src/onCLS.ts
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,15 @@ import {doubleRAF} from './lib/doubleRAF.js';
import {onHidden} from './lib/onHidden.js';
import {runOnce} from './lib/runOnce.js';
import {onFCP} from './onFCP.js';
import {CLSMetric, CLSReportCallback, ReportOpts} from './types.js';
import {
CLSMetric,
CLSReportCallback,
MetricThresholds,
ReportOpts,
} from './types.js';

/** Thresholds for CLS. See https://web.dev/cls/#what-is-a-good-cls-score */
export const CLSThresholds: MetricThresholds = [0.1, 0.25];

/**
* Calculates the [CLS](https://web.dev/cls/) value for the current page and
Expand Down Expand Up @@ -53,9 +61,6 @@ export const onCLS = (onReport: CLSReportCallback, opts?: ReportOpts) => {
// Note: this is done to match the current behavior of CrUX.
onFCP(
runOnce(() => {
// https://web.dev/cls/#what-is-a-good-cls-score
const thresholds = [0.1, 0.25];

let metric = initMetric('CLS', 0);
let report: ReturnType<typeof bindReporter>;

Expand Down Expand Up @@ -102,7 +107,7 @@ export const onCLS = (onReport: CLSReportCallback, opts?: ReportOpts) => {
report = bindReporter(
onReport,
metric,
thresholds,
CLSThresholds,
opts!.reportAllChanges
);

Expand All @@ -119,7 +124,7 @@ export const onCLS = (onReport: CLSReportCallback, opts?: ReportOpts) => {
report = bindReporter(
onReport,
metric,
thresholds,
CLSThresholds,
opts!.reportAllChanges
);

Expand Down
17 changes: 11 additions & 6 deletions src/onFCP.ts
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,15 @@ import {getVisibilityWatcher} from './lib/getVisibilityWatcher.js';
import {initMetric} from './lib/initMetric.js';
import {observe} from './lib/observe.js';
import {whenActivated} from './lib/whenActivated.js';
import {FCPMetric, FCPReportCallback, ReportOpts} from './types.js';
import {
FCPMetric,
FCPReportCallback,
MetricThresholds,
ReportOpts,
} from './types.js';

/** Thresholds for FCP. See https://web.dev/fcp/#what-is-a-good-fcp-score */
export const FCPThresholds: MetricThresholds = [1800, 3000];

/**
* Calculates the [FCP](https://web.dev/fcp/) value for the current page and
Expand All @@ -35,9 +43,6 @@ export const onFCP = (onReport: FCPReportCallback, opts?: ReportOpts) => {
opts = opts || {};

whenActivated(() => {
// https://web.dev/fcp/#what-is-a-good-fcp-score
const thresholds = [1800, 3000];

const visibilityWatcher = getVisibilityWatcher();
let metric = initMetric('FCP');
let report: ReturnType<typeof bindReporter>;
Expand Down Expand Up @@ -67,7 +72,7 @@ export const onFCP = (onReport: FCPReportCallback, opts?: ReportOpts) => {
report = bindReporter(
onReport,
metric,
thresholds,
FCPThresholds,
opts!.reportAllChanges
);

Expand All @@ -78,7 +83,7 @@ export const onFCP = (onReport: FCPReportCallback, opts?: ReportOpts) => {
report = bindReporter(
onReport,
metric,
thresholds,
FCPThresholds,
opts!.reportAllChanges
);

Expand Down
18 changes: 12 additions & 6 deletions src/onFID.ts
Original file line number Diff line number Diff line change
Expand Up @@ -29,10 +29,14 @@ import {whenActivated} from './lib/whenActivated.js';
import {
FIDMetric,
FirstInputPolyfillCallback,
MetricThresholds,
ReportCallback,
ReportOpts,
} from './types.js';

/** Thresholds for FID. See https://web.dev/fid/#what-is-a-good-fid-score */
export const FIDThresholds: MetricThresholds = [100, 300];

/**
* Calculates the [FID](https://web.dev/fid/) value for the current page and
* calls the `callback` function once the value is ready, along with the
Expand All @@ -47,9 +51,6 @@ export const onFID = (onReport: ReportCallback, opts?: ReportOpts) => {
opts = opts || {};

whenActivated(() => {
// https://web.dev/fid/#what-is-a-good-fid-score
const thresholds = [100, 300];

const visibilityWatcher = getVisibilityWatcher();
let metric = initMetric('FID');
let report: ReturnType<typeof bindReporter>;
Expand All @@ -68,7 +69,12 @@ export const onFID = (onReport: ReportCallback, opts?: ReportOpts) => {
};

const po = observe('first-input', handleEntries);
report = bindReporter(onReport, metric, thresholds, opts!.reportAllChanges);
report = bindReporter(
onReport,
metric,
FIDThresholds,
opts!.reportAllChanges
);

if (po) {
onHidden(
Expand All @@ -95,7 +101,7 @@ export const onFID = (onReport: ReportCallback, opts?: ReportOpts) => {
report = bindReporter(
onReport,
metric,
thresholds,
FIDThresholds,
opts!.reportAllChanges
);

Expand All @@ -112,7 +118,7 @@ export const onFID = (onReport: ReportCallback, opts?: ReportOpts) => {
report = bindReporter(
onReport,
metric,
thresholds,
FIDThresholds,
opts!.reportAllChanges
);

Expand Down
22 changes: 16 additions & 6 deletions src/onINP.ts
Original file line number Diff line number Diff line change
Expand Up @@ -24,14 +24,22 @@ import {
initInteractionCountPolyfill,
} from './lib/polyfills/interactionCountPolyfill.js';
import {whenActivated} from './lib/whenActivated.js';
import {INPMetric, ReportCallback, ReportOpts} from './types.js';
import {
INPMetric,
MetricThresholds,
ReportCallback,
ReportOpts,
} from './types.js';

interface Interaction {
id: number;
latency: number;
entries: PerformanceEventTiming[];
}

/** Thresholds for INP. See https://web.dev/inp/#what-is-a-good-inp-score */
export const INPThresholds: MetricThresholds = [200, 500];

// Used to store the interaction count after a bfcache restore, since p98
// interaction latencies should only consider the current navigation.
let prevInteractionCount = 0;
Expand Down Expand Up @@ -146,9 +154,6 @@ export const onINP = (onReport: ReportCallback, opts?: ReportOpts) => {
opts = opts || {};

whenActivated(() => {
// https://web.dev/inp/#what-is-a-good-inp-score
const thresholds = [200, 500];

// TODO(philipwalton): remove once the polyfill is no longer needed.
initInteractionCountPolyfill();

Expand Down Expand Up @@ -205,7 +210,12 @@ export const onINP = (onReport: ReportCallback, opts?: ReportOpts) => {
durationThreshold: opts!.durationThreshold || 40,
} as PerformanceObserverInit);

report = bindReporter(onReport, metric, thresholds, opts!.reportAllChanges);
report = bindReporter(
onReport,
metric,
INPThresholds,
opts!.reportAllChanges
);

if (po) {
// Also observe entries of type `first-input`. This is useful in cases
Expand Down Expand Up @@ -237,7 +247,7 @@ export const onINP = (onReport: ReportCallback, opts?: ReportOpts) => {
report = bindReporter(
onReport,
metric,
thresholds,
INPThresholds,
opts!.reportAllChanges
);
});
Expand Down
17 changes: 11 additions & 6 deletions src/onLCP.ts
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,15 @@ import {observe} from './lib/observe.js';
import {onHidden} from './lib/onHidden.js';
import {runOnce} from './lib/runOnce.js';
import {whenActivated} from './lib/whenActivated.js';
import {LCPMetric, ReportCallback, ReportOpts} from './types.js';
import {
LCPMetric,
MetricThresholds,
ReportCallback,
ReportOpts,
} from './types.js';

/** Thresholds for LCP. See https://web.dev/lcp/#what-is-a-good-lcp-score */
export const LCPThresholds: MetricThresholds = [2500, 4000];

const reportedMetricIDs: Record<string, boolean> = {};

Expand All @@ -44,9 +52,6 @@ export const onLCP = (onReport: ReportCallback, opts?: ReportOpts) => {
opts = opts || {};

whenActivated(() => {
// https://web.dev/lcp/#what-is-a-good-lcp-score
const thresholds = [2500, 4000];

const visibilityWatcher = getVisibilityWatcher();
let metric = initMetric('LCP');
let report: ReturnType<typeof bindReporter>;
Expand Down Expand Up @@ -77,7 +82,7 @@ export const onLCP = (onReport: ReportCallback, opts?: ReportOpts) => {
report = bindReporter(
onReport,
metric,
thresholds,
LCPThresholds,
opts!.reportAllChanges
);

Expand Down Expand Up @@ -106,7 +111,7 @@ export const onLCP = (onReport: ReportCallback, opts?: ReportOpts) => {
report = bindReporter(
onReport,
metric,
thresholds,
LCPThresholds,
opts!.reportAllChanges
);

Expand Down
12 changes: 6 additions & 6 deletions src/onTTFB.ts
Original file line number Diff line number Diff line change
Expand Up @@ -18,10 +18,13 @@ import {bindReporter} from './lib/bindReporter.js';
import {initMetric} from './lib/initMetric.js';
import {onBFCacheRestore} from './lib/bfcache.js';
import {getNavigationEntry} from './lib/getNavigationEntry.js';
import {ReportCallback, ReportOpts} from './types.js';
import {MetricThresholds, ReportCallback, ReportOpts} from './types.js';
import {getActivationStart} from './lib/getActivationStart.js';
import {whenActivated} from './lib/whenActivated.js';

/** Thresholds for TTFB. See https://web.dev/ttfb/#what-is-a-good-ttfb-score */
export const TTFBThresholds: MetricThresholds = [800, 1800];

/**
* Runs in the next task after the page is done loading and/or prerendering.
* @param callback
Expand Down Expand Up @@ -56,14 +59,11 @@ export const onTTFB = (onReport: ReportCallback, opts?: ReportOpts) => {
// Set defaults
opts = opts || {};

// https://web.dev/ttfb/#what-is-a-good-ttfb-score
const thresholds = [800, 1800];

let metric = initMetric('TTFB');
let report = bindReporter(
onReport,
metric,
thresholds,
TTFBThresholds,
opts.reportAllChanges
);

Expand Down Expand Up @@ -97,7 +97,7 @@ export const onTTFB = (onReport: ReportCallback, opts?: ReportOpts) => {
report = bindReporter(
onReport,
metric,
thresholds,
TTFBThresholds,
opts!.reportAllChanges
);

Expand Down
10 changes: 10 additions & 0 deletions src/types/base.ts
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,16 @@ import {
NavigationTimingPolyfillEntry,
} from './polyfills.js';

/**
* The ranges defining a metric's "good", "needs improvement", and "poor"
* thresholds:
*
* - Metric values ≦ [0] are "good"
* - Metric values > [0] and ≦ [1] are "needs improvement"
* - Metric values > [1] are "poor".
*/
export type MetricThresholds = [number, number];

export interface Metric {
/**
* The name of the metric (in acronym form).
Expand Down

0 comments on commit cb26090

Please sign in to comment.