diff --git a/README.md b/README.md index dfb25f6..8a12400 100644 --- a/README.md +++ b/README.md @@ -6,23 +6,23 @@ [An example report for developers.google.com](https://googlechrome.github.io/lighthouse/viewer/?gist=d9072ab8ccb30622deab48e6d5ee229c): - Lighthouse Field Performance Plugin + Lighthouse Field Performance Plugin

-This plugin adds a field performance category with real-world data from [Chrome UX Report](https://developers.google.com/web/tools/chrome-user-experience-report/). It's exactly like [PageSpeed Insights](https://developers.google.com/speed/pagespeed/insights/), but for your local run and with a field performance score. +This plugin adds Core Web Vitals values to your Lighthouse report. The Field Performance category includes real-user data provided by [Chrome UX Report](https://developers.google.com/web/tools/chrome-user-experience-report/). It's similar to the field section in [PageSpeed Insights](https://developers.google.com/speed/pagespeed/insights/). -The scoring algorithm uses [Core Web Vitals](https://web.dev/vitals/). It weigths values for Largest Contentful Paint, First Input Delay, and Cumulative Layout Shift. (_Note_: FCP and the origin values do not affect the score, [see the source](./src/index.js)) +The scoring algorithm weighs values for Largest Contentful Paint (LCP), First Input Delay (FID), and Cumulative Layout Shift (CLS) and picks a **minimum score**. It uses Core Web Vitals assessment that expects all its metrics to pass thresholds. For example, https://edition.cnn.com/ has LCP 5.9 s (15), FID 20 ms (100), and CLS 0.02 (100). It has `poor` mark in the [Search Console](https://support.google.com/webmasters/answer/9205520), and the score is 15. (_Note_: FCP and the origin values do not affect the score, [see the source](./src/index.js)) Check out the parity between Field & Lab performance on mobile: -Field & lab performance on mobile +Field & lab performance on mobile And on desktop: -Field & lab performance on desktop +Field & lab performance on desktop Sometimes field data is missing because a URL doesn't have enough anonymous traffic. In this case, the lab data is the only available measurement. diff --git a/package.json b/package.json index 695fa78..be80d9c 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "lighthouse-plugin-field-performance", - "version": "2.1.1", + "version": "2.2.0", "description": "Lighthouse plugin to display field data", "repository": "https://github.com/treosh/lighthouse-plugin-field-performance", "author": "Aleksey Kulikov , Artem Denysov ", diff --git a/src/index.js b/src/index.js index b2e5dad..61c3858 100644 --- a/src/index.js +++ b/src/index.js @@ -1,3 +1,35 @@ +const ReportScoring = require('lighthouse/lighthouse-core/scoring') +const scoreAllCategories = ReportScoring.scoreAllCategories + +/** + * Monkey-patch Lighthouse's ReportScoring to support Core Web Vitals logic. + * https://github.com/GoogleChrome/lighthouse/blob/f3d0e3459d8fd15b055148dec0ae4e430df6495b/lighthouse-core/scoring.js + * + * Logic: a URL passes the Core Web Vitals assessment if all its metrics pass thresholds. + * The algorithm picks the minimum score (not `averageMean` used in Lighthouse). + * + * Theory of constraints (https://en.wikipedia.org/wiki/Theory_of_constraints): a chain is no stronger than its weakest link. + */ + +/** @typedef {Object} ResultsByAuditId */ +/** @typedef {{ score: ?number, auditRefs: { id: string, weight: number }[] }} CategoryResult */ + +/** @param {any} configCategories @param {ResultsByAuditId} resultsByAuditId */ +ReportScoring.scoreAllCategories = function (configCategories, resultsByAuditId) { + const result = scoreAllCategories(configCategories, resultsByAuditId) + const fieldPluginCategory = /** @type {CategoryResult | null} */ (result['lighthouse-plugin-field-performance']) + if (!fieldPluginCategory) return result + fieldPluginCategory.score = getMinScore(fieldPluginCategory, resultsByAuditId) + return result +} + +/** @param {CategoryResult} fieldPluginCategoryResult @param {ResultsByAuditId} resultsByAuditId */ +function getMinScore(fieldPluginCategoryResult, resultsByAuditId) { + const activeAuditRefs = fieldPluginCategoryResult.auditRefs.filter((auditRef) => auditRef.weight !== 0) + const scores = activeAuditRefs.map((auditRef) => resultsByAuditId[auditRef.id].score) + return scores.length ? Math.min(...scores) : 0 +} + module.exports = { audits: [ { path: 'lighthouse-plugin-field-performance/src/audits/field-fcp.js' }, diff --git a/src/types.d.ts b/src/types.d.ts index caab33b..ae97ce5 100644 --- a/src/types.d.ts +++ b/src/types.d.ts @@ -1,2 +1,3 @@ declare module 'lighthouse' declare module 'lighthouse/lighthouse-cli/run' +declare module 'lighthouse/lighthouse-core/scoring' diff --git a/test/snapshots/test/index.js.md b/test/snapshots/test/index.js.md index df71253..f24f52e 100644 --- a/test/snapshots/test/index.js.md +++ b/test/snapshots/test/index.js.md @@ -365,7 +365,7 @@ Generated by [AVA](https://avajs.dev). ], description: 'These metrics show the performance of the page over the past 30 days. Data is collected anonymously in for real-world Chrome users and provided by Chrome UX Report. [Learn More](https://developers.google.com/web/tools/chrome-user-experience-report/)', id: 'lighthouse-plugin-field-performance', - score: 0.99, + score: 0.98, title: 'Field Performance', } diff --git a/test/snapshots/test/index.js.snap b/test/snapshots/test/index.js.snap index a7cf616..c513f3c 100644 Binary files a/test/snapshots/test/index.js.snap and b/test/snapshots/test/index.js.snap differ