Skip to content

Commit

Permalink
squashed commit of 'mapping-atomic' branch.
Browse files Browse the repository at this point in the history
  • Loading branch information
paulirish committed May 13, 2021
1 parent 8769ff8 commit faee95c
Show file tree
Hide file tree
Showing 10 changed files with 323 additions and 31 deletions.
54 changes: 54 additions & 0 deletions lighthouse-cli/test/cli/__snapshots__/index-test.js.snap
Original file line number Diff line number Diff line change
Expand Up @@ -832,36 +832,89 @@ Object {
"performance": Object {
"auditRefs": Array [
Object {
"acronym": "FCP",
"group": "metrics",
"id": "first-contentful-paint",
"relevantAudits": Array [
"server-response-time",
"render-blocking-resources",
"redirects",
"critical-request-chains",
"uses-text-compression",
"uses-rel-preconnect",
"uses-rel-preload",
"font-display",
"unminified-javascript",
"unminified-css",
"unused-css-rules",
],
"weight": 15,
},
Object {
"acronym": "SI",
"group": "metrics",
"id": "speed-index",
"weight": 15,
},
Object {
"acronym": "LCP",
"group": "metrics",
"id": "largest-contentful-paint",
"relevantAudits": Array [
"server-response-time",
"render-blocking-resources",
"redirects",
"critical-request-chains",
"uses-text-compression",
"uses-rel-preconnect",
"uses-rel-preload",
"font-display",
"unminified-javascript",
"unminified-css",
"unused-css-rules",
"largest-contentful-paint-element",
"preload-lcp-image",
"unused-javascript",
"efficient-animated-content",
"total-byte-weight",
],
"weight": 25,
},
Object {
"acronym": "TTI",
"group": "metrics",
"id": "interactive",
"weight": 15,
},
Object {
"acronym": "TBT",
"group": "metrics",
"id": "total-blocking-time",
"relevantAudits": Array [
"long-tasks",
"third-party-summary",
"third-party-facades",
"bootup-time",
"mainthread-work-breakdown",
"dom-size",
"duplicated-javascript",
"legacy-javascript",
],
"weight": 25,
},
Object {
"acronym": "CLS",
"group": "metrics",
"id": "cumulative-layout-shift",
"relevantAudits": Array [
"layout-shift-elements",
"non-composited-animations",
"unsized-images",
],
"weight": 5,
},
Object {
"acronym": "FCI",
"id": "first-cpu-idle",
"weight": 0,
},
Expand All @@ -870,6 +923,7 @@ Object {
"weight": 0,
},
Object {
"acronym": "FMP",
"id": "first-meaningful-paint",
"weight": 0,
},
Expand Down
20 changes: 11 additions & 9 deletions lighthouse-core/config/default-config.js
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@

const constants = require('./constants.js');
const i18n = require('../lib/i18n/i18n.js');
const m2a = require('./metrics-to-audits.js');

const UIStrings = {
/** Title of the Performance category of audits. Equivalent to 'Web performance', this term is inclusive of all web page speed and loading optimization topics. Also used as a label of a score gauge; try to limit to 20 characters. */
Expand Down Expand Up @@ -420,16 +421,17 @@ const defaultConfig = {
'performance': {
title: str_(UIStrings.performanceCategoryTitle),
auditRefs: [
{id: 'first-contentful-paint', weight: 15, group: 'metrics'},
{id: 'speed-index', weight: 15, group: 'metrics'},
{id: 'largest-contentful-paint', weight: 25, group: 'metrics'},
{id: 'interactive', weight: 15, group: 'metrics'},
{id: 'total-blocking-time', weight: 25, group: 'metrics'},
{id: 'cumulative-layout-shift', weight: 5, group: 'metrics'},
// intentionally left out of metrics group so they won't be displayed
{id: 'first-cpu-idle', weight: 0},
{id: 'first-contentful-paint', weight: 15, group: 'metrics', acronym: 'FCP', relevantAudits: m2a.fcpRelevantAudits},
{id: 'speed-index', weight: 15, group: 'metrics', acronym: 'SI'},
{id: 'largest-contentful-paint', weight: 25, group: 'metrics', acronym: 'LCP', relevantAudits: m2a.lcpRelevantAudits},
{id: 'interactive', weight: 15, group: 'metrics', acronym: 'TTI'},
{id: 'total-blocking-time', weight: 25, group: 'metrics', acronym: 'TBT', relevantAudits: m2a.tbtRelevantAudits},
{id: 'cumulative-layout-shift', weight: 5, group: 'metrics', acronym: 'CLS', relevantAudits: m2a.clsRelevantAudits},

// These are our "invisible" metrics. Not displayed, but still in the LHR
{id: 'first-cpu-idle', weight: 0, acronym: 'FCI'},
{id: 'max-potential-fid', weight: 0},
{id: 'first-meaningful-paint', weight: 0},
{id: 'first-meaningful-paint', weight: 0, acronym: 'FMP'},
{id: 'estimated-input-latency', weight: 0},

{id: 'render-blocking-resources', weight: 0, group: 'load-opportunities'},
Expand Down
55 changes: 55 additions & 0 deletions lighthouse-core/config/metrics-to-audits.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,55 @@
/**
* @license Copyright 2021 The Lighthouse Authors. All Rights Reserved.
* 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 http://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.
*/
'use strict';

// go/lh-audit-metric-mapping
const fcpRelevantAudits = [
'server-response-time',
'render-blocking-resources',
'redirects',
'critical-request-chains',
'uses-text-compression',
'uses-rel-preconnect',
'uses-rel-preload',
'font-display',
'unminified-javascript',
'unminified-css',
'unused-css-rules',
];

const lcpRelevantAudits = [
...fcpRelevantAudits,
'largest-contentful-paint-element',
'preload-lcp-image',
'unused-javascript',
'efficient-animated-content',
'total-byte-weight',
];

const tbtRelevantAudits = [
'long-tasks',
'third-party-summary',
'third-party-facades',
'bootup-time',
'mainthread-work-breakdown',
'dom-size',
'duplicated-javascript',
'legacy-javascript',
];

const clsRelevantAudits = [
'layout-shift-elements',
'non-composited-animations',
'unsized-images',
// 'preload-fonts', // actually in BP, rather than perf
];

module.exports = {
fcpRelevantAudits,
lcpRelevantAudits,
tbtRelevantAudits,
clsRelevantAudits,
};
Original file line number Diff line number Diff line change
Expand Up @@ -118,18 +118,6 @@ class PerformanceCategoryRenderer extends CategoryRenderer {
if (fci) v5andv6metrics.push(fci);
if (fmp) v5andv6metrics.push(fmp);

/** @type {Record<string, string>} */
const acronymMapping = {
'cumulative-layout-shift': 'CLS',
'first-contentful-paint': 'FCP',
'first-cpu-idle': 'FCI',
'first-meaningful-paint': 'FMP',
'interactive': 'TTI',
'largest-contentful-paint': 'LCP',
'speed-index': 'SI',
'total-blocking-time': 'TBT',
};

/**
* Clamp figure to 2 decimal places
* @param {number} val
Expand All @@ -147,7 +135,7 @@ class PerformanceCategoryRenderer extends CategoryRenderer {
} else {
value = 'null';
}
return [acronymMapping[audit.id] || audit.id, value];
return [audit.acronym || audit.id, value];
});
const paramPairs = [...metricPairs];

Expand Down Expand Up @@ -225,6 +213,13 @@ class PerformanceCategoryRenderer extends CategoryRenderer {
.filter(audit => audit.group === 'load-opportunities' && !Util.showAsPassed(audit.result))
.sort((auditA, auditB) => this._getWastedMs(auditB) - this._getWastedMs(auditA));


const filterableMetrics = metricAudits.filter(a => !!a.relevantAudits);
// TODO: only add if there are opportunities & diagnostics rendered.
if (filterableMetrics.length) {
this.renderMetricAuditFilter(filterableMetrics, element);
}

if (opportunityAudits.length) {
// Scale the sparklines relative to savings, minimum 2s to not overstate small savings
const minimumScale = 2000;
Expand Down Expand Up @@ -299,6 +294,74 @@ class PerformanceCategoryRenderer extends CategoryRenderer {

return element;
}

/**
* Render the control to filter the audits by metric. The filtering is done at runtime by CSS only
* @param {LH.ReportResult.AuditRef[]} filterableMetrics
* @param {HTMLDivElement} categoryEl
*/
renderMetricAuditFilter(filterableMetrics, categoryEl) {
// thx https://codepen.io/surjithctly/pen/weEJvX
const metricFilterEl = this.dom.createElement('div', 'lh-metricfilter');
const textEl = this.dom.createChildOf(metricFilterEl, 'span', 'lh-metricfilter__text');
textEl.textContent = 'Show audits relevant to: ';
const labelSelectors = [];
const auditSelectors = [];

const filterChoices = /** @type {LH.ReportResult.AuditRef[]} */ ([
({acronym: 'All'}),
...filterableMetrics
]);
for (const metric of filterChoices) {
// The radio elements are appended into `categoryEl` to allow the sweet ~ selectors to work
const elemId = `metric-${metric.acronym}`;
const radioEl = this.dom.createChildOf(categoryEl, 'input', 'lh-metricfilter__radio', {
type: 'radio',
name: 'metricsfilter',
id: elemId,
hidden: 'true',
});
const labelEl = this.dom.createChildOf(metricFilterEl, 'label', 'lh-metricfilter__label', {
for: elemId,
title: metric.result && metric.result.title,
});
labelEl.textContent = metric.acronym || metric.id;
if (metric.acronym === 'All') {
radioEl.checked = true;
}
// Dynamically write some CSS, for the CSS-only filtering
labelSelectors.push(`.lh-metricfilter__radio#${elemId}:checked ~ .lh-metricfilter > .lh-metricfilter__label[for="${elemId}"]`); // eslint-disable-line max-len
if (metric.relevantAudits) {
/* Generate some CSS selectors like this:
#metric-CLS:checked ~ .lh-audit-group > #layout-shift-elements,
#metric-CLS:checked ~ .lh-audit-group > #non-composited-animations,
#metric-CLS:checked ~ .lh-audit-group > #unsized-images
*/
auditSelectors.push(metric.relevantAudits.map(auditId => `#${elemId}:checked ~ .lh-audit-group > #${auditId}`).join(',\n')); // eslint-disable-line max-len
}
}

const styleEl = this.dom.createChildOf(metricFilterEl, 'style');
// eslint-disable-next-line max-len
styleEl.textContent = `
${labelSelectors.join(',\n')} {
background: var(--color-blue-A700);
color: var(--color-white);
}
/* If selecting non-All, hide all audits (and also the group header/description… */
.lh-metricfilter__radio:checked:not(#metric-All) ~ .lh-audit-group .lh-audit,
.lh-metricfilter__radio:checked:not(#metric-All) ~ .lh-audit-group .lh-audit-group__description,
.lh-metricfilter__radio:checked:not(#metric-All) ~ .lh-audit-group .lh-audit-group__itemcount {
display: none;
}
/* …And then display:block the relevant ones */
${auditSelectors.join(',\n')} {
display: block;
}
/*# sourceURL=metricfilter.css */
`;
categoryEl.append(metricFilterEl);
}
}

if (typeof module !== 'undefined' && module.exports) {
Expand Down
37 changes: 37 additions & 0 deletions lighthouse-core/report/html/report-styles.css

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

15 changes: 15 additions & 0 deletions lighthouse-core/test/config/default-config-test.js
Original file line number Diff line number Diff line change
Expand Up @@ -41,4 +41,19 @@ describe('Default Config', () => {
`${auditResult.id} has an undefined overallSavingsMs`);
});
});

it('relevantAudits map to existing perf audit', () => {
const metricsWithRelevantAudits = defaultConfig.categories.performance.auditRefs.filter(a =>
a.relevantAudits);
const allPerfAuditIds = defaultConfig.categories.performance.auditRefs.map(a => a.id);

for (const metric of metricsWithRelevantAudits) {
assert.ok(Array.isArray(metric.relevantAudits) && metric.relevantAudits.length);

for (const auditid of metric.relevantAudits) {
const errMsg = `(${auditid}) is relevant audit for (${metric.id}), but no audit found.`;
assert.ok(allPerfAuditIds.includes(auditid), errMsg);
}
}
});
});
Loading

0 comments on commit faee95c

Please sign in to comment.