lighthouse 9.5.0-dev.20230116 → 9.5.0-dev.20230118

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/.codecov.yml CHANGED
@@ -20,3 +20,8 @@ coverage:
20
20
  patch:
21
21
  default:
22
22
  if_not_found: success
23
+
24
+ # docs:
25
+ # https://docs.codecov.com/docs/ignoring-paths
26
+ ignore:
27
+ - "core/util.cjs" # file is a copy of report/renderer/util.js
@@ -15,7 +15,6 @@ import {BaseNode} from '../../lib/dependency-graph/base-node.js';
15
15
  import {ByteEfficiencyAudit} from './byte-efficiency-audit.js';
16
16
  import {UnusedCSS} from '../../computed/unused-css.js';
17
17
  import {NetworkRequest} from '../../lib/network-request.js';
18
- import {ProcessedTrace} from '../../computed/processed-trace.js';
19
18
  import {ProcessedNavigation} from '../../computed/processed-navigation.js';
20
19
  import {LoadSimulator} from '../../computed/load-simulator.js';
21
20
  import {FirstContentfulPaint} from '../../computed/metrics/first-contentful-paint.js';
@@ -133,8 +132,7 @@ class RenderBlockingResources extends Audit {
133
132
  const trace = artifacts.traces[Audit.DEFAULT_PASS];
134
133
  const devtoolsLog = artifacts.devtoolsLogs[Audit.DEFAULT_PASS];
135
134
  const simulatorData = {devtoolsLog, settings: context.settings};
136
- const processedTrace = await ProcessedTrace.request(trace, context);
137
- const processedNavigation = await ProcessedNavigation.request(processedTrace, context);
135
+ const processedNavigation = await ProcessedNavigation.request(trace, context);
138
136
  const simulator = await LoadSimulator.request(simulatorData, context);
139
137
  const wastedCssBytes = await RenderBlockingResources.computeWastedCSSBytes(artifacts, context);
140
138
 
@@ -11,7 +11,6 @@ import * as i18n from '../lib/i18n/i18n.js';
11
11
  import {NetworkRecords} from '../computed/network-records.js';
12
12
  import {MainResource} from '../computed/main-resource.js';
13
13
  import {LoadSimulator} from '../computed/load-simulator.js';
14
- import {ProcessedTrace} from '../computed/processed-trace.js';
15
14
  import {ProcessedNavigation} from '../computed/processed-navigation.js';
16
15
  import {PageDependencyGraph} from '../computed/page-dependency-graph.js';
17
16
  import {LanternLargestContentfulPaint} from '../computed/metrics/lantern-largest-contentful-paint.js';
@@ -113,14 +112,12 @@ class UsesRelPreconnectAudit extends Audit {
113
112
  /** @type {Array<LH.IcuMessage>} */
114
113
  const warnings = [];
115
114
 
116
- const processedTrace = await ProcessedTrace.request(trace, context);
117
-
118
115
  const [networkRecords, mainResource, loadSimulator, processedNavigation, pageGraph] =
119
116
  await Promise.all([
120
117
  NetworkRecords.request(devtoolsLog, context),
121
118
  MainResource.request({devtoolsLog, URL: artifacts.URL}, context),
122
119
  LoadSimulator.request({devtoolsLog, settings}, context),
123
- ProcessedNavigation.request(processedTrace, context),
120
+ ProcessedNavigation.request(trace, context),
124
121
  PageDependencyGraph.request({trace, devtoolsLog, URL: artifacts.URL}, context),
125
122
  ]);
126
123
 
@@ -6,7 +6,6 @@
6
6
 
7
7
  import {BaseNode} from '../../lib/dependency-graph/base-node.js';
8
8
  import {NetworkRequest} from '../../lib/network-request.js';
9
- import {ProcessedTrace} from '../processed-trace.js';
10
9
  import {ProcessedNavigation} from '../processed-navigation.js';
11
10
  import {PageDependencyGraph} from '../page-dependency-graph.js';
12
11
  import {LoadSimulator} from '../load-simulator.js';
@@ -106,8 +105,7 @@ class LanternMetric {
106
105
 
107
106
  const metricName = this.name.replace('Lantern', '');
108
107
  const graph = await PageDependencyGraph.request(data, context);
109
- const processedTrace = await ProcessedTrace.request(data.trace, context);
110
- const processedNavigation = await ProcessedNavigation.request(processedTrace, context);
108
+ const processedNavigation = await ProcessedNavigation.request(data.trace, context);
111
109
  const simulator = data.simulator || (await LoadSimulator.request(data, context));
112
110
 
113
111
  const optimisticGraph = this.getOptimisticGraph(graph, processedNavigation);
@@ -70,7 +70,7 @@ class Metric {
70
70
 
71
71
  const processedTrace = await ProcessedTrace.request(trace, context);
72
72
  const processedNavigation = gatherContext.gatherMode === 'timespan' ?
73
- undefined : await ProcessedNavigation.request(processedTrace, context);
73
+ undefined : await ProcessedNavigation.request(trace, context);
74
74
 
75
75
  const augmentedData = Object.assign({
76
76
  networkRecords: await NetworkRecords.request(devtoolsLog, context),
@@ -45,7 +45,7 @@ class TimingSummary {
45
45
  /* eslint-disable max-len */
46
46
 
47
47
  const processedTrace = await ProcessedTrace.request(trace, context);
48
- const processedNavigation = await requestOrUndefined(ProcessedNavigation, processedTrace);
48
+ const processedNavigation = await requestOrUndefined(ProcessedNavigation, trace);
49
49
  const speedline = await Speedline.request(trace, context);
50
50
  const firstContentfulPaint = await requestOrUndefined(FirstContentfulPaint, metricComputationData);
51
51
  const firstContentfulPaintAllFrames = await requestOrUndefined(FirstContentfulPaintAllFrames, metricComputationData);
@@ -5,14 +5,17 @@
5
5
  */
6
6
 
7
7
  import {makeComputedArtifact} from './computed-artifact.js';
8
+ import {ProcessedTrace} from './processed-trace.js';
8
9
  import LHTraceProcessor from '../lib/lh-trace-processor.js';
9
10
 
10
11
  class ProcessedNavigation {
11
12
  /**
12
- * @param {LH.Artifacts.ProcessedTrace} processedTrace
13
+ * @param {LH.Trace} trace
14
+ * @param {LH.Artifacts.ComputedContext} context
13
15
  * @return {Promise<LH.Artifacts.ProcessedNavigation>}
14
16
  */
15
- static async compute_(processedTrace) {
17
+ static async compute_(trace, context) {
18
+ const processedTrace = await ProcessedTrace.request(trace, context);
16
19
  return LHTraceProcessor.processNavigation(processedTrace);
17
20
  }
18
21
  }
@@ -465,14 +465,14 @@ const defaultConfig = {
465
465
  supportedModes: ['navigation', 'timespan', 'snapshot'],
466
466
  auditRefs: [
467
467
  {id: 'first-contentful-paint', weight: 10, group: 'metrics', acronym: 'FCP', relevantAudits: metricsToAudits.fcpRelevantAudits},
468
- {id: 'interactive', weight: 10, group: 'metrics', acronym: 'TTI'},
469
- {id: 'speed-index', weight: 10, group: 'metrics', acronym: 'SI'},
470
- {id: 'total-blocking-time', weight: 30, group: 'metrics', acronym: 'TBT', relevantAudits: metricsToAudits.tbtRelevantAudits},
471
468
  {id: 'largest-contentful-paint', weight: 25, group: 'metrics', acronym: 'LCP', relevantAudits: metricsToAudits.lcpRelevantAudits},
472
- {id: 'cumulative-layout-shift', weight: 15, group: 'metrics', acronym: 'CLS', relevantAudits: metricsToAudits.clsRelevantAudits},
469
+ {id: 'total-blocking-time', weight: 30, group: 'metrics', acronym: 'TBT', relevantAudits: metricsToAudits.tbtRelevantAudits},
470
+ {id: 'cumulative-layout-shift', weight: 25, group: 'metrics', acronym: 'CLS', relevantAudits: metricsToAudits.clsRelevantAudits},
471
+ {id: 'speed-index', weight: 10, group: 'metrics', acronym: 'SI'},
473
472
  {id: 'experimental-interaction-to-next-paint', weight: 0, group: 'metrics', acronym: 'INP', relevantAudits: metricsToAudits.inpRelevantAudits},
474
473
 
475
474
  // These are our "invisible" metrics. Not displayed, but still in the LHR.
475
+ {id: 'interactive', weight: 0, group: 'hidden', acronym: 'TTI'},
476
476
  {id: 'max-potential-fid', weight: 0, group: 'hidden'},
477
477
  {id: 'first-meaningful-paint', weight: 0, acronym: 'FMP', group: 'hidden'},
478
478
 
@@ -39,10 +39,7 @@ async function getBaseArtifacts(resolvedConfig, driver, context) {
39
39
  PageLoadError: null,
40
40
  GatherContext: context,
41
41
  // Artifacts that have been replaced by regular gatherers in Fraggle Rock.
42
- Stacks: [],
43
42
  NetworkUserAgent: '',
44
- WebAppManifest: null,
45
- InstallabilityErrors: {errors: []},
46
43
  traces: {},
47
44
  devtoolsLogs: {},
48
45
  };
@@ -38,10 +38,18 @@ class InstallabilityErrors extends FRGatherer {
38
38
  * @param {LH.Gatherer.FRTransitionalContext} context
39
39
  * @return {Promise<LH.Artifacts['InstallabilityErrors']>}
40
40
  */
41
- getArtifact(context) {
41
+ async getArtifact(context) {
42
42
  const driver = context.driver;
43
43
 
44
- return InstallabilityErrors.getInstallabilityErrors(driver.defaultSession);
44
+ try {
45
+ return await InstallabilityErrors.getInstallabilityErrors(driver.defaultSession);
46
+ } catch {
47
+ return {
48
+ errors: [
49
+ {errorId: 'protocol-timeout', errorArguments: []},
50
+ ],
51
+ };
52
+ }
45
53
  }
46
54
  }
47
55
 
@@ -126,7 +126,11 @@ class Stacks extends FRGatherer {
126
126
  * @return {Promise<LH.Artifacts['Stacks']>}
127
127
  */
128
128
  async getArtifact(context) {
129
- return Stacks.collectStacks(context.driver.executionContext);
129
+ try {
130
+ return await Stacks.collectStacks(context.driver.executionContext);
131
+ } catch {
132
+ return [];
133
+ }
130
134
  }
131
135
  }
132
136
 
@@ -213,14 +213,14 @@ class TraceElements extends FRGatherer {
213
213
  }
214
214
 
215
215
  /**
216
- * @param {LH.Artifacts.ProcessedTrace} processedTrace
216
+ * @param {LH.Trace} trace
217
217
  * @param {LH.Gatherer.FRTransitionalContext} context
218
218
  * @return {Promise<{nodeId: number, type: string} | undefined>}
219
219
  */
220
- static async getLcpElement(processedTrace, context) {
220
+ static async getLcpElement(trace, context) {
221
221
  let processedNavigation;
222
222
  try {
223
- processedNavigation = await ProcessedNavigation.request(processedTrace, context);
223
+ processedNavigation = await ProcessedNavigation.request(trace, context);
224
224
  } catch (err) {
225
225
  // If we were running in timespan mode and there was no paint, treat LCP as missing.
226
226
  if (context.gatherMode === 'timespan' && err.code === LighthouseError.errors.NO_FCP.code) {
@@ -270,7 +270,7 @@ class TraceElements extends FRGatherer {
270
270
  const processedTrace = await ProcessedTrace.request(trace, context);
271
271
  const {mainThreadEvents} = processedTrace;
272
272
 
273
- const lcpNodeData = await TraceElements.getLcpElement(processedTrace, context);
273
+ const lcpNodeData = await TraceElements.getLcpElement(trace, context);
274
274
  const clsNodeData = TraceElements.getTopLayoutShiftElements(mainThreadEvents);
275
275
  const animatedElementData = await this.getAnimatedElements(mainThreadEvents);
276
276
  const responsivenessElementData = await TraceElements.getResponsivenessElement(trace, context);
@@ -92,10 +92,14 @@ class WebAppManifest extends FRGatherer {
92
92
  * @param {LH.Gatherer.FRTransitionalContext} context
93
93
  * @return {Promise<LH.Artifacts['WebAppManifest']>}
94
94
  */
95
- getArtifact(context) {
95
+ async getArtifact(context) {
96
96
  const driver = context.driver;
97
97
  const {finalDisplayedUrl} = context.baseArtifacts.URL;
98
- return WebAppManifest.getWebAppManifest(driver.defaultSession, finalDisplayedUrl);
98
+ try {
99
+ return await WebAppManifest.getWebAppManifest(driver.defaultSession, finalDisplayedUrl);
100
+ } catch {
101
+ return null;
102
+ }
99
103
  }
100
104
  }
101
105
 
@@ -41,10 +41,7 @@ const BASE_ARTIFACT_BLANKS = {
41
41
  NetworkUserAgent: '',
42
42
  BenchmarkIndex: '',
43
43
  BenchmarkIndexes: '',
44
- WebAppManifest: '',
45
44
  GatherContext: '',
46
- InstallabilityErrors: '',
47
- Stacks: '',
48
45
  traces: '',
49
46
  devtoolsLogs: '',
50
47
  settings: '',
@@ -54,6 +51,15 @@ const BASE_ARTIFACT_BLANKS = {
54
51
  };
55
52
  const BASE_ARTIFACT_NAMES = Object.keys(BASE_ARTIFACT_BLANKS);
56
53
 
54
+ // These were legacy base artifacts, but we need certain gatherers (e.g. bfcache) to run after them.
55
+ // The order is controlled by the config, but still need to force them to run every time.
56
+ const alwaysRunArtifactIds = [
57
+ 'WebAppManifest',
58
+ 'InstallabilityErrors',
59
+ 'Stacks',
60
+ 'FullPageScreenshot',
61
+ ];
62
+
57
63
  /**
58
64
  * @param {LegacyResolvedConfig['passes']} passes
59
65
  * @param {LegacyResolvedConfig['audits']} audits
@@ -79,7 +85,8 @@ function assertValidPasses(passes, audits) {
79
85
  const gatherer = gathererDefn.instance;
80
86
  foundGatherers.add(gatherer.name);
81
87
  const isGatherRequiredByAudits = requestedGatherers.has(gatherer.name);
82
- if (!isGatherRequiredByAudits && gatherer.name !== 'FullPageScreenshot') {
88
+ const isAlwaysRunArtifact = alwaysRunArtifactIds.includes(gatherer.name);
89
+ if (!isGatherRequiredByAudits && !isAlwaysRunArtifact) {
83
90
  const msg = `${gatherer.name} gatherer requested, however no audit requires it.`;
84
91
  log.warn('config', msg);
85
92
  }
@@ -328,10 +335,13 @@ class LegacyResolvedConfig {
328
335
 
329
336
  // 3. Resolve which gatherers will need to run
330
337
  const requestedGathererIds = LegacyResolvedConfig.getGatherersRequestedByAudits(audits);
338
+ for (const gathererId of alwaysRunArtifactIds) {
339
+ requestedGathererIds.add(gathererId);
340
+ }
331
341
 
332
- // Always include FullPageScreenshot, unless explictly told not to.
333
- if (!settings.disableFullPageScreenshot) {
334
- requestedGathererIds.add('FullPageScreenshot');
342
+ // Remove FullPageScreenshot if we explicitly exclude it.
343
+ if (settings.disableFullPageScreenshot) {
344
+ requestedGathererIds.delete('FullPageScreenshot');
335
345
  }
336
346
 
337
347
  // 4. Filter to only the neccessary passes
@@ -70,6 +70,9 @@ legacyDefaultConfig.passes = [{
70
70
  'trace-elements',
71
71
  'inspector-issues',
72
72
  'source-maps',
73
+ 'web-app-manifest',
74
+ 'installability-errors',
75
+ 'stacks',
73
76
  'full-page-screenshot',
74
77
  'bf-cache-failures',
75
78
  ],
@@ -16,10 +16,7 @@ import * as prepare from '../../gather/driver/prepare.js';
16
16
  import * as storage from '../../gather/driver/storage.js';
17
17
  import * as navigation from '../../gather/driver/navigation.js';
18
18
  import * as serviceWorkers from '../../gather/driver/service-workers.js';
19
- import WebAppManifest from '../../gather/gatherers/web-app-manifest.js';
20
- import InstallabilityErrors from '../../gather/gatherers/installability-errors.js';
21
19
  import NetworkUserAgent from '../../gather/gatherers/network-user-agent.js';
22
- import Stacks from '../../gather/gatherers/stacks.js';
23
20
  import {finalizeArtifacts} from '../../gather/base-artifacts.js';
24
21
  import UrlUtils from '../../lib/url-utils.js';
25
22
 
@@ -395,9 +392,6 @@ class GatherRunner {
395
392
  HostUserAgent: hostUserAgent,
396
393
  NetworkUserAgent: '', // updated later
397
394
  BenchmarkIndex: 0, // updated later
398
- WebAppManifest: null, // updated later
399
- InstallabilityErrors: {errors: []}, // updated later
400
- Stacks: [], // updated later
401
395
  traces: {},
402
396
  devtoolsLogs: {},
403
397
  settings: options.settings,
@@ -424,37 +418,6 @@ class GatherRunner {
424
418
 
425
419
  const baseArtifacts = passContext.baseArtifacts;
426
420
 
427
- // Fetch the manifest, if it exists.
428
- try {
429
- baseArtifacts.WebAppManifest = await WebAppManifest.getWebAppManifest(
430
- passContext.driver.defaultSession, passContext.url);
431
- } catch (err) {
432
- log.error('GatherRunner WebAppManifest', err);
433
- baseArtifacts.WebAppManifest = null;
434
- }
435
-
436
- try {
437
- baseArtifacts.InstallabilityErrors = await InstallabilityErrors.getInstallabilityErrors(
438
- passContext.driver.defaultSession);
439
- } catch (err) {
440
- log.error('GatherRunner InstallabilityErrors', err);
441
- baseArtifacts.InstallabilityErrors = {
442
- errors: [
443
- {
444
- errorId: 'protocol-timeout',
445
- errorArguments: [],
446
- },
447
- ],
448
- };
449
- }
450
-
451
- try {
452
- baseArtifacts.Stacks = await Stacks.collectStacks(passContext.driver.executionContext);
453
- } catch (err) {
454
- log.error('GatherRunner Stacks', err);
455
- baseArtifacts.Stacks = [];
456
- }
457
-
458
421
  // Find the NetworkUserAgent actually used in the devtoolsLogs.
459
422
  const devtoolsLog = baseArtifacts.devtoolsLogs[passContext.passConfig.passName];
460
423
  baseArtifacts.NetworkUserAgent = NetworkUserAgent.getNetworkUserAgent(devtoolsLog);
@@ -63,10 +63,12 @@ const stackPacksToInclude = [
63
63
 
64
64
  /**
65
65
  * Returns all packs that match the stacks found in the page.
66
- * @param {LH.Artifacts['Stacks']} pageStacks
66
+ * @param {LH.Artifacts['Stacks']|undefined} pageStacks
67
67
  * @return {LH.RawIcu<Array<LH.Result.StackPack>>}
68
68
  */
69
69
  function getStackPacks(pageStacks) {
70
+ if (!pageStacks) return [];
71
+
70
72
  /** @type {LH.RawIcu<Array<LH.Result.StackPack>>} */
71
73
  const packs = [];
72
74
 
@@ -3840,8 +3840,10 @@ class PerformanceCategoryRenderer extends CategoryRenderer {
3840
3840
  _getScoringCalculatorHref(auditRefs) {
3841
3841
  // TODO: filter by !!acronym when dropping renderer support of v7 LHRs.
3842
3842
  const metrics = auditRefs.filter(audit => audit.group === 'metrics');
3843
+ const tti = auditRefs.find(audit => audit.id === 'interactive');
3843
3844
  const fci = auditRefs.find(audit => audit.id === 'first-cpu-idle');
3844
3845
  const fmp = auditRefs.find(audit => audit.id === 'first-meaningful-paint');
3846
+ if (tti) metrics.push(tti);
3845
3847
  if (fci) metrics.push(fci);
3846
3848
  if (fmp) metrics.push(fmp);
3847
3849
 
@@ -117,7 +117,7 @@ class Ca{constructor(e,a){this._document=e,this._lighthouseChannel="unknown",thi
117
117
  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
118
118
  * See the License for the specific language governing permissions and
119
119
  * limitations under the License.
120
- */class La extends wa{_renderMetric(e){const a=this.dom.createComponent("metric"),n=this.dom.find(".lh-metric",a);n.id=e.result.id;const t=de.calculateRating(e.result.score,e.result.scoreDisplayMode);n.classList.add(`lh-metric--${t}`);this.dom.find(".lh-metric__title",a).textContent=e.result.title;const i=this.dom.find(".lh-metric__value",a);i.textContent=e.result.displayValue||"";const o=this.dom.find(".lh-metric__description",a);if(o.append(this.dom.convertMarkdownLinkSnippets(e.result.description)),"error"===e.result.scoreDisplayMode){o.textContent="",i.textContent="Error!";this.dom.createChildOf(o,"span").textContent=e.result.errorMessage||"Report error: no metric information"}else"notApplicable"===e.result.scoreDisplayMode&&(i.textContent="--");return n}_renderOpportunity(e,a){const n=this.dom.createComponent("opportunity"),t=this.populateAuditValues(e,n);if(t.id=e.result.id,!e.result.details||"error"===e.result.scoreDisplayMode)return t;const i=e.result.details;if("opportunity"!==i.type)return t;const o=this.dom.find("span.lh-audit__display-text, div.lh-audit__display-text",t),r=i.overallSavingsMs/a*100+"%";if(this.dom.find("div.lh-sparkline__bar",t).style.width=r,o.textContent=de.i18n.formatSeconds(i.overallSavingsMs,.01),e.result.displayValue){const a=e.result.displayValue;this.dom.find("div.lh-load-opportunity__sparkline",t).title=a,o.title=a}return t}_getWastedMs(e){if(e.result.details&&"opportunity"===e.result.details.type){const a=e.result.details;if("number"!=typeof a.overallSavingsMs)throw new Error("non-opportunity details passed to _getWastedMs");return a.overallSavingsMs}return Number.MIN_VALUE}_getScoringCalculatorHref(e){const a=e.filter((e=>"metrics"===e.group)),n=e.find((e=>"first-cpu-idle"===e.id)),t=e.find((e=>"first-meaningful-paint"===e.id));n&&a.push(n),t&&a.push(t);const i=[...a.map((e=>{let a;var n;return"number"==typeof e.result.numericValue?(a="cumulative-layout-shift"===e.id?(n=e.result.numericValue,Math.round(100*n)/100):Math.round(e.result.numericValue),a=a.toString()):a="null",[e.acronym||e.id,a]}))];de.reportJson&&(i.push(["device",de.reportJson.configSettings.formFactor]),i.push(["version",de.reportJson.lighthouseVersion]));const o=new URLSearchParams(i),r=new URL("https://googlechrome.github.io/lighthouse/scorecalc/");return r.hash=o.toString(),r.href}_classifyPerformanceAudit(e){return e.group?null:e.result.details&&"opportunity"===e.result.details.type?"load-opportunity":"diagnostic"}render(e,a,n){const t=de.i18n.strings,i=this.dom.createElement("div","lh-category");i.id=e.id,i.append(this.renderCategoryHeader(e,a,n));const o=e.auditRefs.filter((e=>"metrics"===e.group));if(o.length){const[n,r]=this.renderAuditGroup(a.metrics),s=this.dom.createElement("input","lh-metrics-toggle__input"),l=`lh-metrics-toggle${de.getUniqueSuffix()}`;s.setAttribute("aria-label","Toggle the display of metric descriptions"),s.type="checkbox",s.id=l,n.prepend(s);const p=this.dom.find(".lh-audit-group__header",n),u=this.dom.createChildOf(p,"label","lh-metrics-toggle__label");u.htmlFor=l;const c=this.dom.createChildOf(u,"span","lh-metrics-toggle__labeltext--show"),d=this.dom.createChildOf(u,"span","lh-metrics-toggle__labeltext--hide");c.textContent=de.i18n.strings.expandView,d.textContent=de.i18n.strings.collapseView;const m=this.dom.createElement("div","lh-metrics-container");if(n.insertBefore(m,r),o.forEach((e=>{m.append(this._renderMetric(e))})),i.querySelector(".lh-gauge__wrapper")){const a=this.dom.find(".lh-category-header__description",i),n=this.dom.createChildOf(a,"div","lh-metrics__disclaimer"),o=this.dom.convertMarkdownLinkSnippets(t.varianceDisclaimer);n.append(o);const r=this.dom.createChildOf(n,"a","lh-calclink");r.target="_blank",r.textContent=t.calculatorLink,this.dom.safelySetHref(r,this._getScoringCalculatorHref(e.auditRefs))}n.classList.add("lh-audit-group--metrics"),i.append(n)}const r=this.dom.createChildOf(i,"div","lh-filmstrip-container"),s=e.auditRefs.find((e=>"screenshot-thumbnails"===e.id))?.result;if(s?.details){r.id=s.id;const e=this.detailsRenderer.render(s.details);e&&r.append(e)}const l=e.auditRefs.filter((e=>"load-opportunity"===this._classifyPerformanceAudit(e))).filter((e=>!de.showAsPassed(e.result))).sort(((e,a)=>this._getWastedMs(a)-this._getWastedMs(e))),p=o.filter((e=>!!e.relevantAudits));if(p.length&&this.renderMetricAuditFilter(p,i),l.length){const e=2e3,n=l.map((e=>this._getWastedMs(e))),o=Math.max(...n),r=Math.max(1e3*Math.ceil(o/1e3),e),[s,p]=this.renderAuditGroup(a["load-opportunities"]),u=this.dom.createComponent("opportunityHeader");this.dom.find(".lh-load-opportunity__col--one",u).textContent=t.opportunityResourceColumnLabel,this.dom.find(".lh-load-opportunity__col--two",u).textContent=t.opportunitySavingsColumnLabel;const c=this.dom.find(".lh-load-opportunity__header",u);s.insertBefore(c,p),l.forEach((e=>s.insertBefore(this._renderOpportunity(e,r),p))),s.classList.add("lh-audit-group--load-opportunities"),i.append(s)}const u=e.auditRefs.filter((e=>"diagnostic"===this._classifyPerformanceAudit(e))).filter((e=>!de.showAsPassed(e.result))).sort(((e,a)=>("informative"===e.result.scoreDisplayMode?100:Number(e.result.score))-("informative"===a.result.scoreDisplayMode?100:Number(a.result.score))));if(u.length){const[e,n]=this.renderAuditGroup(a.diagnostics);u.forEach((a=>e.insertBefore(this.renderAudit(a),n))),e.classList.add("lh-audit-group--diagnostics"),i.append(e)}const c=e.auditRefs.filter((e=>this._classifyPerformanceAudit(e)&&de.showAsPassed(e.result)));if(!c.length)return i;const d={auditRefs:c,groupDefinitions:a},m=this.renderClump("passed",d);i.append(m);const h=[];if(["performance-budget","timing-budget"].forEach((a=>{const n=e.auditRefs.find((e=>e.id===a));if(n?.result.details){const e=this.detailsRenderer.render(n.result.details);e&&(e.id=a,e.classList.add("lh-details","lh-details--budget","lh-audit"),h.push(e))}})),h.length>0){const[e,n]=this.renderAuditGroup(a.budgets);h.forEach((a=>e.insertBefore(a,n))),e.classList.add("lh-audit-group--budgets"),i.append(e)}return i}renderMetricAuditFilter(e,a){const n=this.dom.createElement("div","lh-metricfilter");this.dom.createChildOf(n,"span","lh-metricfilter__text").textContent=de.i18n.strings.showRelevantAudits;const t=[{acronym:"All"},...e],i=de.getUniqueSuffix();for(const e of t){const t=`metric-${e.acronym}-${i}`,o=this.dom.createChildOf(n,"input","lh-metricfilter__radio");o.type="radio",o.name=`metricsfilter-${i}`,o.id=t;const r=this.dom.createChildOf(n,"label","lh-metricfilter__label");r.htmlFor=t,r.title=e.result?.title,r.textContent=e.acronym||e.id,"All"===e.acronym&&(o.checked=!0,r.classList.add("lh-metricfilter__label--active")),a.append(n),o.addEventListener("input",(n=>{for(const e of a.querySelectorAll("label.lh-metricfilter__label"))e.classList.toggle("lh-metricfilter__label--active",e.htmlFor===t);a.classList.toggle("lh-category--filtered","All"!==e.acronym);for(const n of a.querySelectorAll("div.lh-audit"))"All"!==e.acronym?(n.hidden=!0,e.relevantAudits&&e.relevantAudits.includes(n.id)&&(n.hidden=!1)):n.hidden=!1;const i=a.querySelectorAll("div.lh-audit-group, details.lh-audit-group");for(const e of i){e.hidden=!1;const a=Array.from(e.querySelectorAll("div.lh-audit")),n=!!a.length&&a.every((e=>e.hidden));e.hidden=n}}))}}}
120
+ */class La extends wa{_renderMetric(e){const a=this.dom.createComponent("metric"),n=this.dom.find(".lh-metric",a);n.id=e.result.id;const t=de.calculateRating(e.result.score,e.result.scoreDisplayMode);n.classList.add(`lh-metric--${t}`);this.dom.find(".lh-metric__title",a).textContent=e.result.title;const i=this.dom.find(".lh-metric__value",a);i.textContent=e.result.displayValue||"";const o=this.dom.find(".lh-metric__description",a);if(o.append(this.dom.convertMarkdownLinkSnippets(e.result.description)),"error"===e.result.scoreDisplayMode){o.textContent="",i.textContent="Error!";this.dom.createChildOf(o,"span").textContent=e.result.errorMessage||"Report error: no metric information"}else"notApplicable"===e.result.scoreDisplayMode&&(i.textContent="--");return n}_renderOpportunity(e,a){const n=this.dom.createComponent("opportunity"),t=this.populateAuditValues(e,n);if(t.id=e.result.id,!e.result.details||"error"===e.result.scoreDisplayMode)return t;const i=e.result.details;if("opportunity"!==i.type)return t;const o=this.dom.find("span.lh-audit__display-text, div.lh-audit__display-text",t),r=i.overallSavingsMs/a*100+"%";if(this.dom.find("div.lh-sparkline__bar",t).style.width=r,o.textContent=de.i18n.formatSeconds(i.overallSavingsMs,.01),e.result.displayValue){const a=e.result.displayValue;this.dom.find("div.lh-load-opportunity__sparkline",t).title=a,o.title=a}return t}_getWastedMs(e){if(e.result.details&&"opportunity"===e.result.details.type){const a=e.result.details;if("number"!=typeof a.overallSavingsMs)throw new Error("non-opportunity details passed to _getWastedMs");return a.overallSavingsMs}return Number.MIN_VALUE}_getScoringCalculatorHref(e){const a=e.filter((e=>"metrics"===e.group)),n=e.find((e=>"interactive"===e.id)),t=e.find((e=>"first-cpu-idle"===e.id)),i=e.find((e=>"first-meaningful-paint"===e.id));n&&a.push(n),t&&a.push(t),i&&a.push(i);const o=[...a.map((e=>{let a;var n;return"number"==typeof e.result.numericValue?(a="cumulative-layout-shift"===e.id?(n=e.result.numericValue,Math.round(100*n)/100):Math.round(e.result.numericValue),a=a.toString()):a="null",[e.acronym||e.id,a]}))];de.reportJson&&(o.push(["device",de.reportJson.configSettings.formFactor]),o.push(["version",de.reportJson.lighthouseVersion]));const r=new URLSearchParams(o),s=new URL("https://googlechrome.github.io/lighthouse/scorecalc/");return s.hash=r.toString(),s.href}_classifyPerformanceAudit(e){return e.group?null:e.result.details&&"opportunity"===e.result.details.type?"load-opportunity":"diagnostic"}render(e,a,n){const t=de.i18n.strings,i=this.dom.createElement("div","lh-category");i.id=e.id,i.append(this.renderCategoryHeader(e,a,n));const o=e.auditRefs.filter((e=>"metrics"===e.group));if(o.length){const[n,r]=this.renderAuditGroup(a.metrics),s=this.dom.createElement("input","lh-metrics-toggle__input"),l=`lh-metrics-toggle${de.getUniqueSuffix()}`;s.setAttribute("aria-label","Toggle the display of metric descriptions"),s.type="checkbox",s.id=l,n.prepend(s);const p=this.dom.find(".lh-audit-group__header",n),u=this.dom.createChildOf(p,"label","lh-metrics-toggle__label");u.htmlFor=l;const c=this.dom.createChildOf(u,"span","lh-metrics-toggle__labeltext--show"),d=this.dom.createChildOf(u,"span","lh-metrics-toggle__labeltext--hide");c.textContent=de.i18n.strings.expandView,d.textContent=de.i18n.strings.collapseView;const m=this.dom.createElement("div","lh-metrics-container");if(n.insertBefore(m,r),o.forEach((e=>{m.append(this._renderMetric(e))})),i.querySelector(".lh-gauge__wrapper")){const a=this.dom.find(".lh-category-header__description",i),n=this.dom.createChildOf(a,"div","lh-metrics__disclaimer"),o=this.dom.convertMarkdownLinkSnippets(t.varianceDisclaimer);n.append(o);const r=this.dom.createChildOf(n,"a","lh-calclink");r.target="_blank",r.textContent=t.calculatorLink,this.dom.safelySetHref(r,this._getScoringCalculatorHref(e.auditRefs))}n.classList.add("lh-audit-group--metrics"),i.append(n)}const r=this.dom.createChildOf(i,"div","lh-filmstrip-container"),s=e.auditRefs.find((e=>"screenshot-thumbnails"===e.id))?.result;if(s?.details){r.id=s.id;const e=this.detailsRenderer.render(s.details);e&&r.append(e)}const l=e.auditRefs.filter((e=>"load-opportunity"===this._classifyPerformanceAudit(e))).filter((e=>!de.showAsPassed(e.result))).sort(((e,a)=>this._getWastedMs(a)-this._getWastedMs(e))),p=o.filter((e=>!!e.relevantAudits));if(p.length&&this.renderMetricAuditFilter(p,i),l.length){const e=2e3,n=l.map((e=>this._getWastedMs(e))),o=Math.max(...n),r=Math.max(1e3*Math.ceil(o/1e3),e),[s,p]=this.renderAuditGroup(a["load-opportunities"]),u=this.dom.createComponent("opportunityHeader");this.dom.find(".lh-load-opportunity__col--one",u).textContent=t.opportunityResourceColumnLabel,this.dom.find(".lh-load-opportunity__col--two",u).textContent=t.opportunitySavingsColumnLabel;const c=this.dom.find(".lh-load-opportunity__header",u);s.insertBefore(c,p),l.forEach((e=>s.insertBefore(this._renderOpportunity(e,r),p))),s.classList.add("lh-audit-group--load-opportunities"),i.append(s)}const u=e.auditRefs.filter((e=>"diagnostic"===this._classifyPerformanceAudit(e))).filter((e=>!de.showAsPassed(e.result))).sort(((e,a)=>("informative"===e.result.scoreDisplayMode?100:Number(e.result.score))-("informative"===a.result.scoreDisplayMode?100:Number(a.result.score))));if(u.length){const[e,n]=this.renderAuditGroup(a.diagnostics);u.forEach((a=>e.insertBefore(this.renderAudit(a),n))),e.classList.add("lh-audit-group--diagnostics"),i.append(e)}const c=e.auditRefs.filter((e=>this._classifyPerformanceAudit(e)&&de.showAsPassed(e.result)));if(!c.length)return i;const d={auditRefs:c,groupDefinitions:a},m=this.renderClump("passed",d);i.append(m);const h=[];if(["performance-budget","timing-budget"].forEach((a=>{const n=e.auditRefs.find((e=>e.id===a));if(n?.result.details){const e=this.detailsRenderer.render(n.result.details);e&&(e.id=a,e.classList.add("lh-details","lh-details--budget","lh-audit"),h.push(e))}})),h.length>0){const[e,n]=this.renderAuditGroup(a.budgets);h.forEach((a=>e.insertBefore(a,n))),e.classList.add("lh-audit-group--budgets"),i.append(e)}return i}renderMetricAuditFilter(e,a){const n=this.dom.createElement("div","lh-metricfilter");this.dom.createChildOf(n,"span","lh-metricfilter__text").textContent=de.i18n.strings.showRelevantAudits;const t=[{acronym:"All"},...e],i=de.getUniqueSuffix();for(const e of t){const t=`metric-${e.acronym}-${i}`,o=this.dom.createChildOf(n,"input","lh-metricfilter__radio");o.type="radio",o.name=`metricsfilter-${i}`,o.id=t;const r=this.dom.createChildOf(n,"label","lh-metricfilter__label");r.htmlFor=t,r.title=e.result?.title,r.textContent=e.acronym||e.id,"All"===e.acronym&&(o.checked=!0,r.classList.add("lh-metricfilter__label--active")),a.append(n),o.addEventListener("input",(n=>{for(const e of a.querySelectorAll("label.lh-metricfilter__label"))e.classList.toggle("lh-metricfilter__label--active",e.htmlFor===t);a.classList.toggle("lh-category--filtered","All"!==e.acronym);for(const n of a.querySelectorAll("div.lh-audit"))"All"!==e.acronym?(n.hidden=!0,e.relevantAudits&&e.relevantAudits.includes(n.id)&&(n.hidden=!1)):n.hidden=!1;const i=a.querySelectorAll("div.lh-audit-group, details.lh-audit-group");for(const e of i){e.hidden=!1;const a=Array.from(e.querySelectorAll("div.lh-audit")),n=!!a.length&&a.every((e=>e.hidden));e.hidden=n}}))}}}
121
121
  /**
122
122
  * @license
123
123
  * Copyright 2018 The Lighthouse Authors. All Rights Reserved.
@@ -105,7 +105,7 @@ class c{constructor(e,t){this._document=e,this._lighthouseChannel="unknown",this
105
105
  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
106
106
  * See the License for the specific language governing permissions and
107
107
  * limitations under the License.
108
- */class w extends d{_renderMetric(e){const t=this.dom.createComponent("metric"),n=this.dom.find(".lh-metric",t);n.id=e.result.id;const r=l.calculateRating(e.result.score,e.result.scoreDisplayMode);n.classList.add(`lh-metric--${r}`);this.dom.find(".lh-metric__title",t).textContent=e.result.title;const o=this.dom.find(".lh-metric__value",t);o.textContent=e.result.displayValue||"";const i=this.dom.find(".lh-metric__description",t);if(i.append(this.dom.convertMarkdownLinkSnippets(e.result.description)),"error"===e.result.scoreDisplayMode){i.textContent="",o.textContent="Error!";this.dom.createChildOf(i,"span").textContent=e.result.errorMessage||"Report error: no metric information"}else"notApplicable"===e.result.scoreDisplayMode&&(o.textContent="--");return n}_renderOpportunity(e,t){const n=this.dom.createComponent("opportunity"),r=this.populateAuditValues(e,n);if(r.id=e.result.id,!e.result.details||"error"===e.result.scoreDisplayMode)return r;const o=e.result.details;if("opportunity"!==o.type)return r;const i=this.dom.find("span.lh-audit__display-text, div.lh-audit__display-text",r),a=o.overallSavingsMs/t*100+"%";if(this.dom.find("div.lh-sparkline__bar",r).style.width=a,i.textContent=l.i18n.formatSeconds(o.overallSavingsMs,.01),e.result.displayValue){const t=e.result.displayValue;this.dom.find("div.lh-load-opportunity__sparkline",r).title=t,i.title=t}return r}_getWastedMs(e){if(e.result.details&&"opportunity"===e.result.details.type){const t=e.result.details;if("number"!=typeof t.overallSavingsMs)throw new Error("non-opportunity details passed to _getWastedMs");return t.overallSavingsMs}return Number.MIN_VALUE}_getScoringCalculatorHref(e){const t=e.filter((e=>"metrics"===e.group)),n=e.find((e=>"first-cpu-idle"===e.id)),r=e.find((e=>"first-meaningful-paint"===e.id));n&&t.push(n),r&&t.push(r);const o=[...t.map((e=>{let t;var n;return"number"==typeof e.result.numericValue?(t="cumulative-layout-shift"===e.id?(n=e.result.numericValue,Math.round(100*n)/100):Math.round(e.result.numericValue),t=t.toString()):t="null",[e.acronym||e.id,t]}))];l.reportJson&&(o.push(["device",l.reportJson.configSettings.formFactor]),o.push(["version",l.reportJson.lighthouseVersion]));const i=new URLSearchParams(o),a=new URL("https://googlechrome.github.io/lighthouse/scorecalc/");return a.hash=i.toString(),a.href}_classifyPerformanceAudit(e){return e.group?null:e.result.details&&"opportunity"===e.result.details.type?"load-opportunity":"diagnostic"}render(e,t,n){const r=l.i18n.strings,o=this.dom.createElement("div","lh-category");o.id=e.id,o.append(this.renderCategoryHeader(e,t,n));const i=e.auditRefs.filter((e=>"metrics"===e.group));if(i.length){const[n,a]=this.renderAuditGroup(t.metrics),s=this.dom.createElement("input","lh-metrics-toggle__input"),c=`lh-metrics-toggle${l.getUniqueSuffix()}`;s.setAttribute("aria-label","Toggle the display of metric descriptions"),s.type="checkbox",s.id=c,n.prepend(s);const d=this.dom.find(".lh-audit-group__header",n),h=this.dom.createChildOf(d,"label","lh-metrics-toggle__label");h.htmlFor=c;const p=this.dom.createChildOf(h,"span","lh-metrics-toggle__labeltext--show"),u=this.dom.createChildOf(h,"span","lh-metrics-toggle__labeltext--hide");p.textContent=l.i18n.strings.expandView,u.textContent=l.i18n.strings.collapseView;const g=this.dom.createElement("div","lh-metrics-container");if(n.insertBefore(g,a),i.forEach((e=>{g.append(this._renderMetric(e))})),o.querySelector(".lh-gauge__wrapper")){const t=this.dom.find(".lh-category-header__description",o),n=this.dom.createChildOf(t,"div","lh-metrics__disclaimer"),i=this.dom.convertMarkdownLinkSnippets(r.varianceDisclaimer);n.append(i);const a=this.dom.createChildOf(n,"a","lh-calclink");a.target="_blank",a.textContent=r.calculatorLink,this.dom.safelySetHref(a,this._getScoringCalculatorHref(e.auditRefs))}n.classList.add("lh-audit-group--metrics"),o.append(n)}const a=this.dom.createChildOf(o,"div","lh-filmstrip-container"),s=e.auditRefs.find((e=>"screenshot-thumbnails"===e.id))?.result;if(s?.details){a.id=s.id;const e=this.detailsRenderer.render(s.details);e&&a.append(e)}const c=e.auditRefs.filter((e=>"load-opportunity"===this._classifyPerformanceAudit(e))).filter((e=>!l.showAsPassed(e.result))).sort(((e,t)=>this._getWastedMs(t)-this._getWastedMs(e))),d=i.filter((e=>!!e.relevantAudits));if(d.length&&this.renderMetricAuditFilter(d,o),c.length){const e=2e3,n=c.map((e=>this._getWastedMs(e))),i=Math.max(...n),a=Math.max(1e3*Math.ceil(i/1e3),e),[l,s]=this.renderAuditGroup(t["load-opportunities"]),d=this.dom.createComponent("opportunityHeader");this.dom.find(".lh-load-opportunity__col--one",d).textContent=r.opportunityResourceColumnLabel,this.dom.find(".lh-load-opportunity__col--two",d).textContent=r.opportunitySavingsColumnLabel;const h=this.dom.find(".lh-load-opportunity__header",d);l.insertBefore(h,s),c.forEach((e=>l.insertBefore(this._renderOpportunity(e,a),s))),l.classList.add("lh-audit-group--load-opportunities"),o.append(l)}const h=e.auditRefs.filter((e=>"diagnostic"===this._classifyPerformanceAudit(e))).filter((e=>!l.showAsPassed(e.result))).sort(((e,t)=>("informative"===e.result.scoreDisplayMode?100:Number(e.result.score))-("informative"===t.result.scoreDisplayMode?100:Number(t.result.score))));if(h.length){const[e,n]=this.renderAuditGroup(t.diagnostics);h.forEach((t=>e.insertBefore(this.renderAudit(t),n))),e.classList.add("lh-audit-group--diagnostics"),o.append(e)}const p=e.auditRefs.filter((e=>this._classifyPerformanceAudit(e)&&l.showAsPassed(e.result)));if(!p.length)return o;const u={auditRefs:p,groupDefinitions:t},g=this.renderClump("passed",u);o.append(g);const m=[];if(["performance-budget","timing-budget"].forEach((t=>{const n=e.auditRefs.find((e=>e.id===t));if(n?.result.details){const e=this.detailsRenderer.render(n.result.details);e&&(e.id=t,e.classList.add("lh-details","lh-details--budget","lh-audit"),m.push(e))}})),m.length>0){const[e,n]=this.renderAuditGroup(t.budgets);m.forEach((t=>e.insertBefore(t,n))),e.classList.add("lh-audit-group--budgets"),o.append(e)}return o}renderMetricAuditFilter(e,t){const n=this.dom.createElement("div","lh-metricfilter");this.dom.createChildOf(n,"span","lh-metricfilter__text").textContent=l.i18n.strings.showRelevantAudits;const r=[{acronym:"All"},...e],o=l.getUniqueSuffix();for(const e of r){const r=`metric-${e.acronym}-${o}`,i=this.dom.createChildOf(n,"input","lh-metricfilter__radio");i.type="radio",i.name=`metricsfilter-${o}`,i.id=r;const a=this.dom.createChildOf(n,"label","lh-metricfilter__label");a.htmlFor=r,a.title=e.result?.title,a.textContent=e.acronym||e.id,"All"===e.acronym&&(i.checked=!0,a.classList.add("lh-metricfilter__label--active")),t.append(n),i.addEventListener("input",(n=>{for(const e of t.querySelectorAll("label.lh-metricfilter__label"))e.classList.toggle("lh-metricfilter__label--active",e.htmlFor===r);t.classList.toggle("lh-category--filtered","All"!==e.acronym);for(const n of t.querySelectorAll("div.lh-audit"))"All"!==e.acronym?(n.hidden=!0,e.relevantAudits&&e.relevantAudits.includes(n.id)&&(n.hidden=!1)):n.hidden=!1;const o=t.querySelectorAll("div.lh-audit-group, details.lh-audit-group");for(const e of o){e.hidden=!1;const t=Array.from(e.querySelectorAll("div.lh-audit")),n=!!t.length&&t.every((e=>e.hidden));e.hidden=n}}))}}}
108
+ */class w extends d{_renderMetric(e){const t=this.dom.createComponent("metric"),n=this.dom.find(".lh-metric",t);n.id=e.result.id;const r=l.calculateRating(e.result.score,e.result.scoreDisplayMode);n.classList.add(`lh-metric--${r}`);this.dom.find(".lh-metric__title",t).textContent=e.result.title;const o=this.dom.find(".lh-metric__value",t);o.textContent=e.result.displayValue||"";const i=this.dom.find(".lh-metric__description",t);if(i.append(this.dom.convertMarkdownLinkSnippets(e.result.description)),"error"===e.result.scoreDisplayMode){i.textContent="",o.textContent="Error!";this.dom.createChildOf(i,"span").textContent=e.result.errorMessage||"Report error: no metric information"}else"notApplicable"===e.result.scoreDisplayMode&&(o.textContent="--");return n}_renderOpportunity(e,t){const n=this.dom.createComponent("opportunity"),r=this.populateAuditValues(e,n);if(r.id=e.result.id,!e.result.details||"error"===e.result.scoreDisplayMode)return r;const o=e.result.details;if("opportunity"!==o.type)return r;const i=this.dom.find("span.lh-audit__display-text, div.lh-audit__display-text",r),a=o.overallSavingsMs/t*100+"%";if(this.dom.find("div.lh-sparkline__bar",r).style.width=a,i.textContent=l.i18n.formatSeconds(o.overallSavingsMs,.01),e.result.displayValue){const t=e.result.displayValue;this.dom.find("div.lh-load-opportunity__sparkline",r).title=t,i.title=t}return r}_getWastedMs(e){if(e.result.details&&"opportunity"===e.result.details.type){const t=e.result.details;if("number"!=typeof t.overallSavingsMs)throw new Error("non-opportunity details passed to _getWastedMs");return t.overallSavingsMs}return Number.MIN_VALUE}_getScoringCalculatorHref(e){const t=e.filter((e=>"metrics"===e.group)),n=e.find((e=>"interactive"===e.id)),r=e.find((e=>"first-cpu-idle"===e.id)),o=e.find((e=>"first-meaningful-paint"===e.id));n&&t.push(n),r&&t.push(r),o&&t.push(o);const i=[...t.map((e=>{let t;var n;return"number"==typeof e.result.numericValue?(t="cumulative-layout-shift"===e.id?(n=e.result.numericValue,Math.round(100*n)/100):Math.round(e.result.numericValue),t=t.toString()):t="null",[e.acronym||e.id,t]}))];l.reportJson&&(i.push(["device",l.reportJson.configSettings.formFactor]),i.push(["version",l.reportJson.lighthouseVersion]));const a=new URLSearchParams(i),s=new URL("https://googlechrome.github.io/lighthouse/scorecalc/");return s.hash=a.toString(),s.href}_classifyPerformanceAudit(e){return e.group?null:e.result.details&&"opportunity"===e.result.details.type?"load-opportunity":"diagnostic"}render(e,t,n){const r=l.i18n.strings,o=this.dom.createElement("div","lh-category");o.id=e.id,o.append(this.renderCategoryHeader(e,t,n));const i=e.auditRefs.filter((e=>"metrics"===e.group));if(i.length){const[n,a]=this.renderAuditGroup(t.metrics),s=this.dom.createElement("input","lh-metrics-toggle__input"),c=`lh-metrics-toggle${l.getUniqueSuffix()}`;s.setAttribute("aria-label","Toggle the display of metric descriptions"),s.type="checkbox",s.id=c,n.prepend(s);const d=this.dom.find(".lh-audit-group__header",n),h=this.dom.createChildOf(d,"label","lh-metrics-toggle__label");h.htmlFor=c;const p=this.dom.createChildOf(h,"span","lh-metrics-toggle__labeltext--show"),u=this.dom.createChildOf(h,"span","lh-metrics-toggle__labeltext--hide");p.textContent=l.i18n.strings.expandView,u.textContent=l.i18n.strings.collapseView;const g=this.dom.createElement("div","lh-metrics-container");if(n.insertBefore(g,a),i.forEach((e=>{g.append(this._renderMetric(e))})),o.querySelector(".lh-gauge__wrapper")){const t=this.dom.find(".lh-category-header__description",o),n=this.dom.createChildOf(t,"div","lh-metrics__disclaimer"),i=this.dom.convertMarkdownLinkSnippets(r.varianceDisclaimer);n.append(i);const a=this.dom.createChildOf(n,"a","lh-calclink");a.target="_blank",a.textContent=r.calculatorLink,this.dom.safelySetHref(a,this._getScoringCalculatorHref(e.auditRefs))}n.classList.add("lh-audit-group--metrics"),o.append(n)}const a=this.dom.createChildOf(o,"div","lh-filmstrip-container"),s=e.auditRefs.find((e=>"screenshot-thumbnails"===e.id))?.result;if(s?.details){a.id=s.id;const e=this.detailsRenderer.render(s.details);e&&a.append(e)}const c=e.auditRefs.filter((e=>"load-opportunity"===this._classifyPerformanceAudit(e))).filter((e=>!l.showAsPassed(e.result))).sort(((e,t)=>this._getWastedMs(t)-this._getWastedMs(e))),d=i.filter((e=>!!e.relevantAudits));if(d.length&&this.renderMetricAuditFilter(d,o),c.length){const e=2e3,n=c.map((e=>this._getWastedMs(e))),i=Math.max(...n),a=Math.max(1e3*Math.ceil(i/1e3),e),[l,s]=this.renderAuditGroup(t["load-opportunities"]),d=this.dom.createComponent("opportunityHeader");this.dom.find(".lh-load-opportunity__col--one",d).textContent=r.opportunityResourceColumnLabel,this.dom.find(".lh-load-opportunity__col--two",d).textContent=r.opportunitySavingsColumnLabel;const h=this.dom.find(".lh-load-opportunity__header",d);l.insertBefore(h,s),c.forEach((e=>l.insertBefore(this._renderOpportunity(e,a),s))),l.classList.add("lh-audit-group--load-opportunities"),o.append(l)}const h=e.auditRefs.filter((e=>"diagnostic"===this._classifyPerformanceAudit(e))).filter((e=>!l.showAsPassed(e.result))).sort(((e,t)=>("informative"===e.result.scoreDisplayMode?100:Number(e.result.score))-("informative"===t.result.scoreDisplayMode?100:Number(t.result.score))));if(h.length){const[e,n]=this.renderAuditGroup(t.diagnostics);h.forEach((t=>e.insertBefore(this.renderAudit(t),n))),e.classList.add("lh-audit-group--diagnostics"),o.append(e)}const p=e.auditRefs.filter((e=>this._classifyPerformanceAudit(e)&&l.showAsPassed(e.result)));if(!p.length)return o;const u={auditRefs:p,groupDefinitions:t},g=this.renderClump("passed",u);o.append(g);const m=[];if(["performance-budget","timing-budget"].forEach((t=>{const n=e.auditRefs.find((e=>e.id===t));if(n?.result.details){const e=this.detailsRenderer.render(n.result.details);e&&(e.id=t,e.classList.add("lh-details","lh-details--budget","lh-audit"),m.push(e))}})),m.length>0){const[e,n]=this.renderAuditGroup(t.budgets);m.forEach((t=>e.insertBefore(t,n))),e.classList.add("lh-audit-group--budgets"),o.append(e)}return o}renderMetricAuditFilter(e,t){const n=this.dom.createElement("div","lh-metricfilter");this.dom.createChildOf(n,"span","lh-metricfilter__text").textContent=l.i18n.strings.showRelevantAudits;const r=[{acronym:"All"},...e],o=l.getUniqueSuffix();for(const e of r){const r=`metric-${e.acronym}-${o}`,i=this.dom.createChildOf(n,"input","lh-metricfilter__radio");i.type="radio",i.name=`metricsfilter-${o}`,i.id=r;const a=this.dom.createChildOf(n,"label","lh-metricfilter__label");a.htmlFor=r,a.title=e.result?.title,a.textContent=e.acronym||e.id,"All"===e.acronym&&(i.checked=!0,a.classList.add("lh-metricfilter__label--active")),t.append(n),i.addEventListener("input",(n=>{for(const e of t.querySelectorAll("label.lh-metricfilter__label"))e.classList.toggle("lh-metricfilter__label--active",e.htmlFor===r);t.classList.toggle("lh-category--filtered","All"!==e.acronym);for(const n of t.querySelectorAll("div.lh-audit"))"All"!==e.acronym?(n.hidden=!0,e.relevantAudits&&e.relevantAudits.includes(n.id)&&(n.hidden=!1)):n.hidden=!1;const o=t.querySelectorAll("div.lh-audit-group, details.lh-audit-group");for(const e of o){e.hidden=!1;const t=Array.from(e.querySelectorAll("div.lh-audit")),n=!!t.length&&t.every((e=>e.hidden));e.hidden=n}}))}}}
109
109
  /**
110
110
  * @license
111
111
  * Copyright 2018 The Lighthouse Authors. All Rights Reserved.
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "lighthouse",
3
3
  "type": "module",
4
- "version": "9.5.0-dev.20230116",
4
+ "version": "9.5.0-dev.20230118",
5
5
  "description": "Automated auditing, performance metrics, and best practices for the web.",
6
6
  "main": "./core/index.js",
7
7
  "bin": {
@@ -116,8 +116,10 @@ export class PerformanceCategoryRenderer extends CategoryRenderer {
116
116
  _getScoringCalculatorHref(auditRefs) {
117
117
  // TODO: filter by !!acronym when dropping renderer support of v7 LHRs.
118
118
  const metrics = auditRefs.filter(audit => audit.group === 'metrics');
119
+ const tti = auditRefs.find(audit => audit.id === 'interactive');
119
120
  const fci = auditRefs.find(audit => audit.id === 'first-cpu-idle');
120
121
  const fmp = auditRefs.find(audit => audit.id === 'first-meaningful-paint');
122
+ if (tti) metrics.push(tti);
121
123
  if (fci) metrics.push(fci);
122
124
  if (fmp) metrics.push(fmp);
123
125
 
@@ -106,7 +106,7 @@ describe('ReportGenerator', () => {
106
106
  \\"http://localhost:10200/dobetterweb/dbw_tester.html\\",\\"http://localhost:10200/dobetterweb/dbw_tester.html\\",\\"2021-09-07T20:11:11.853Z\\",\\"navigation\\"
107
107
 
108
108
  category,score
109
- \\"performance\\",\\"0.26\\"
109
+ \\"performance\\",\\"0.3\\"
110
110
  \\"accessibility\\",\\"0.77\\"
111
111
  \\"best-practices\\",\\"0.25\\"
112
112
  \\"seo\\",\\"0.67\\"
@@ -114,9 +114,9 @@ category,score
114
114
 
115
115
  category,audit,score,displayValue,description
116
116
  \\"performance\\",\\"first-contentful-paint\\",\\"0.01\\",\\"6.8 s\\",\\"First Contentful Paint marks the time at which the first text or image is painted. [Learn more about the First Contentful Paint metric](https://developer.chrome.com/docs/lighthouse/performance/first-contentful-paint/).\\"
117
- \\"performance\\",\\"interactive\\",\\"0.41\\",\\"8.2 s\\",\\"Time to Interactive is the amount of time it takes for the page to become fully interactive. [Learn more about the Time to Interactive metric](https://developer.chrome.com/docs/lighthouse/performance/interactive/).\\"
118
- \\"performance\\",\\"speed-index\\",\\"0.21\\",\\"8.1 s\\",\\"Speed Index shows how quickly the contents of a page are visibly populated. [Learn more about the Speed Index metric](https://developer.chrome.com/docs/lighthouse/performance/speed-index/).\\"
117
+ \\"performance\\",\\"largest-contentful-paint\\",\\"0.07\\",\\"6.8 s\\",\\"Largest Contentful Paint marks the time at which the largest text or image is painted. [Learn more about the Largest Contentful Paint metric](https://developer.chrome.com/docs/lighthouse/performance/lighthouse-largest-contentful-paint/)\\"
119
118
  \\"performance\\",\\"total-blocking-time\\",\\"0.2\\",\\"1,220 ms\\",\\"Sum of all time periods between FCP and Time to Interactive, when task length exceeded 50ms, expressed in milliseconds. [Learn more about the Total Blocking Time metric](https://developer.chrome.com/docs/lighthouse/performance/lighthouse-total-blocking-time/).\\"
119
+ \\"performance\\",\\"cumulative-layout-shift\\",\\"0.8\\",\\"0.136\\",\\"Cumulative Layout Shift measures the movement of visible elements within the viewport. [Learn more about the Cumulative Layout Shift metric](https://web.dev/cls/).\\"
120
120
  "
121
121
  `);
122
122
 
@@ -69,11 +69,10 @@ describe('PerfCategoryRenderer', () => {
69
69
  Array.from(timelineElements).map(el => el.id),
70
70
  [
71
71
  'first-contentful-paint',
72
- 'interactive',
73
- 'speed-index',
74
- 'total-blocking-time',
75
72
  'largest-contentful-paint',
73
+ 'total-blocking-time',
76
74
  'cumulative-layout-shift',
75
+ 'speed-index',
77
76
  ]
78
77
  );
79
78
  });
@@ -322,11 +321,11 @@ describe('PerfCategoryRenderer', () => {
322
321
  expect(url.hash.split('&')).toMatchInlineSnapshot(`
323
322
  Array [
324
323
  "#FCP=6844",
325
- "TTI=8191",
326
- "SI=8114",
327
- "TBT=1221",
328
324
  "LCP=6844",
325
+ "TBT=1221",
329
326
  "CLS=0",
327
+ "SI=8114",
328
+ "TTI=8191",
330
329
  "FMP=6844",
331
330
  ]
332
331
  `);
@@ -343,11 +342,11 @@ Array [
343
342
  expect(url.hash.split('&')).toMatchInlineSnapshot(`
344
343
  Array [
345
344
  "#FCP=6844",
346
- "TTI=8191",
347
- "SI=8114",
348
- "TBT=1221",
349
345
  "LCP=6844",
346
+ "TBT=1221",
350
347
  "CLS=0.14",
348
+ "SI=8114",
349
+ "TTI=8191",
351
350
  "FMP=6844",
352
351
  "device=mobile",
353
352
  "version=6.0.0",
@@ -79,12 +79,6 @@ interface ContextualBaseArtifacts {
79
79
  interface LegacyBaseArtifacts {
80
80
  /** The user agent string that Lighthouse used to load the page. Set to the empty string if unknown. */
81
81
  NetworkUserAgent: string;
82
- /** Information on detected tech stacks (e.g. JS libraries) used by the page. */
83
- Stacks: Artifacts.DetectedStack[];
84
- /** Parsed version of the page's Web App Manifest, or null if none found. This moved to a regular artifact in Fraggle Rock. */
85
- WebAppManifest: Artifacts.Manifest | null;
86
- /** Errors preventing page being installable as PWA. This moved to a regular artifact in Fraggle Rock. */
87
- InstallabilityErrors: Artifacts.InstallabilityErrors;
88
82
  /** A set of page-load traces, keyed by passName. */
89
83
  traces: {[passName: string]: Trace};
90
84
  /** A set of DevTools debugger protocol records, keyed by passName. */
@@ -151,6 +145,8 @@ export interface GathererArtifacts extends PublicGathererArtifacts,LegacyBaseArt
151
145
  GlobalListeners: Array<Artifacts.GlobalListener>;
152
146
  /** The issues surfaced in the devtools Issues panel */
153
147
  InspectorIssues: Artifacts.InspectorIssues;
148
+ /** Errors preventing page being installable as PWA. */
149
+ InstallabilityErrors: Artifacts.InstallabilityErrors;
154
150
  /** JS coverage information for code used during audit. Keyed by script id. */
155
151
  // 'url' is excluded because it can be overriden by a magic sourceURL= comment, which makes keeping it a dangerous footgun!
156
152
  JsUsage: Record<string, Omit<LH.Crdp.Profiler.ScriptCoverage, 'url'>>;
@@ -172,6 +168,8 @@ export interface GathererArtifacts extends PublicGathererArtifacts,LegacyBaseArt
172
168
  ServiceWorker: {versions: LH.Crdp.ServiceWorker.ServiceWorkerVersion[], registrations: LH.Crdp.ServiceWorker.ServiceWorkerRegistration[]};
173
169
  /** Source maps of scripts executed in the page. */
174
170
  SourceMaps: Array<Artifacts.SourceMap>;
171
+ /** Information on detected tech stacks (e.g. JS libraries) used by the page. */
172
+ Stacks: Artifacts.DetectedStack[];
175
173
  /** Information on <script> and <link> tags blocking first paint. */
176
174
  TagsBlockingFirstPaint: Artifacts.TagBlockingFirstPaint[];
177
175
  /** Information about tap targets including their position and size. */
@@ -180,6 +178,8 @@ export interface GathererArtifacts extends PublicGathererArtifacts,LegacyBaseArt
180
178
  Trace: Trace;
181
179
  /** Elements associated with metrics (ie: Largest Contentful Paint element). */
182
180
  TraceElements: Artifacts.TraceElement[];
181
+ /** Parsed version of the page's Web App Manifest, or null if none found. */
182
+ WebAppManifest: Artifacts.Manifest | null;
183
183
  }
184
184
 
185
185
  declare module Artifacts {