Commit 5a003efc authored by Paul Irish's avatar Paul Irish Committed by Commit Bot

DevTools: Roll Lighthouse to 4.0.0-beta

Bug: 772558
Change-Id: Ie1ef89f7a189687e600e5e22d376c53dac242079
Reviewed-on: https://chromium-review.googlesource.com/c/1355176Reviewed-by: default avatarDmitry Gozman <dgozman@chromium.org>
Commit-Queue: Paul Irish <paulirish@chromium.org>
Cr-Commit-Position: refs/heads/master@{#612481}
parent 298c4d34
...@@ -38,7 +38,7 @@ all_devtools_files = [ ...@@ -38,7 +38,7 @@ all_devtools_files = [
"front_end/audits2_worker.js", "front_end/audits2_worker.js",
"front_end/audits2_worker.json", "front_end/audits2_worker.json",
"front_end/audits2_worker/Audits2Service.js", "front_end/audits2_worker/Audits2Service.js",
"front_end/audits2_worker/lighthouse/lighthouse-background.js", "front_end/audits2_worker/lighthouse/lighthouse-dt-bundle.js",
"front_end/audits2_worker/module.json", "front_end/audits2_worker/module.json",
"front_end/audits2/Audits2Panel.js", "front_end/audits2/Audits2Panel.js",
"front_end/audits2/Audits2Controller.js", "front_end/audits2/Audits2Controller.js",
...@@ -55,6 +55,7 @@ all_devtools_files = [ ...@@ -55,6 +55,7 @@ all_devtools_files = [
"front_end/audits2/lighthouse/renderer/details-renderer.js", "front_end/audits2/lighthouse/renderer/details-renderer.js",
"front_end/audits2/lighthouse/renderer/category-renderer.js", "front_end/audits2/lighthouse/renderer/category-renderer.js",
"front_end/audits2/lighthouse/renderer/performance-category-renderer.js", "front_end/audits2/lighthouse/renderer/performance-category-renderer.js",
"front_end/audits2/lighthouse/renderer/pwa-category-renderer.js",
"front_end/audits2/lighthouse/renderer/crc-details-renderer.js", "front_end/audits2/lighthouse/renderer/crc-details-renderer.js",
"front_end/audits2/lighthouse/renderer/report-renderer.js", "front_end/audits2/lighthouse/renderer/report-renderer.js",
"front_end/audits2/lighthouse/renderer/util.js", "front_end/audits2/lighthouse/renderer/util.js",
......
...@@ -59,7 +59,7 @@ class CriticalRequestChainRenderer { ...@@ -59,7 +59,7 @@ class CriticalRequestChainRenderer {
const node = parent[id]; const node = parent[id];
const siblings = Object.keys(parent); const siblings = Object.keys(parent);
const isLastChild = siblings.indexOf(id) === (siblings.length - 1); const isLastChild = siblings.indexOf(id) === (siblings.length - 1);
const hasChildren = Object.keys(node.children).length > 0; const hasChildren = !!node.children && Object.keys(node.children).length > 0;
// Copy the tree markers so that we don't change by reference. // Copy the tree markers so that we don't change by reference.
const newTreeMarkers = Array.isArray(treeMarkers) ? treeMarkers.slice(0) : []; const newTreeMarkers = Array.isArray(treeMarkers) ? treeMarkers.slice(0) : [];
...@@ -149,13 +149,14 @@ class CriticalRequestChainRenderer { ...@@ -149,13 +149,14 @@ class CriticalRequestChainRenderer {
*/ */
static buildTree(dom, tmpl, segment, elem, details) { static buildTree(dom, tmpl, segment, elem, details) {
elem.appendChild(CriticalRequestChainRenderer.createChainNode(dom, tmpl, segment)); elem.appendChild(CriticalRequestChainRenderer.createChainNode(dom, tmpl, segment));
if (segment.node.children) {
for (const key of Object.keys(segment.node.children)) { for (const key of Object.keys(segment.node.children)) {
const childSegment = CriticalRequestChainRenderer.createSegment(segment.node.children, key, const childSegment = CriticalRequestChainRenderer.createSegment(segment.node.children, key,
segment.startTime, segment.transferSize, segment.treeMarkers, segment.isLastChild); segment.startTime, segment.transferSize, segment.treeMarkers, segment.isLastChild);
CriticalRequestChainRenderer.buildTree(dom, tmpl, childSegment, elem, details); CriticalRequestChainRenderer.buildTree(dom, tmpl, childSegment, elem, details);
} }
} }
}
/** /**
* @param {DOM} dom * @param {DOM} dom
......
...@@ -80,6 +80,8 @@ class DetailsRenderer { ...@@ -80,6 +80,8 @@ class DetailsRenderer {
case 'opportunity': case 'opportunity':
// @ts-ignore - TODO(bckenny): Fix type hierarchy // @ts-ignore - TODO(bckenny): Fix type hierarchy
return this._renderOpportunityTable(details); return this._renderOpportunityTable(details);
case 'numeric':
return this._renderNumeric(/** @type {StringDetailsJSON} */ (details));
default: { default: {
throw new Error(`Unknown type: ${details.type}`); throw new Error(`Unknown type: ${details.type}`);
} }
...@@ -124,14 +126,11 @@ class DetailsRenderer { ...@@ -124,14 +126,11 @@ class DetailsRenderer {
displayedPath = parsed.file === '/' ? parsed.origin : parsed.file; displayedPath = parsed.file === '/' ? parsed.origin : parsed.file;
displayedHost = parsed.file === '/' ? '' : `(${parsed.hostname})`; displayedHost = parsed.file === '/' ? '' : `(${parsed.hostname})`;
title = url; title = url;
} catch (/** @type {!Error} */ e) { } catch (e) {
if (!e.name.startsWith('TypeError')) {
throw e;
}
displayedPath = url; displayedPath = url;
} }
const element = /** @type {HTMLElement} */ (this._dom.createElement('div', 'lh-text__url')); const element = this._dom.createElement('div', 'lh-text__url');
element.appendChild(this._renderText({ element.appendChild(this._renderText({
value: displayedPath, value: displayedPath,
})); }));
...@@ -162,7 +161,7 @@ class DetailsRenderer { ...@@ -162,7 +161,7 @@ class DetailsRenderer {
}); });
} }
const a = /** @type {HTMLAnchorElement} */ (this._dom.createElement('a')); const a = this._dom.createElement('a');
a.rel = 'noopener'; a.rel = 'noopener';
a.target = '_blank'; a.target = '_blank';
a.textContent = details.text; a.textContent = details.text;
...@@ -181,6 +180,16 @@ class DetailsRenderer { ...@@ -181,6 +180,16 @@ class DetailsRenderer {
return element; return element;
} }
/**
* @param {{value: string}} text
* @return {Element}
*/
_renderNumeric(text) {
const element = this._dom.createElement('div', 'lh-numeric');
element.textContent = text.value;
return element;
}
/** /**
* Create small thumbnail with scaled down image asset. * Create small thumbnail with scaled down image asset.
* If the supplied details doesn't have an image/* mimeType, then an empty span is returned. * If the supplied details doesn't have an image/* mimeType, then an empty span is returned.
...@@ -188,7 +197,7 @@ class DetailsRenderer { ...@@ -188,7 +197,7 @@ class DetailsRenderer {
* @return {Element} * @return {Element}
*/ */
_renderThumbnail(details) { _renderThumbnail(details) {
const element = /** @type {HTMLImageElement}*/ (this._dom.createElement('img', 'lh-thumbnail')); const element = this._dom.createElement('img', 'lh-thumbnail');
const strValue = details.value; const strValue = details.value;
element.src = strValue; element.src = strValue;
element.title = strValue; element.title = strValue;
...@@ -337,7 +346,7 @@ class DetailsRenderer { ...@@ -337,7 +346,7 @@ class DetailsRenderer {
* @protected * @protected
*/ */
renderNode(item) { renderNode(item) {
const element = /** @type {HTMLSpanElement} */ (this._dom.createElement('span', 'lh-node')); const element = this._dom.createElement('span', 'lh-node');
if (item.snippet) { if (item.snippet) {
element.textContent = item.snippet; element.textContent = item.snippet;
} }
......
...@@ -18,6 +18,8 @@ ...@@ -18,6 +18,8 @@
/* globals URL self */ /* globals URL self */
/** @typedef {HTMLElementTagNameMap & {[id: string]: HTMLElement}} HTMLElmentByTagName */
class DOM { class DOM {
/** /**
* @param {Document} document * @param {Document} document
...@@ -27,14 +29,14 @@ class DOM { ...@@ -27,14 +29,14 @@ class DOM {
this._document = document; this._document = document;
} }
// TODO(bckenny): can pass along `createElement`'s inferred type
/** /**
* @param {string} name * @template {string} T
* @param {T} name
* @param {string=} className * @param {string=} className
* @param {Object<string, (string|undefined)>=} attrs Attribute key/val pairs. * @param {Object<string, (string|undefined)>=} attrs Attribute key/val pairs.
* Note: if an attribute key has an undefined value, this method does not * Note: if an attribute key has an undefined value, this method does not
* set the attribute on the node. * set the attribute on the node.
* @return {Element} * @return {HTMLElmentByTagName[T]}
*/ */
createElement(name, className, attrs = {}) { createElement(name, className, attrs = {}) {
const element = this._document.createElement(name); const element = this._document.createElement(name);
...@@ -58,13 +60,14 @@ class DOM { ...@@ -58,13 +60,14 @@ class DOM {
} }
/** /**
* @template {string} T
* @param {Element} parentElem * @param {Element} parentElem
* @param {string} elementName * @param {T} elementName
* @param {string=} className * @param {string=} className
* @param {Object<string, (string|undefined)>=} attrs Attribute key/val pairs. * @param {Object<string, (string|undefined)>=} attrs Attribute key/val pairs.
* Note: if an attribute key has an undefined value, this method does not * Note: if an attribute key has an undefined value, this method does not
* set the attribute on the node. * set the attribute on the node.
* @return {Element} * @return {HTMLElmentByTagName[T]}
*/ */
createChildOf(parentElem, elementName, className, attrs) { createChildOf(parentElem, elementName, className, attrs) {
const element = this.createElement(elementName, className, attrs); const element = this.createElement(elementName, className, attrs);
...@@ -122,7 +125,7 @@ class DOM { ...@@ -122,7 +125,7 @@ class DOM {
// Append link if there are any. // Append link if there are any.
if (linkText && linkHref) { if (linkText && linkHref) {
const a = /** @type {HTMLAnchorElement} */ (this.createElement('a')); const a = this.createElement('a');
a.rel = 'noopener'; a.rel = 'noopener';
a.target = '_blank'; a.target = '_blank';
a.textContent = linkText; a.textContent = linkText;
...@@ -147,7 +150,7 @@ class DOM { ...@@ -147,7 +150,7 @@ class DOM {
const [preambleText, codeText] = parts.splice(0, 2); const [preambleText, codeText] = parts.splice(0, 2);
element.appendChild(this._document.createTextNode(preambleText)); element.appendChild(this._document.createTextNode(preambleText));
if (codeText) { if (codeText) {
const pre = /** @type {HTMLPreElement} */ (this.createElement('code')); const pre = this.createElement('code');
pre.textContent = codeText; pre.textContent = codeText;
element.appendChild(pre); element.appendChild(pre);
} }
......
...@@ -188,7 +188,7 @@ class PerformanceCategoryRenderer extends CategoryRenderer { ...@@ -188,7 +188,7 @@ class PerformanceCategoryRenderer extends CategoryRenderer {
groupEl.appendChild(headerEl); groupEl.appendChild(headerEl);
opportunityAudits.forEach((item, i) => opportunityAudits.forEach((item, i) =>
groupEl.appendChild(this._renderOpportunity(item, i, scale))); groupEl.appendChild(this._renderOpportunity(item, i, scale)));
groupEl.classList.add('lh-audit-group--opportunities'); groupEl.classList.add('lh-audit-group--load-opportunities');
element.appendChild(groupEl); element.appendChild(groupEl);
} }
...@@ -209,14 +209,17 @@ class PerformanceCategoryRenderer extends CategoryRenderer { ...@@ -209,14 +209,17 @@ class PerformanceCategoryRenderer extends CategoryRenderer {
} }
// Passed audits // Passed audits
const passedElements = category.auditRefs const passedAudits = category.auditRefs
.filter(audit => (audit.group === 'load-opportunities' || audit.group === 'diagnostics') && .filter(audit => (audit.group === 'load-opportunities' || audit.group === 'diagnostics') &&
Util.showAsPassed(audit.result)) Util.showAsPassed(audit.result));
.map((audit, i) => this.renderAudit(audit, i));
if (!passedElements.length) return element; if (!passedAudits.length) return element;
const passedElem = this.renderPassedAuditsSection(passedElements); const clumpOpts = {
auditRefs: passedAudits,
groupDefinitions: groups,
};
const passedElem = this.renderClump('passed', clumpOpts);
element.appendChild(passedElem); element.appendChild(passedElem);
return element; return element;
} }
......
/**
* @license
* Copyright 2018 Google Inc. 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';
/* globals self, Util, CategoryRenderer */
class PwaCategoryRenderer extends CategoryRenderer {
/**
* @param {LH.ReportResult.Category} category
* @param {Object<string, LH.Result.ReportGroup>} [groupDefinitions]
* @return {Element}
*/
render(category, groupDefinitions = {}) {
const categoryElem = this.dom.createElement('div', 'lh-category');
this.createPermalinkSpan(categoryElem, category.id);
categoryElem.appendChild(this.renderCategoryHeader(category));
const auditRefs = category.auditRefs;
// Regular audits aren't split up into pass/fail/not-applicable clumps, they're
// all put in a top-level clump that isn't expandable/collapsable.
const regularAuditRefs = auditRefs.filter(ref => ref.result.scoreDisplayMode !== 'manual');
const auditsElem = this._renderAudits(regularAuditRefs, groupDefinitions);
categoryElem.appendChild(auditsElem);
// Manual audits are still in a manual clump.
const manualAuditRefs = auditRefs.filter(ref => ref.result.scoreDisplayMode === 'manual');
const manualElem = this.renderClump('manual',
{auditRefs: manualAuditRefs, groupDefinitions, description: category.manualDescription});
categoryElem.appendChild(manualElem);
return categoryElem;
}
/**
* @param {LH.ReportResult.Category} category
* @return {DocumentFragment}
*/
renderScoreGauge(category) {
// Defer to parent-gauge style if category error.
if (category.score === null) {
return super.renderScoreGauge(category);
}
const tmpl = this.dom.cloneTemplate('#tmpl-lh-gauge--pwa', this.templateContext);
const wrapper = /** @type {HTMLAnchorElement} */ (this.dom.find('.lh-gauge--pwa__wrapper',
tmpl));
wrapper.href = `#${category.id}`;
const allGroups = this._getGroupIds(category.auditRefs);
const passingGroupIds = this._getPassingGroupIds(category.auditRefs);
if (passingGroupIds.size === allGroups.size) {
wrapper.classList.add('lh-badged--all');
} else {
for (const passingGroupId of passingGroupIds) {
wrapper.classList.add(`lh-badged--${passingGroupId}`);
}
}
this.dom.find('.lh-gauge__label', tmpl).textContent = category.title;
return tmpl;
}
/**
* Returns the group IDs found in auditRefs.
* @param {Array<LH.ReportResult.AuditRef>} auditRefs
* @return {Set<string>}
*/
_getGroupIds(auditRefs) {
const groupIds = auditRefs.map(ref => ref.group).filter(/** @return {g is string} */ g => !!g);
return new Set(groupIds);
}
/**
* Returns the group IDs whose audits are all considered passing.
* @param {Array<LH.ReportResult.AuditRef>} auditRefs
* @return {Set<string>}
*/
_getPassingGroupIds(auditRefs) {
const uniqueGroupIds = this._getGroupIds(auditRefs);
// Remove any that have a failing audit.
for (const auditRef of auditRefs) {
if (!Util.showAsPassed(auditRef.result) && auditRef.group) {
uniqueGroupIds.delete(auditRef.group);
}
}
return uniqueGroupIds;
}
/**
* Render non-manual audits in groups, giving a badge to any group that has
* all passing audits.
* @param {Array<LH.ReportResult.AuditRef>} auditRefs
* @param {Object<string, LH.Result.ReportGroup>} groupDefinitions
* @return {Element}
*/
_renderAudits(auditRefs, groupDefinitions) {
const auditsElem = this.renderUnexpandableClump(auditRefs, groupDefinitions);
// Add a 'badged' class to group if all audits in that group pass.
const passsingGroupIds = this._getPassingGroupIds(auditRefs);
for (const groupId of passsingGroupIds) {
const groupElem = this.dom.find(`.lh-audit-group--${groupId}`, auditsElem);
groupElem.classList.add('lh-badged');
}
return auditsElem;
}
}
if (typeof module !== 'undefined' && module.exports) {
module.exports = PwaCategoryRenderer;
} else {
self.PwaCategoryRenderer = PwaCategoryRenderer;
}
...@@ -26,7 +26,7 @@ ...@@ -26,7 +26,7 @@
/** @typedef {import('./dom.js')} DOM */ /** @typedef {import('./dom.js')} DOM */
/** @typedef {import('./details-renderer.js').DetailsJSON} DetailsJSON */ /** @typedef {import('./details-renderer.js').DetailsJSON} DetailsJSON */
/* globals self, Util, DetailsRenderer, CategoryRenderer, PerformanceCategoryRenderer */ /* globals self, Util, DetailsRenderer, CategoryRenderer, PerformanceCategoryRenderer, PwaCategoryRenderer */
class ReportRenderer { class ReportRenderer {
/** /**
...@@ -42,6 +42,7 @@ class ReportRenderer { ...@@ -42,6 +42,7 @@ class ReportRenderer {
/** /**
* @param {LH.Result} result * @param {LH.Result} result
* @param {Element} container Parent element to render the report into. * @param {Element} container Parent element to render the report into.
* @return {Element}
*/ */
renderReport(result, container) { renderReport(result, container) {
// Mutate the UIStrings if necessary (while saving originals) // Mutate the UIStrings if necessary (while saving originals)
...@@ -55,7 +56,7 @@ class ReportRenderer { ...@@ -55,7 +56,7 @@ class ReportRenderer {
// put the UIStrings back into original state // put the UIStrings back into original state
Util.updateAllUIStrings(originalUIStrings); Util.updateAllUIStrings(originalUIStrings);
return /** @type {Element} **/ (container); return container;
} }
/** /**
...@@ -188,24 +189,39 @@ class ReportRenderer { ...@@ -188,24 +189,39 @@ class ReportRenderer {
const detailsRenderer = new DetailsRenderer(this._dom); const detailsRenderer = new DetailsRenderer(this._dom);
const categoryRenderer = new CategoryRenderer(this._dom, detailsRenderer); const categoryRenderer = new CategoryRenderer(this._dom, detailsRenderer);
categoryRenderer.setTemplateContext(this._templateContext); categoryRenderer.setTemplateContext(this._templateContext);
const perfCategoryRenderer = new PerformanceCategoryRenderer(this._dom, detailsRenderer);
perfCategoryRenderer.setTemplateContext(this._templateContext); /** @type {Record<string, CategoryRenderer>} */
const specificCategoryRenderers = {
performance: new PerformanceCategoryRenderer(this._dom, detailsRenderer),
pwa: new PwaCategoryRenderer(this._dom, detailsRenderer),
};
Object.values(specificCategoryRenderers).forEach(renderer => {
renderer.setTemplateContext(this._templateContext);
});
const categories = reportSection.appendChild(this._dom.createElement('div', 'lh-categories')); const categories = reportSection.appendChild(this._dom.createElement('div', 'lh-categories'));
for (const category of report.reportCategories) { for (const category of report.reportCategories) {
if (scoreHeader) { const renderer = specificCategoryRenderers[category.id] || categoryRenderer;
scoreHeader.appendChild(categoryRenderer.renderScoreGauge(category)); categories.appendChild(renderer.render(category, report.categoryGroups));
} }
let renderer = categoryRenderer; if (scoreHeader) {
if (category.id === 'performance') { const defaultGauges = [];
renderer = perfCategoryRenderer; const customGauges = [];
for (const category of report.reportCategories) {
const renderer = specificCategoryRenderers[category.id] || categoryRenderer;
const categoryGauge = renderer.renderScoreGauge(category);
// Group gauges that aren't default at the end of the header
if (renderer.renderScoreGauge === categoryRenderer.renderScoreGauge) {
defaultGauges.push(categoryGauge);
} else {
customGauges.push(categoryGauge);
} }
categories.appendChild(renderer.render(category, report.categoryGroups));
} }
scoreHeader.append(...defaultGauges, ...customGauges);
if (scoreHeader) {
const scoreScale = this._dom.cloneTemplate('#tmpl-lh-scorescale', this._templateContext); const scoreScale = this._dom.cloneTemplate('#tmpl-lh-scorescale', this._templateContext);
this._dom.find('.lh-scorescale-label', scoreScale).textContent = this._dom.find('.lh-scorescale-label', scoreScale).textContent =
Util.UIStrings.scorescaleLabel; Util.UIStrings.scorescaleLabel;
......
...@@ -62,6 +62,15 @@ class Util { ...@@ -62,6 +62,15 @@ class Util {
if (typeof clone.categories !== 'object') throw new Error('No categories provided.'); if (typeof clone.categories !== 'object') throw new Error('No categories provided.');
clone.reportCategories = Object.values(clone.categories); clone.reportCategories = Object.values(clone.categories);
// The proto process turns 'not-applicable' into 'not_applicable'. Correct this to support both.
// TODO: remove when underscore/hyphen proto issue is resolved. See #6371, #6201.
for (const audit of Object.values(clone.audits)) {
// @ts-ignore tsc rightly flags that this value shouldn't occur.
if (audit.scoreDisplayMode === 'not_applicable') {
audit.scoreDisplayMode = 'not-applicable';
}
}
// For convenience, smoosh all AuditResults into their auditDfn (which has just weight & group) // For convenience, smoosh all AuditResults into their auditDfn (which has just weight & group)
for (const category of clone.reportCategories) { for (const category of clone.reportCategories) {
category.auditRefs.forEach(auditMeta => { category.auditRefs.forEach(auditMeta => {
...@@ -398,7 +407,7 @@ class Util { ...@@ -398,7 +407,7 @@ class Util {
networkThrottling = `${Util.formatNumber(requestLatencyMs)}${NBSP}ms HTTP RTT, ` + networkThrottling = `${Util.formatNumber(requestLatencyMs)}${NBSP}ms HTTP RTT, ` +
`${Util.formatNumber(throttling.downloadThroughputKbps)}${NBSP}Kbps down, ` + `${Util.formatNumber(throttling.downloadThroughputKbps)}${NBSP}Kbps down, ` +
`${Util.formatNumber(throttling.uploadThroughputKbps)}${NBSP}Kbps up (DevTools)`; `${Util.formatNumber(throttling.uploadThroughputKbps)}${NBSP}Kbps up (DevTools)`;
summary = 'Throttled Fast 3G network'; summary = 'Throttled Slow 4G network';
break; break;
} }
case 'simulate': { case 'simulate': {
...@@ -406,7 +415,7 @@ class Util { ...@@ -406,7 +415,7 @@ class Util {
cpuThrottling = `${Util.formatNumber(cpuSlowdownMultiplier)}x slowdown (Simulated)`; cpuThrottling = `${Util.formatNumber(cpuSlowdownMultiplier)}x slowdown (Simulated)`;
networkThrottling = `${Util.formatNumber(rttMs)}${NBSP}ms TCP RTT, ` + networkThrottling = `${Util.formatNumber(rttMs)}${NBSP}ms TCP RTT, ` +
`${Util.formatNumber(throughputKbps)}${NBSP}Kbps throughput (Simulated)`; `${Util.formatNumber(throughputKbps)}${NBSP}Kbps throughput (Simulated)`;
summary = 'Simulated Fast 3G network'; summary = 'Simulated Slow 4G network';
break; break;
} }
default: default:
...@@ -484,8 +493,8 @@ Util.UIStrings = { ...@@ -484,8 +493,8 @@ Util.UIStrings = {
/** Label of value shown in the summary of critical request chains. Refers to the total amount of time (milliseconds) of the longest critical path chain/sequence of network requests. Example value: 2310 ms */ /** Label of value shown in the summary of critical request chains. Refers to the total amount of time (milliseconds) of the longest critical path chain/sequence of network requests. Example value: 2310 ms */
crcLongestDurationLabel: 'Maximum critical path latency:', crcLongestDurationLabel: 'Maximum critical path latency:',
/** Explanation shown to users below performance results to inform them that the test was done with a 3G network connection and to warn them that the numbers they see will likely change slightly the next time they run Lighthouse. 'Lighthouse' becomes link text to additional documentation. */ /** Explanation shown to users below performance results to inform them that the test was done with a 4G network connection and to warn them that the numbers they see will likely change slightly the next time they run Lighthouse. 'Lighthouse' becomes link text to additional documentation. */
lsPerformanceCategoryDescription: '[Lighthouse](https://developers.google.com/web/tools/lighthouse/) analysis of the current page on emulated 3G. Values are estimated and may vary.', lsPerformanceCategoryDescription: '[Lighthouse](https://developers.google.com/web/tools/lighthouse/) analysis of the current page on an emulated mobile network. Values are estimated and may vary.',
/** Title of the lab data section of the Performance category. Within this section are various speed metrics which quantify the pageload performance into values presented in seconds and milliseconds. "Lab" is an abbreviated form of "laboratory", and refers to the fact that the data is from a controlled test of a website, not measurements from real users visiting that site. */ /** Title of the lab data section of the Performance category. Within this section are various speed metrics which quantify the pageload performance into values presented in seconds and milliseconds. "Lab" is an abbreviated form of "laboratory", and refers to the fact that the data is from a controlled test of a website, not measurements from real users visiting that site. */
labDataTitle: 'Lab Data', labDataTitle: 'Lab Data',
}; };
......
...@@ -24,6 +24,7 @@ ...@@ -24,6 +24,7 @@
"lighthouse/renderer/dom.js", "lighthouse/renderer/dom.js",
"lighthouse/renderer/category-renderer.js", "lighthouse/renderer/category-renderer.js",
"lighthouse/renderer/performance-category-renderer.js", "lighthouse/renderer/performance-category-renderer.js",
"lighthouse/renderer/pwa-category-renderer.js",
"lighthouse/renderer/details-renderer.js", "lighthouse/renderer/details-renderer.js",
"lighthouse/renderer/crc-details-renderer.js", "lighthouse/renderer/crc-details-renderer.js",
"lighthouse/renderer/report-renderer.js", "lighthouse/renderer/report-renderer.js",
...@@ -48,6 +49,7 @@ ...@@ -48,6 +49,7 @@
"lighthouse/renderer/dom.js", "lighthouse/renderer/dom.js",
"lighthouse/renderer/category-renderer.js", "lighthouse/renderer/category-renderer.js",
"lighthouse/renderer/performance-category-renderer.js", "lighthouse/renderer/performance-category-renderer.js",
"lighthouse/renderer/pwa-category-renderer.js",
"lighthouse/renderer/details-renderer.js", "lighthouse/renderer/details-renderer.js",
"lighthouse/renderer/crc-details-renderer.js", "lighthouse/renderer/crc-details-renderer.js",
"lighthouse/renderer/report-renderer.js" "lighthouse/renderer/report-renderer.js"
......
...@@ -10,10 +10,10 @@ ...@@ -10,10 +10,10 @@
} }
], ],
"scripts": [ "scripts": [
"lighthouse/lighthouse-background.js", "lighthouse/lighthouse-dt-bundle.js",
"Audits2Service.js" "Audits2Service.js"
], ],
"skip_compilation": [ "skip_compilation": [
"lighthouse/lighthouse-background.js" "lighthouse/lighthouse-dt-bundle.js"
] ]
} }
...@@ -399,7 +399,7 @@ function renameIdentifiers(identifierMap) { ...@@ -399,7 +399,7 @@ function renameIdentifiers(identifierMap) {
return; return;
if (filePath.includes('externs.js')) if (filePath.includes('externs.js'))
return; return;
if (filePath.includes('eslint') || filePath.includes('lighthouse-background.js') || filePath.includes('/cm/') || if (filePath.includes('eslint') || filePath.includes('lighthouse-dt-bundle.js') || filePath.includes('/cm/') ||
filePath.includes('/xterm.js/') || filePath.includes('/acorn/')) filePath.includes('/xterm.js/') || filePath.includes('/acorn/'))
return; return;
if (filePath.includes('/cm_modes/') && !filePath.includes('DefaultCodeMirror') && if (filePath.includes('/cm_modes/') && !filePath.includes('DefaultCodeMirror') &&
......
...@@ -12,10 +12,76 @@ Run audits: enabled visible ...@@ -12,10 +12,76 @@ Run audits: enabled visible
=============== Lighthouse Status Updates =============== =============== Lighthouse Status Updates ===============
Loading… Loading…
Create config
Requiring gatherers
Requiring audits
Runner setup
Connecting to browser
Getting browser version
Resetting state with about:blank
Benchmarking machine
Initializing… Initializing…
Running beforePass methods
Retrieving setup: Scripts
Retrieving setup: CSSUsage
Retrieving setup: Viewport
Retrieving setup: ViewportDimensions
Retrieving setup: ThemeColor
Retrieving setup: Manifest
Retrieving setup: RuntimeExceptions
Retrieving setup: ChromeConsoleMessages
Retrieving setup: ImageUsage
Retrieving setup: Accessibility
Retrieving setup: AnchorsWithNoRelNoopener
Retrieving setup: AppCacheManifest
Retrieving setup: Doctype
Retrieving setup: DOMStats
Retrieving setup: JSLibraries
Retrieving setup: OptimizedImages
Retrieving setup: PasswordInputsWithPreventedPaste
Retrieving setup: ResponseCompression
Retrieving setup: TagsBlockingFirstPaint
Retrieving setup: MetaDescription
Retrieving setup: FontSize
Retrieving setup: CrawlableLinks
Retrieving setup: MetaRobots
Retrieving setup: Hreflang
Retrieving setup: EmbeddedContent
Retrieving setup: Canonical
Retrieving setup: RobotsTxt
Loading page & waiting for onload Loading page & waiting for onload
Getting browser version
Running pass methods
Retrieving in-page: Scripts
Retrieving in-page: CSSUsage
Retrieving in-page: Viewport
Retrieving in-page: ViewportDimensions
Retrieving in-page: ThemeColor
Retrieving in-page: Manifest
Retrieving in-page: RuntimeExceptions
Retrieving in-page: ChromeConsoleMessages
Retrieving in-page: ImageUsage
Retrieving in-page: Accessibility
Retrieving in-page: AnchorsWithNoRelNoopener
Retrieving in-page: AppCacheManifest
Retrieving in-page: Doctype
Retrieving in-page: DOMStats
Retrieving in-page: JSLibraries
Retrieving in-page: OptimizedImages
Retrieving in-page: PasswordInputsWithPreventedPaste
Retrieving in-page: ResponseCompression
Retrieving in-page: TagsBlockingFirstPaint
Retrieving in-page: MetaDescription
Retrieving in-page: FontSize
Retrieving in-page: CrawlableLinks
Retrieving in-page: MetaRobots
Retrieving in-page: Hreflang
Retrieving in-page: EmbeddedContent
Retrieving in-page: Canonical
Retrieving in-page: RobotsTxt
Retrieving trace Retrieving trace
Retrieving devtoolsLog and network records Retrieving devtoolsLog & network records
Running afterPass methods
Retrieving: Scripts Retrieving: Scripts
Retrieving: CSSUsage Retrieving: CSSUsage
Retrieving: Viewport Retrieving: Viewport
...@@ -35,7 +101,6 @@ Retrieving: OptimizedImages ...@@ -35,7 +101,6 @@ Retrieving: OptimizedImages
Retrieving: PasswordInputsWithPreventedPaste Retrieving: PasswordInputsWithPreventedPaste
Retrieving: ResponseCompression Retrieving: ResponseCompression
Retrieving: TagsBlockingFirstPaint Retrieving: TagsBlockingFirstPaint
Retrieving: WebSQL
Retrieving: MetaDescription Retrieving: MetaDescription
Retrieving: FontSize Retrieving: FontSize
Retrieving: CrawlableLinks Retrieving: CrawlableLinks
...@@ -44,52 +109,87 @@ Retrieving: Hreflang ...@@ -44,52 +109,87 @@ Retrieving: Hreflang
Retrieving: EmbeddedContent Retrieving: EmbeddedContent
Retrieving: Canonical Retrieving: Canonical
Retrieving: RobotsTxt Retrieving: RobotsTxt
Retrieving: Fonts Resetting state with about:blank
Running beforePass methods
Retrieving setup: ServiceWorker
Retrieving setup: Offline
Retrieving setup: StartUrl
Loading page & waiting for onload Loading page & waiting for onload
Retrieving devtoolsLog and network records Running pass methods
Retrieving in-page: ServiceWorker
Retrieving in-page: Offline
Retrieving in-page: StartUrl
Retrieving devtoolsLog & network records
Running afterPass methods
Retrieving: ServiceWorker Retrieving: ServiceWorker
Retrieving: Offline Retrieving: Offline
Retrieving: StartUrl Retrieving: StartUrl
Resetting state with about:blank
Running beforePass methods
Retrieving setup: HTTPRedirect
Retrieving setup: HTMLWithoutJavaScript
Loading page & waiting for onload Loading page & waiting for onload
Retrieving devtoolsLog and network records Running pass methods
Retrieving in-page: HTTPRedirect
Retrieving in-page: HTMLWithoutJavaScript
Retrieving devtoolsLog & network records
Running afterPass methods
Retrieving: HTTPRedirect Retrieving: HTTPRedirect
Retrieving: HTMLWithoutJavaScript Retrieving: HTMLWithoutJavaScript
Disconnecting from browser... Disconnecting from browser...
Analyzing and running audits... Analyzing and running audits...
Evaluating: Uses HTTPS Evaluating: Uses HTTPS
Computing artifact: NetworkRecords
Evaluating: Redirects HTTP traffic to HTTPS Evaluating: Redirects HTTP traffic to HTTPS
Evaluating: Registers a service worker Evaluating: Registers a service worker
Evaluating: Responds with a 200 when offline Evaluating: Current page responds with a 200 when offline
Evaluating: Has a `<meta name="viewport">` tag with `width` or `initial-scale` Evaluating: Has a `<meta name="viewport">` tag with `width` or `initial-scale`
Evaluating: Contains some content when JavaScript is not available Evaluating: Contains some content when JavaScript is not available
Evaluating: First Contentful Paint Evaluating: First Contentful Paint
Computing artifact: FirstContentfulPaint
Computing artifact: TraceOfTab
Evaluating: First Meaningful Paint Evaluating: First Meaningful Paint
Evaluating: Page load is fast enough on 3G Computing artifact: FirstMeaningfulPaint
Evaluating: Page load is fast enough on mobile networks
Computing artifact: Interactive
Evaluating: Speed Index Evaluating: Speed Index
Computing artifact: SpeedIndex
Evaluating: Screenshot Thumbnails Evaluating: Screenshot Thumbnails
Computing artifact: Speedline
Evaluating: Final Screenshot Evaluating: Final Screenshot
Computing artifact: Screenshots
Evaluating: Estimated Input Latency Evaluating: Estimated Input Latency
Computing artifact: EstimatedInputLatency
Evaluating: No browser errors logged to the console Evaluating: No browser errors logged to the console
Evaluating: Server response times are low (TTFB) Evaluating: Server response times are low (TTFB)
Computing artifact: MainResource
Evaluating: First CPU Idle Evaluating: First CPU Idle
Computing artifact: FirstCPUIdle
Evaluating: Time to Interactive Evaluating: Time to Interactive
Evaluating: User Timing marks and measures Evaluating: User Timing marks and measures
Evaluating: Minimize Critical Requests Depth Evaluating: Minimize Critical Requests Depth
Computing artifact: CriticalRequestChains
Evaluating: Avoid multiple page redirects Evaluating: Avoid multiple page redirects
Evaluating: User can be prompted to Install the Web App Evaluating: Web app manifest meets the installability requirements
Computing artifact: ManifestValues
Evaluating: Configured for a custom splash screen Evaluating: Configured for a custom splash screen
Evaluating: Address bar matches brand colors Evaluating: Sets an address-bar theme color
Evaluating: The `short_name` won't be truncated on the homescreen
Evaluating: Content is sized correctly for the viewport Evaluating: Content is sized correctly for the viewport
Evaluating: Displays images with correct aspect ratio Evaluating: Displays images with correct aspect ratio
Evaluating: Avoids deprecated APIs Evaluating: Avoids deprecated APIs
Evaluating: Minimizes main-thread work Evaluating: Minimizes main-thread work
Computing artifact: MainThreadTasks
Evaluating: JavaScript execution time Evaluating: JavaScript execution time
Evaluating: Preload key requests Evaluating: Preload key requests
Computing artifact: PageDependencyGraph
Computing artifact: LoadSimulator
Computing artifact: NetworkAnalysis
Evaluating: Preconnect to required origins Evaluating: Preconnect to required origins
Computing artifact: LoadSimulator
Evaluating: All text remains visible during webfont loads Evaluating: All text remains visible during webfont loads
Evaluating: Network Requests Evaluating: Network Requests
Evaluating: Metrics Evaluating: Metrics
Evaluating: start_url responds with a 200 when offline
Evaluating: Site works cross-browser Evaluating: Site works cross-browser
Evaluating: Page transitions don't feel like they block on the network Evaluating: Page transitions don't feel like they block on the network
Evaluating: Each page has a URL Evaluating: Each page has a URL
...@@ -159,7 +259,6 @@ Evaluating: Avoids requesting the geolocation permission on page load ...@@ -159,7 +259,6 @@ Evaluating: Avoids requesting the geolocation permission on page load
Evaluating: Avoids `document.write()` Evaluating: Avoids `document.write()`
Evaluating: Avoids front-end JavaScript libraries with known security vulnerabilities Evaluating: Avoids front-end JavaScript libraries with known security vulnerabilities
Evaluating: Detected JavaScript libraries Evaluating: Detected JavaScript libraries
Evaluating: Avoids WebSQL DB
Evaluating: Avoids requesting the notification permission on page load Evaluating: Avoids requesting the notification permission on page load
Evaluating: Allows users to paste into password fields Evaluating: Allows users to paste into password fields
Evaluating: Uses HTTP/2 for its own resources Evaluating: Uses HTTP/2 for its own resources
...@@ -179,7 +278,7 @@ Generating results... ...@@ -179,7 +278,7 @@ Generating results...
=============== Lighthouse Results =============== =============== Lighthouse Results ===============
URL: http://127.0.0.1:8000/devtools/resources/inspected-page.html URL: http://127.0.0.1:8000/devtools/resources/inspected-page.html
Version: 3.2.0 Version: 4.0.0-beta
accesskeys: not-applicable accesskeys: not-applicable
...@@ -230,6 +329,7 @@ http-status-code: pass ...@@ -230,6 +329,7 @@ http-status-code: pass
image-alt: not-applicable image-alt: not-applicable
image-aspect-ratio: pass image-aspect-ratio: pass
input-image-alt: not-applicable input-image-alt: not-applicable
installable-manifest: fail
interactive: flaky interactive: flaky
interactive-element-affordance: manual interactive-element-affordance: manual
is-crawlable: pass is-crawlable: pass
...@@ -245,7 +345,6 @@ load-fast-enough-for-pwa: flaky ...@@ -245,7 +345,6 @@ load-fast-enough-for-pwa: flaky
logical-tab-order: manual logical-tab-order: manual
mainthread-work-breakdown: ERROR Something went wrong with recording the trace over your page load. Please run Lighthouse again. (NO_FCP) mainthread-work-breakdown: ERROR Something went wrong with recording the trace over your page load. Please run Lighthouse again. (NO_FCP)
managed-focus: manual managed-focus: manual
manifest-short-name-length: not-applicable
meta-description: fail meta-description: fail
meta-refresh: not-applicable meta-refresh: not-applicable
meta-viewport: not-applicable meta-viewport: not-applicable
...@@ -254,9 +353,9 @@ mobile-friendly: manual ...@@ -254,9 +353,9 @@ mobile-friendly: manual
network-requests: informative network-requests: informative
no-document-write: pass no-document-write: pass
no-vulnerable-libraries: pass no-vulnerable-libraries: pass
no-websql: pass
notification-on-start: pass notification-on-start: pass
object-alt: not-applicable object-alt: not-applicable
offline-start-url: fail
offscreen-content-hidden: manual offscreen-content-hidden: manual
offscreen-images: flaky offscreen-images: flaky
password-inputs-can-be-pasted-into: pass password-inputs-can-be-pasted-into: pass
...@@ -298,9 +397,8 @@ video-caption: not-applicable ...@@ -298,9 +397,8 @@ video-caption: not-applicable
video-description: not-applicable video-description: not-applicable
viewport: fail viewport: fail
visual-order-follows-dom: manual visual-order-follows-dom: manual
webapp-install-banner: fail
without-javascript: fail without-javascript: fail
works-offline: fail works-offline: fail
# of .lh-audit divs: 112 # of .lh-audit divs: 111
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment