diff --git a/README.md b/README.md index 55db7669..5f01f854 100644 --- a/README.md +++ b/README.md @@ -15,7 +15,6 @@ - [Batch multiple reports together](#batch-multiple-reports-together) - [Build options](#build-options) - [Which build is right for you?](#which-build-is-right-for-you) - - [How the polyfill works](#how-the-polyfill-works) - [API](#api) - [Types](#types) - [Functions](#functions) @@ -36,14 +35,14 @@ The library supports all of the [Core Web Vitals](https://web.dev/articles/vital ### Core Web Vitals - [Cumulative Layout Shift (CLS)](https://web.dev/articles/cls) -- [First Input Delay (FID)](https://web.dev/articles/fid) +- [Interaction to Next Paint (INP)](https://web.dev/articles/inp) - [Largest Contentful Paint (LCP)](https://web.dev/articles/lcp) ### Other metrics -- [Interaction to next Paint (INP)](https://web.dev/articles/inp) - [First Contentful Paint (FCP)](https://web.dev/articles/fcp) - [Time to First Byte (TTFB)](https://web.dev/articles/ttfb) +- [First Input Delay (FID)](https://web.dev/articles/fid) _Deprecated and will be removed in next major release_ @@ -75,10 +74,10 @@ For details on the difference between the builds, see - -**3. The "base+polyfill" build** - -_**⚠️ Warning ⚠️** the "base+polyfill" build is deprecated. See [#238](https://github.com/GoogleChrome/web-vitals/issues/238) for details._ - -Loading the "base+polyfill" build is a two-step process: - -First, in your application code, import the "base" build rather than the "standard" build. To do this, change any `import` statements that reference `web-vitals` to `web-vitals/base`: - -```diff -- import {onLCP, onFID, onCLS} from 'web-vitals'; -+ import {onLCP, onFID, onCLS} from 'web-vitals/base'; -``` - -Then, inline the code from `dist/polyfill.js` into the `` of your pages. This step is important since the "base" build will error if the polyfill code has not been added. - -```html - - - - - - - ... - - -``` - -It's important that the code is inlined directly into the HTML. _Do not link to an external script file, as that will negatively affect performance:_ - -```html - - - - - -``` - -Also note that the code _must_ go in the `` of your pages in order to work. See [how the polyfill works](#how-the-polyfill-works) for more details. - -_**Tip:** while it's certainly possible to inline the code in `dist/polyfill.js` by copy and pasting it directly into your templates, it's better to automate this process in a build step—otherwise you risk the "base" and the "polyfill" scripts getting out of sync when new versions are released._ - ### From a CDN @@ -167,10 +119,10 @@ _**Important!** The [unpkg.com](https://unpkg.com) CDN is shown here for example ```html ``` @@ -181,12 +133,12 @@ _**Important!** The [unpkg.com](https://unpkg.com) CDN is shown here for example ``` @@ -218,12 +170,12 @@ _**Important!** The [unpkg.com](https://unpkg.com) CDN is shown here for example (function () { var script = document.createElement('script'); script.src = - 'https://unpkg.com/web-vitals@3/dist/web-vitals.attribution.iife.js'; + 'https://unpkg.com/web-vitals@4/dist/web-vitals.attribution.iife.js'; script.onload = function () { // When loading `web-vitals` using a classic script, all the public // methods can be found on the `webVitals` global namespace. webVitals.onCLS(console.log); - webVitals.onFID(console.log); + webVitals.onINP(console.log); webVitals.onLCP(console.log); }; document.head.appendChild(script); @@ -242,10 +194,10 @@ The following example measures each of the Core Web Vitals metrics and logs the _(The examples below import the "standard" build, but they will work with the "attribution" build as well.)_ ```js -import {onCLS, onFID, onLCP} from 'web-vitals'; +import {onCLS, onINP, onLCP} from 'web-vitals'; onCLS(console.log); -onFID(console.log); +onINP(console.log); onLCP(console.log); ``` @@ -261,7 +213,7 @@ In other cases, a metric callback may be called more than once: - CLS and INP should be reported any time the [page's `visibilityState` changes to hidden](https://developer.chrome.com/blog/page-lifecycle-api/#advice-hidden). - All metrics are reported again (with the above exceptions) after a page is restored from the [back/forward cache](https://web.dev/articles/bfcache). -_**Warning:** do not call any of the Web Vitals functions (e.g. `onCLS()`, `onFID()`, `onLCP()`) more than once per page load. Each of these functions creates a `PerformanceObserver` instance and registers event listeners for the lifetime of the page. While the overhead of calling these functions once is negligible, calling them repeatedly on the same page may eventually result in a memory leak._ +_**Warning:** do not call any of the Web Vitals functions (e.g. `onCLS()`, `onINP()`, `onLCP()`) more than once per page load. Each of these functions creates a `PerformanceObserver` instance and registers event listeners for the lifetime of the page. While the overhead of calling these functions once is negligible, calling them repeatedly on the same page may eventually result in a memory leak._ ### Report the value on every change @@ -287,14 +239,14 @@ Other analytics providers, however, do not allow this, so instead of reporting t The following example shows how to use the `id` and `delta` properties: ```js -import {onCLS, onFID, onLCP} from 'web-vitals'; +import {onCLS, onINP, onLCP} from 'web-vitals'; function logDelta({name, id, delta}) { console.log(`${name} matching ID ${id} changed by ${delta}`); } onCLS(logDelta); -onFID(logDelta); +onINP(logDelta); onLCP(logDelta); ``` @@ -309,7 +261,7 @@ The following example measures each of the Core Web Vitals metrics and reports t The `sendToAnalytics()` function uses the [`navigator.sendBeacon()`](https://developer.mozilla.org/docs/Web/API/Navigator/sendBeacon) method (if available), but falls back to the [`fetch()`](https://developer.mozilla.org/docs/Web/API/Fetch_API) API when not. ```js -import {onCLS, onFID, onLCP} from 'web-vitals'; +import {onCLS, onINP, onLCP} from 'web-vitals'; function sendToAnalytics(metric) { // Replace with whatever serialization method you prefer. @@ -322,7 +274,7 @@ function sendToAnalytics(metric) { } onCLS(sendToAnalytics); -onFID(sendToAnalytics); +onINP(sendToAnalytics); onLCP(sendToAnalytics); ``` @@ -333,7 +285,7 @@ Google Analytics does not support reporting metric distributions in any of its b [Google Analytics 4](https://support.google.com/analytics/answer/10089681) introduces a new Event model allowing custom parameters instead of a fixed category, action, and label. It also supports non-integer values, making it easier to measure Web Vitals metrics compared to previous versions. ```js -import {onCLS, onFID, onLCP} from 'web-vitals'; +import {onCLS, onINP, onLCP} from 'web-vitals'; function sendToGoogleAnalytics({name, delta, value, id}) { // Assumes the global `gtag()` function exists, see: @@ -355,7 +307,7 @@ function sendToGoogleAnalytics({name, delta, value, id}) { } onCLS(sendToGoogleAnalytics); -onFID(sendToGoogleAnalytics); +onINP(sendToGoogleAnalytics); onLCP(sendToGoogleAnalytics); ``` @@ -375,7 +327,7 @@ When using the [attribution build](#attribution-build), you can send additional This example sends an additional `debug_target` param to Google Analytics, corresponding to the element most associated with each metric. ```js -import {onCLS, onFID, onLCP} from 'web-vitals/attribution'; +import {onCLS, onINP, onLCP} from 'web-vitals/attribution'; function sendToGoogleAnalytics({name, delta, value, id, attribution}) { const eventParams = { @@ -391,7 +343,7 @@ function sendToGoogleAnalytics({name, delta, value, id, attribution}) { case 'CLS': eventParams.debug_target = attribution.largestShiftTarget; break; - case 'FID': + case 'INP': eventParams.debug_target = attribution.eventTarget; break; case 'LCP': @@ -405,7 +357,7 @@ function sendToGoogleAnalytics({name, delta, value, id, attribution}) { } onCLS(sendToGoogleAnalytics); -onFID(sendToGoogleAnalytics); +onINP(sendToGoogleAnalytics); onLCP(sendToGoogleAnalytics); ``` @@ -422,7 +374,7 @@ However, since not all Web Vitals metrics become available at the same time, and Instead, you should keep a queue of all metrics that were reported and flush the queue whenever the page is backgrounded or unloaded: ```js -import {onCLS, onFID, onLCP} from 'web-vitals'; +import {onCLS, onINP, onLCP} from 'web-vitals'; const queue = new Set(); function addToQueue(metric) { @@ -444,7 +396,7 @@ function flushQueue() { } onCLS(addToQueue); -onFID(addToQueue); +onINP(addToQueue); onLCP(addToQueue); // Report all available metrics whenever the page is backgrounded or unloaded. @@ -466,7 +418,7 @@ _**Note:** see [the Page Lifecycle guide](https://developers.google.com/web/upda ## Build options -The `web-vitals` package includes builds for the "standard", "attribution", and "base+polyfill" ([deprecated](https://github.com/GoogleChrome/web-vitals/issues/238)) builds, as well as different formats of each to allow developers to choose the format that best meets their needs or integrates with their architecture. +The `web-vitals` package includes both "standard" and "attribution" builds, as well as different formats of each to allow developers to choose the format that best meets their needs or integrates with their architecture. The following table lists all the builds distributed with the `web-vitals` package on npm. @@ -522,41 +474,6 @@ The following table lists all the builds distributed with the `web-vitals` packa An IIFE version of the web-vitals.attribution.js build (exposed on the window.webVitals.* namespace). - - web-vitals.base.js - -- - -

This build has been deprecated.

-

An ES module bundle containing just the "base" part of the "base+polyfill" version.

- Use this bundle if (and only if) you've also added the polyfill.js script to the <head> of your pages. See how to use the polyfill for more details. - - - - web-vitals.base.umd.cjs - -- - -

This build has been deprecated.

-

A UMD version of the web-vitals.base.js bundle (exposed on the window.webVitals.* namespace).

- - - - - web-vitals.base.iife.js - -- - -

This build has been deprecated.

-

An IIFE version of the web-vitals.base.js bundle (exposed on the window.webVitals.* namespace).

- - - - polyfill.js - -- - -

This build has been deprecated.

-

The "polyfill" part of the "base+polyfill" version. This script should be used with either web-vitals.base.js, web-vitals.base.umd.cjs, or web-vitals.base.iife.js (it will not work with any script that doesn't have "base" in the filename).

- See how to use the polyfill for more details. - - @@ -569,16 +486,6 @@ However, if you'd lke to collect additional debug information to help you diagno For guidance on how to collect and use real-user data to debug performance issues, see [Debug performance in the field](https://web.dev/debug-performance-in-the-field/). -### How the polyfill works - -_**⚠️ Warning ⚠️** the "base+polyfill" build is deprecated. See [#238](https://github.com/GoogleChrome/web-vitals/issues/238) for details._ - -The `polyfill.js` script adds event listeners (to track FID cross-browser), and it records initial page visibility state as well as the timestamp of the first visibility change to hidden (to improve the accuracy of CLS, FCP, LCP, and FID). It also polyfills the [Navigation Timing API Level 2](https://www.w3.org/TR/navigation-timing-2/) in browsers that only support the original (now deprecated) [Navigation Timing API](https://www.w3.org/TR/navigation-timing/). - -In order for the polyfill to work properly, the script must be the first script added to the page, and it must run before the browser renders any content to the screen. This is why it needs to be added to the `` of the document. - -The "standard" build of the `web-vitals` library includes some of the same logic found in `polyfill.js`. To avoid duplicating that code when using the "base+polyfill" build, the `web-vitals.base.js` bundle does not include any polyfill logic, instead it coordinates with the code in `polyfill.js`, which is why the two scripts must be used together. - ## API ### Types: @@ -625,12 +532,7 @@ interface Metric { * The array may also be empty if the metric value was not based on any * entries (e.g. a CLS value of 0 given no layout shifts). */ - entries: ( - | PerformanceEntry - | LayoutShift - | FirstInputPolyfillEntry - | NavigationTimingPolyfillEntry - )[]; + entries: (PerformanceEntry | LayoutShift)[]; /** * The type of navigation. @@ -759,56 +661,6 @@ type LoadState = | 'complete'; ``` -#### `FirstInputPolyfillEntry` - -If using the "base+polyfill" build (and if the browser doesn't natively support the Event Timing API), the `metric.entries` reported by `onFID()` will contain an object that polyfills the `PerformanceEventTiming` entry: - -```ts -type FirstInputPolyfillEntry = Omit< - PerformanceEventTiming, - 'processingEnd' | 'toJSON' ->; -``` - -#### `FirstInputPolyfillCallback` - -```ts -interface FirstInputPolyfillCallback { - (entry: FirstInputPolyfillEntry): void; -} -``` - -#### `NavigationTimingPolyfillEntry` - -If using the "base+polyfill" build (and if the browser doesn't support the [Navigation Timing API Level 2](https://www.w3.org/TR/navigation-timing-2/) interface), the `metric.entries` reported by `onTTFB()` will contain an object that polyfills the `PerformanceNavigationTiming` entry using timings from the legacy `performance.timing` interface: - -```ts -type NavigationTimingPolyfillEntry = Omit< - PerformanceNavigationTiming, - | 'initiatorType' - | 'nextHopProtocol' - | 'redirectCount' - | 'transferSize' - | 'encodedBodySize' - | 'decodedBodySize' - | 'type' -> & { - type: PerformanceNavigationTiming['type']; -}; -``` - -#### `WebVitalsGlobal` - -If using the "base+polyfill" build, the `polyfill.js` script creates the global `webVitals` namespace matching the following interface: - -```ts -interface WebVitalsGlobal { - firstInputPolyfill: (onFirstInput: FirstInputPolyfillCallback) => void; - resetFirstInputPolyfill: () => void; - firstHiddenTime: number; -} -``` - ### Functions: #### `onCLS()` @@ -833,6 +685,8 @@ Calculates the [FCP](https://web.dev/articles/fcp) value for the current page an #### `onFID()` +_Deprecated and will be removed in next major release_ + ```ts type onFID = (callback: FIDReportCallback, opts?: ReportOpts) => void; ``` @@ -898,10 +752,10 @@ The thresholds of each metric's "good", "needs improvement", and "poor" ratings Example: ```ts -import {CLSThresholds, FIDThresholds, LCPThresholds} from 'web-vitals'; +import {CLSThresholds, INPThresholds, LCPThresholds} from 'web-vitals'; console.log(CLSThresholds); // [ 0.1, 0.25 ] -console.log(FIDThresholds); // [ 100, 300 ] +console.log(INPThresholds); // [ 200, 500 ] console.log(LCPThresholds); // [ 2500, 4000 ] ``` @@ -982,7 +836,7 @@ interface FCPAttribution { * general page load issues. This can be used to access `serverTiming` for example: * navigationEntry?.serverTiming */ - navigationEntry?: PerformanceNavigationTiming | NavigationTimingPolyfillEntry; + navigationEntry?: PerformanceNavigationTiming; } ``` @@ -1005,10 +859,9 @@ interface FIDAttribution { */ eventType: string; /** - * The `PerformanceEventTiming` entry corresponding to FID (or the - * polyfill entry in browsers that don't support Event Timing). + * The `PerformanceEventTiming` entry corresponding to FID. */ - eventEntry: PerformanceEventTiming | FirstInputPolyfillEntry; + eventEntry: PerformanceEventTiming; /** * The loading state of the document at the time when the first interaction * occurred (see `LoadState` for details). If the first interaction occurred @@ -1094,7 +947,7 @@ interface LCPAttribution { * general page load issues. This can be used to access `serverTiming` for example: * navigationEntry?.serverTiming */ - navigationEntry?: PerformanceNavigationTiming | NavigationTimingPolyfillEntry; + navigationEntry?: PerformanceNavigationTiming; /** * The `resource` entry for the LCP resource (if applicable), which is useful * for diagnosing resource load issues. @@ -1136,7 +989,7 @@ interface TTFBAttribution { * general page load issues. This can be used to access `serverTiming` for example: * navigationEntry?.serverTiming */ - navigationEntry?: PerformanceNavigationTiming | NavigationTimingPolyfillEntry; + navigationEntry?: PerformanceNavigationTiming; } ``` @@ -1148,10 +1001,10 @@ Browser support for each function is as follows: - `onCLS()`: Chromium - `onFCP()`: Chromium, Firefox, Safari 14.1+ -- `onFID()`: Chromium, Firefox _(with [polyfill](#how-to-use-the-polyfill): Safari, Internet Explorer)_ +- `onFID()`: Chromium, Firefox _(Deprecated)_ - `onINP()`: Chromium - `onLCP()`: Chromium -- `onTTFB()`: Chromium, Firefox, Safari 15+ _(with [polyfill](#how-to-use-the-polyfill): Safari 8+, Internet Explorer)_ +- `onTTFB()`: Chromium, Firefox, Safari 15+ ## Limitations diff --git a/attribution.d.ts b/attribution.d.ts index 1cdb5204..eef78ebc 100644 --- a/attribution.d.ts +++ b/attribution.d.ts @@ -13,4 +13,4 @@ limitations under the License. */ -export * from './dist/modules/attribution.js'; +export * from './dist/modules/attribution/index.js'; diff --git a/base.d.ts b/base.d.ts deleted file mode 100644 index f15dc001..00000000 --- a/base.d.ts +++ /dev/null @@ -1,65 +0,0 @@ -/* - Copyright 2022 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 { - /** - * @deprecated The "base+polyfill" build is deprecated. - * See: https://bit.ly/3aqzsGm - */ - onCLS, -} from './dist/modules/index.js'; - -export { - /** - * @deprecated The "base+polyfill" build is deprecated. - * See: https://bit.ly/3aqzsGm - */ - onFCP, -} from './dist/modules/index.js'; - -export { - /** - * @deprecated The "base+polyfill" build is deprecated. - * See: https://bit.ly/3aqzsGm - */ - onFID, -} from './dist/modules/index.js'; - -export { - /** - * @deprecated The "base+polyfill" build is deprecated. - * See: https://bit.ly/3aqzsGm - */ - onINP, -} from './dist/modules/index.js'; - -export { - /** - * @deprecated The "base+polyfill" build is deprecated. - * See: https://bit.ly/3aqzsGm - */ - onLCP, -} from './dist/modules/index.js'; - -export { - /** - * @deprecated The "base+polyfill" build is deprecated. - * See: https://bit.ly/3aqzsGm - */ - onTTFB, -} from './dist/modules/index.js'; - -export * from './dist/modules/deprecated.js'; -export * from './dist/modules/types.js'; diff --git a/base.js b/base.js deleted file mode 100644 index ae7bfd33..00000000 --- a/base.js +++ /dev/null @@ -1,18 +0,0 @@ -/* - Copyright 2022 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. -*/ - -// Creates the `web-vitals/base` import in node-based bundlers. -// This will not be needed when export maps are widely supported. -export * from './dist/web-vitals.base.js'; diff --git a/package.json b/package.json index 4080f036..98a61489 100644 --- a/package.json +++ b/package.json @@ -13,23 +13,13 @@ "require": "./dist/web-vitals.umd.cjs", "default": "./dist/web-vitals.js" }, - "./base": { - "types": "./base.d.ts", - "require": "./dist/web-vitals.base.umd.cjs", - "default": "./dist/web-vitals.base.js" - }, - "./base.js": { - "types": "./base.d.ts", - "require": "./dist/web-vitals.base.umd.cjs", - "default": "./dist/web-vitals.base.js" - }, "./attribution": { - "types": "./dist/modules/attribution.d.ts", + "types": "./dist/modules/attribution/index.d.ts", "require": "./dist/web-vitals.attribution.umd.cjs", "default": "./dist/web-vitals.attribution.js" }, "./attribution.js": { - "types": "./dist/modules/attribution.d.ts", + "types": "./dist/modules/attribution/index.d.ts", "require": "./dist/web-vitals.attribution.umd.cjs", "default": "./dist/web-vitals.attribution.js" }, @@ -85,8 +75,6 @@ "files": [ "attribution.js", "attribution.d.ts", - "base.js", - "base.d.ts", "dist", "src" ], diff --git a/rollup.config.js b/rollup.config.js index d1533d06..1d1e0426 100644 --- a/rollup.config.js +++ b/rollup.config.js @@ -17,7 +17,7 @@ import babel from '@rollup/plugin-babel'; import replace from '@rollup/plugin-replace'; import terser from '@rollup/plugin-terser'; -const configurePlugins = ({module, polyfill = false}) => { +const configurePlugins = ({module}) => { return [ babel({ babelHelpers: 'bundled', @@ -37,12 +37,6 @@ const configurePlugins = ({module, polyfill = false}) => { mangle: true, compress: true, }), - replace({ - values: { - 'window.__WEB_VITALS_POLYFILL__': polyfill, - }, - preventAssignment: true, - }), ]; }; @@ -53,7 +47,7 @@ const configs = [ format: 'esm', file: './dist/web-vitals.js', }, - plugins: configurePlugins({module: true, polyfill: false}), + plugins: configurePlugins({module: true}), }, { input: 'dist/modules/index.js', @@ -62,7 +56,7 @@ const configs = [ file: `./dist/web-vitals.umd.cjs`, name: 'webVitals', }, - plugins: configurePlugins({module: false, polyfill: false}), + plugins: configurePlugins({module: false}), }, { input: 'dist/modules/index.js', @@ -71,71 +65,33 @@ const configs = [ file: './dist/web-vitals.iife.js', name: 'webVitals', }, - plugins: configurePlugins({module: false, polyfill: false}), - }, - { - input: 'dist/modules/index.js', - output: { - format: 'esm', - file: './dist/web-vitals.base.js', - }, - plugins: configurePlugins({module: true, polyfill: true}), - }, - { - input: 'dist/modules/index.js', - output: { - format: 'umd', - file: `./dist/web-vitals.base.umd.cjs`, - name: 'webVitals', - extend: true, - }, - plugins: configurePlugins({module: false, polyfill: true}), - }, - { - input: 'dist/modules/index.js', - output: { - format: 'iife', - file: `./dist/web-vitals.base.iife.js`, - name: 'webVitals', - extend: true, - }, - plugins: configurePlugins({module: false, polyfill: true}), - }, - { - input: 'dist/modules/polyfill.js', - output: { - format: 'iife', - file: './dist/polyfill.js', - name: 'webVitals', - strict: false, - }, plugins: configurePlugins({module: false}), }, { - input: 'dist/modules/attribution.js', + input: 'dist/modules/attribution/index.js', output: { format: 'esm', file: './dist/web-vitals.attribution.js', }, - plugins: configurePlugins({module: true, polyfill: false}), + plugins: configurePlugins({module: true}), }, { - input: 'dist/modules/attribution.js', + input: 'dist/modules/attribution/index.js', output: { format: 'umd', file: `./dist/web-vitals.attribution.umd.cjs`, name: 'webVitals', }, - plugins: configurePlugins({module: false, polyfill: false}), + plugins: configurePlugins({module: false}), }, { - input: 'dist/modules/attribution.js', + input: 'dist/modules/attribution/index.js', output: { format: 'iife', file: './dist/web-vitals.attribution.iife.js', name: 'webVitals', }, - plugins: configurePlugins({module: false, polyfill: false}), + plugins: configurePlugins({module: false}), }, ]; diff --git a/src/attribution/deprecated.ts b/src/attribution/deprecated.ts new file mode 100644 index 00000000..826ebfc9 --- /dev/null +++ b/src/attribution/deprecated.ts @@ -0,0 +1,26 @@ +/* + * Copyright 2024 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 { + /** + * @deprecated Use `onINP()` instead. + */ + onFID, +} from './onFID.js'; + +export {FIDThresholds} from '../onFID.js'; + +export * from '../types.js'; diff --git a/src/attribution.ts b/src/attribution/index.ts similarity index 51% rename from src/attribution.ts rename to src/attribution/index.ts index 89fe99a0..c0362821 100644 --- a/src/attribution.ts +++ b/src/attribution/index.ts @@ -14,18 +14,17 @@ * limitations under the License. */ -export {onCLS} from './attribution/onCLS.js'; -export {onFCP} from './attribution/onFCP.js'; -export {onFID} from './attribution/onFID.js'; -export {onINP} from './attribution/onINP.js'; -export {onLCP} from './attribution/onLCP.js'; -export {onTTFB} from './attribution/onTTFB.js'; +export {onCLS} from './onCLS.js'; +export {onFCP} from './onFCP.js'; +export {onINP} from './onINP.js'; +export {onLCP} from './onLCP.js'; +export {onTTFB} from './onTTFB.js'; -export {CLSThresholds} from './onCLS.js'; -export {FCPThresholds} from './onFCP.js'; -export {FIDThresholds} from './onFID.js'; -export {INPThresholds} from './onINP.js'; -export {LCPThresholds} from './onLCP.js'; -export {TTFBThresholds} from './onTTFB.js'; +export {CLSThresholds} from '../onCLS.js'; +export {FCPThresholds} from '../onFCP.js'; +export {INPThresholds} from '../onINP.js'; +export {LCPThresholds} from '../onLCP.js'; +export {TTFBThresholds} from '../onTTFB.js'; -export * from './types.js'; +export * from './deprecated.js'; +export * from '../types.js'; diff --git a/src/deprecated.ts b/src/deprecated.ts index 5bb254d8..1acc67e3 100644 --- a/src/deprecated.ts +++ b/src/deprecated.ts @@ -14,51 +14,10 @@ * limitations under the License. */ -export { - /** - * @deprecated Use `onCLS()` instead. - */ - onCLS as getCLS, -} from './onCLS.js'; - -export { - /** - * @deprecated Use `onFCP()` instead. - */ - onFCP as getFCP, -} from './onFCP.js'; - -export { - /** - * @deprecated Use `onFID()` instead. - */ - onFID as getFID, -} from './onFID.js'; - export { /** * @deprecated Use `onINP()` instead. */ - onINP as getINP, -} from './onINP.js'; - -export { - /** - * @deprecated Use `onLCP()` instead. - */ - onLCP as getLCP, -} from './onLCP.js'; - -export { - /** - * @deprecated Use `onTTFB()` instead. - */ - onTTFB as getTTFB, -} from './onTTFB.js'; - -export { - /** - * @deprecated Use `ReportCallback` instead. - */ - ReportCallback as ReportHandler, -} from './types.js'; + onFID, + FIDThresholds, +} from './onFID.js'; diff --git a/src/index.ts b/src/index.ts index 22ea7c91..6c5dc45d 100644 --- a/src/index.ts +++ b/src/index.ts @@ -16,7 +16,6 @@ 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'; diff --git a/src/lib/getNavigationEntry.ts b/src/lib/getNavigationEntry.ts index fa523bdf..3a3e8fd3 100644 --- a/src/lib/getNavigationEntry.ts +++ b/src/lib/getNavigationEntry.ts @@ -14,47 +14,12 @@ * limitations under the License. */ -import {NavigationTimingPolyfillEntry} from '../types.js'; - -const getNavigationEntryFromPerformanceTiming = - (): NavigationTimingPolyfillEntry => { - const timing = performance.timing; - const type = performance.navigation.type; - - const navigationEntry: {[key: string]: number | string} = { - entryType: 'navigation', - startTime: 0, - type: type == 2 ? 'back_forward' : type === 1 ? 'reload' : 'navigate', - }; - - for (const key in timing) { - if (key !== 'navigationStart' && key !== 'toJSON') { - navigationEntry[key] = Math.max( - (timing[key as keyof PerformanceTiming] as number) - - timing.navigationStart, - 0, - ); - } - } - return navigationEntry as unknown as NavigationTimingPolyfillEntry; - }; - export const getNavigationEntry = (): | PerformanceNavigationTiming - | NavigationTimingPolyfillEntry | undefined => { - if (window.__WEB_VITALS_POLYFILL__) { - return ( - window.performance && - ((performance.getEntriesByType && - performance.getEntriesByType('navigation')[0]) || - getNavigationEntryFromPerformanceTiming()) - ); - } else { - return ( - window.performance && - performance.getEntriesByType && - performance.getEntriesByType('navigation')[0] - ); - } + return ( + window.performance && + performance.getEntriesByType && + performance.getEntriesByType('navigation')[0] + ); }; diff --git a/src/lib/observe.ts b/src/lib/observe.ts index fca60989..af63f068 100644 --- a/src/lib/observe.ts +++ b/src/lib/observe.ts @@ -14,18 +14,13 @@ * limitations under the License. */ -import { - FirstInputPolyfillEntry, - NavigationTimingPolyfillEntry, -} from '../types.js'; - interface PerformanceEntryMap { 'event': PerformanceEventTiming[]; 'paint': PerformancePaintTiming[]; 'layout-shift': LayoutShift[]; 'largest-contentful-paint': LargestContentfulPaint[]; - 'first-input': PerformanceEventTiming[] | FirstInputPolyfillEntry[]; - 'navigation': PerformanceNavigationTiming[] | NavigationTimingPolyfillEntry[]; + 'first-input': PerformanceEventTiming[]; + 'navigation': PerformanceNavigationTiming[]; 'resource': PerformanceResourceTiming[]; } diff --git a/src/onFID.ts b/src/onFID.ts index c9ee655e..e3e3c327 100644 --- a/src/onFID.ts +++ b/src/onFID.ts @@ -69,6 +69,7 @@ export const onFID = (onReport: FIDReportCallback, opts?: ReportOpts) => { }; const po = observe('first-input', handleEntries); + report = bindReporter( onReport, metric, @@ -83,19 +84,7 @@ export const onFID = (onReport: FIDReportCallback, opts?: ReportOpts) => { po.disconnect(); }), ); - } - if (window.__WEB_VITALS_POLYFILL__) { - console.warn( - 'The web-vitals "base+polyfill" build is deprecated. See: https://bit.ly/3aqzsGm', - ); - - // Prefer the native implementation if available, - if (!po) { - window.webVitals.firstInputPolyfill( - handleEntry as FirstInputPolyfillCallback, - ); - } onBFCacheRestore(() => { metric = initMetric('FID'); report = bindReporter( @@ -105,27 +94,10 @@ export const onFID = (onReport: FIDReportCallback, opts?: ReportOpts) => { opts!.reportAllChanges, ); - window.webVitals.resetFirstInputPolyfill(); - window.webVitals.firstInputPolyfill( - handleEntry as FirstInputPolyfillCallback, - ); + // Browsers don't re-emit FID on bfcache restore so fake it until you make it + resetFirstInputPolyfill(); + firstInputPolyfill(handleEntry as FirstInputPolyfillCallback); }); - } else { - // Only monitor bfcache restores if the browser supports FID natively. - if (po) { - onBFCacheRestore(() => { - metric = initMetric('FID'); - report = bindReporter( - onReport, - metric, - FIDThresholds, - opts!.reportAllChanges, - ); - - resetFirstInputPolyfill(); - firstInputPolyfill(handleEntry as FirstInputPolyfillCallback); - }); - } } }); }; diff --git a/src/types/base.ts b/src/types/base.ts index c38660ef..f19f7081 100644 --- a/src/types/base.ts +++ b/src/types/base.ts @@ -14,10 +14,6 @@ * limitations under the License. */ -import { - FirstInputPolyfillEntry, - NavigationTimingPolyfillEntry, -} from './polyfills.js'; import type {CLSMetric} from './cls.js'; import type {FCPMetric} from './fcp.js'; import type {FIDMetric} from './fid.js'; @@ -64,12 +60,7 @@ export interface Metric { * The array may also be empty if the metric value was not based on any * entries (e.g. a CLS value of 0 given no layout shifts). */ - entries: ( - | PerformanceEntry - | LayoutShift - | FirstInputPolyfillEntry - | NavigationTimingPolyfillEntry - )[]; + entries: (PerformanceEntry | LayoutShift)[]; /** * The type of navigation. diff --git a/src/types/fcp.ts b/src/types/fcp.ts index ac9e3066..86d48b33 100644 --- a/src/types/fcp.ts +++ b/src/types/fcp.ts @@ -15,7 +15,6 @@ */ import type {LoadState, Metric} from './base.js'; -import {NavigationTimingPolyfillEntry} from './polyfills.js'; /** * An FCP-specific version of the Metric object. @@ -55,7 +54,7 @@ export interface FCPAttribution { * general page load issues. This can be used to access `serverTiming` for example: * navigationEntry?.serverTiming */ - navigationEntry?: PerformanceNavigationTiming | NavigationTimingPolyfillEntry; + navigationEntry?: PerformanceNavigationTiming; } /** diff --git a/src/types/fid.ts b/src/types/fid.ts index 4b664704..f6b71e75 100644 --- a/src/types/fid.ts +++ b/src/types/fid.ts @@ -15,14 +15,13 @@ */ import type {LoadState, Metric} from './base.js'; -import {FirstInputPolyfillEntry} from './polyfills.js'; /** * An FID-specific version of the Metric object. */ export interface FIDMetric extends Metric { name: 'FID'; - entries: (PerformanceEventTiming | FirstInputPolyfillEntry)[]; + entries: PerformanceEventTiming[]; } /** @@ -46,10 +45,9 @@ export interface FIDAttribution { */ eventType: string; /** - * The `PerformanceEventTiming` entry corresponding to FID (or the - * polyfill entry in browsers that don't support Event Timing). + * The `PerformanceEventTiming` entry corresponding to FID. */ - eventEntry: PerformanceEventTiming | FirstInputPolyfillEntry; + eventEntry: PerformanceEventTiming; /** * The loading state of the document at the time when the first interaction * occurred (see `LoadState` for details). If the first interaction occurred diff --git a/src/types/lcp.ts b/src/types/lcp.ts index c32ca1d8..2128695b 100644 --- a/src/types/lcp.ts +++ b/src/types/lcp.ts @@ -15,7 +15,6 @@ */ import type {Metric} from './base.js'; -import {NavigationTimingPolyfillEntry} from './polyfills.js'; /** * An LCP-specific version of the Metric object. @@ -69,7 +68,7 @@ export interface LCPAttribution { * general page load issues. This can be used to access `serverTiming` for example: * navigationEntry?.serverTiming */ - navigationEntry?: PerformanceNavigationTiming | NavigationTimingPolyfillEntry; + navigationEntry?: PerformanceNavigationTiming; /** * The `resource` entry for the LCP resource (if applicable), which is useful * for diagnosing resource load issues. diff --git a/src/types/polyfills.ts b/src/types/polyfills.ts index c174fe27..14bd5aea 100644 --- a/src/types/polyfills.ts +++ b/src/types/polyfills.ts @@ -22,16 +22,3 @@ export type FirstInputPolyfillEntry = Omit< export interface FirstInputPolyfillCallback { (entry: FirstInputPolyfillEntry): void; } - -export type NavigationTimingPolyfillEntry = Omit< - PerformanceNavigationTiming, - | 'initiatorType' - | 'nextHopProtocol' - | 'redirectCount' - | 'transferSize' - | 'encodedBodySize' - | 'decodedBodySize' - | 'type' -> & { - type: PerformanceNavigationTiming['type']; -}; diff --git a/src/types/ttfb.ts b/src/types/ttfb.ts index 4fe66eab..35a7f8c3 100644 --- a/src/types/ttfb.ts +++ b/src/types/ttfb.ts @@ -15,14 +15,13 @@ */ import type {Metric} from './base.js'; -import {NavigationTimingPolyfillEntry} from './polyfills.js'; /** * A TTFB-specific version of the Metric object. */ export interface TTFBMetric extends Metric { name: 'TTFB'; - entries: PerformanceNavigationTiming[] | NavigationTimingPolyfillEntry[]; + entries: PerformanceNavigationTiming[]; } /** @@ -56,7 +55,7 @@ export interface TTFBAttribution { * general page load issues. This can be used to access `serverTiming` for example: * navigationEntry?.serverTiming */ - navigationEntry?: PerformanceNavigationTiming | NavigationTimingPolyfillEntry; + navigationEntry?: PerformanceNavigationTiming; } /** diff --git a/test/e2e/onFID-test.js b/test/e2e/onFID-test.js index b652107d..d90d7c3d 100644 --- a/test/e2e/onFID-test.js +++ b/test/e2e/onFID-test.js @@ -77,7 +77,7 @@ describe('onFID()', async function () { assert.match(fid.entries[0].name, /(mouse|pointer)down/); }); - it('does not report if the browser does not support FID and the polyfill is not used', async function () { + it('does not report if the browser does not support FID', async function () { if (browserSupportsFID) this.skip(); await navigateTo('/test/fid'); @@ -94,8 +94,7 @@ describe('onFID()', async function () { await stubForwardBack(); - // Assert no entries after bfcache restores either (if the browser does - // not support native FID and the polyfill is not used). + // Assert no entries after bfcache restores either. await h1.click(); // Wait a bit to ensure no beacons were sent. @@ -105,35 +104,6 @@ describe('onFID()', async function () { assert.strictEqual(bfcacheRestoreBeacons.length, 0); }); - it('falls back to the polyfill in non-supporting browsers', async function () { - // Ignore Safari until this bug is fixed: - // https://bugs.webkit.org/show_bug.cgi?id=211101 - if (browser.capabilities.browserName === 'Safari') this.skip(); - - await navigateTo('/test/fid?polyfill=1'); - - // Click on the

. - const h1 = await $('h1'); - await h1.click(); - - await beaconCountIs(1); - - const [fid] = await getBeacons(); - - assert(fid.value >= 0); - assert(fid.id.match(/^v3-\d+-\d+$/)); - assert.strictEqual(fid.name, 'FID'); - assert.strictEqual(fid.value, fid.delta); - assert.strictEqual(fid.rating, 'good'); - assert.match(fid.navigationType, /navigate|reload/); - assert.match(fid.entries[0].name, /(mouse|pointer)down/); - if (browserSupportsFID) { - assert('duration' in fid.entries[0]); - } else { - assert(!('duration' in fid.entries[0])); - } - }); - it('does not report if the document was hidden at page load time', async function () { // Ignore Safari until this bug is fixed: // https://bugs.webkit.org/show_bug.cgi?id=211101 diff --git a/test/server.js b/test/server.js index b6ea7731..2ac9098b 100644 --- a/test/server.js +++ b/test/server.js @@ -50,9 +50,6 @@ app.post('/collect', bodyParser.text(), (req, res) => { app.get('/test/:view', function (req, res, next) { let modulePath = `/dist/web-vitals.js`; - if (req.query.polyfill) { - modulePath = `/dist/web-vitals.base.js`; - } if (req.query.attribution) { modulePath = `/dist/web-vitals.attribution.js`; } @@ -60,7 +57,6 @@ app.get('/test/:view', function (req, res, next) { const data = { ...req.query, modulePath: modulePath, - webVitalsPolyfill: fs.readFileSync('./dist/polyfill.js', 'utf-8'), }; const content = nunjucks.render(`${req.params.view}.njk`, data); diff --git a/test/views/layout.njk b/test/views/layout.njk index 6ff783a1..b26934e0 100644 --- a/test/views/layout.njk +++ b/test/views/layout.njk @@ -223,9 +223,6 @@ }; }()); - {% if polyfill %} - - {% endif %} {% block head %}{% endblock %} {% if renderBlocking %}