lighthouse 9.5.0-dev.20220612 → 9.5.0-dev.20220615

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/changelog.md CHANGED
@@ -1,6 +1,6 @@
1
1
  <a name="9.5.0"></a>
2
2
  # 9.5.0 (2022-03-09)
3
- [Full Changelog](https://github.com/compare/v9.4.0...v9.5.0)
3
+ [Full Changelog](https://github.com/GoogleChrome/lighthouse/compare/v9.4.0...v9.5.0)
4
4
 
5
5
  We expect this release to ship in the DevTools of [Chrome 101](https://chromiumdash.appspot.com/schedule), and to PageSpeed Insights within 2 weeks.
6
6
 
@@ -54,7 +54,7 @@ Thanks to our new contributor 👽🐷🐰🐯🐻!
54
54
 
55
55
  <a name="9.4.0"></a>
56
56
  # 9.4.0 (2022-02-16)
57
- [Full Changelog](https://github.com/compare/v9.3.1...v9.4.0)
57
+ [Full Changelog](https://github.com/GoogleChrome/lighthouse/compare/v9.3.1...v9.4.0)
58
58
 
59
59
  We expect this release to ship in the DevTools of [Chrome 100](https://chromiumdash.appspot.com/schedule), and to PageSpeed Insights within 2 weeks.
60
60
 
@@ -99,7 +99,7 @@ We expect this release to ship in the DevTools of [Chrome 100](https://chromiumd
99
99
 
100
100
  <a name="9.3.1"></a>
101
101
  # 9.3.1 (2022-01-31)
102
- [Full Changelog](https://github.com/compare/v9.3.0...v9.3.1)
102
+ [Full Changelog](https://github.com/GoogleChrome/lighthouse/compare/v9.3.0...v9.3.1)
103
103
 
104
104
  ## Report
105
105
 
@@ -107,7 +107,7 @@ We expect this release to ship in the DevTools of [Chrome 100](https://chromiumd
107
107
 
108
108
  <a name="9.3.0"></a>
109
109
  # 9.3.0 (2022-01-31)
110
- [Full Changelog](https://github.com/compare/v9.2.0...v9.3.0)
110
+ [Full Changelog](https://github.com/GoogleChrome/lighthouse/compare/v9.2.0...v9.3.0)
111
111
 
112
112
  We expect this release to ship in the DevTools of [Chrome 100](https://chromiumdash.appspot.com/schedule), and to PageSpeed Insights within 2 weeks.
113
113
 
@@ -8,7 +8,6 @@
8
8
  const Audit = require('../audit.js');
9
9
  const i18n = require('../../lib/i18n/i18n.js');
10
10
  const ComputedLcp = require('../../computed/metrics/largest-contentful-paint.js');
11
- const LHError = require('../../lib/lh-error.js');
12
11
 
13
12
  const UIStrings = {
14
13
  /** Description of the Largest Contentful Paint (LCP) metric, which marks the time at which the largest text or image is painted by the browser. This is displayed within a tooltip when the user hovers on the metric name to see more. No character length limits. 'Learn More' becomes link text to additional documentation. */
@@ -77,28 +76,9 @@ class LargestContentfulPaint extends Audit {
77
76
  const metricComputationData = {trace, devtoolsLog, gatherContext,
78
77
  settings: context.settings, URL: artifacts.URL};
79
78
 
80
- let metricResult;
81
- try {
82
- metricResult = await ComputedLcp.request(metricComputationData, context);
83
- } catch (err) {
84
- const match = artifacts.HostUserAgent.match(/Chrome\/(\d+)/);
85
- if (!match) throw err;
86
- const milestone = Number(match[1]);
87
-
88
- // m79 is the minimum version which supports LCP
89
- // https://chromium.googlesource.com/chromium/src/+/master/docs/speed/metrics_changelog/lcp.md
90
- if (milestone < 79 && err.code === 'NO_LCP') {
91
- throw new LHError(
92
- LHError.errors.UNSUPPORTED_OLD_CHROME,
93
- {featureName: 'Largest Contentful Paint'}
94
- );
95
- }
96
- throw err;
97
- }
98
-
79
+ const metricResult = await ComputedLcp.request(metricComputationData, context);
99
80
  const options = context.options[context.settings.formFactor];
100
81
 
101
-
102
82
  return {
103
83
  score: Audit.computeLogNormalScore(
104
84
  options.scoring,
@@ -294,6 +294,8 @@ function filterConfigByExplicitFilters(config, filters) {
294
294
  baseAuditIds = getAuditIdsInCategories(config.categories, onlyCategories);
295
295
  } else if (onlyAudits) {
296
296
  baseAuditIds = new Set();
297
+ } else if (!config.categories || !Object.keys(config.categories).length) {
298
+ baseAuditIds = new Set(config.audits?.map(audit => audit.implementation.meta.id));
297
299
  }
298
300
 
299
301
  const auditIdsToKeep = new Set(
@@ -327,6 +327,7 @@ async function navigationGather(requestor, options) {
327
327
  const artifacts = await Runner.gather(
328
328
  async () => {
329
329
  let {page} = options;
330
+ const normalizedRequestor = isCallback ? requestor : URL.normalizeUrl(requestor);
330
331
 
331
332
  // For navigation mode, we shouldn't connect to a browser in audit mode,
332
333
  // therefore we connect to the browser in the gatherFn callback.
@@ -340,7 +341,7 @@ async function navigationGather(requestor, options) {
340
341
  const context = {
341
342
  driver,
342
343
  config,
343
- requestor: isCallback ? requestor : URL.normalizeUrl(requestor),
344
+ requestor: normalizedRequestor,
344
345
  options: internalOptions,
345
346
  };
346
347
  const {baseArtifacts} = await _setup(context);
@@ -108,13 +108,64 @@ class UserFlow {
108
108
  */
109
109
  async navigate(requestor, stepOptions) {
110
110
  if (this.currentTimespan) throw new Error('Timespan already in progress');
111
+ if (this.currentNavigation) throw new Error('Navigation already in progress');
111
112
 
112
113
  const options = this._getNextNavigationOptions(stepOptions);
113
114
  const gatherResult = await navigationGather(requestor, options);
114
115
 
115
116
  this._addGatherStep(gatherResult, options);
117
+ }
118
+
119
+ /**
120
+ * This is an alternative to `navigate()` that can be used to analyze a navigation triggered by user interaction.
121
+ * For more on user triggered navigations, see https://github.com/GoogleChrome/lighthouse/blob/master/docs/user-flows.md#triggering-a-navigation-via-user-interactions.
122
+ *
123
+ * @param {StepOptions=} stepOptions
124
+ */
125
+ async startNavigation(stepOptions) {
126
+ /** @type {(value: () => void) => void} */
127
+ let completeSetup;
128
+ /** @type {(value: any) => void} */
129
+ let rejectDuringSetup;
130
+
131
+ // This promise will resolve once the setup is done
132
+ // and Lighthouse is waiting for a page navigation to be triggered.
133
+ const navigationSetupPromise = new Promise((resolve, reject) => {
134
+ completeSetup = resolve;
135
+ rejectDuringSetup = reject;
136
+ });
137
+
138
+ // The promise in this callback will not resolve until `continueNavigation` is invoked,
139
+ // because `continueNavigation` is passed along to `navigateSetupPromise`
140
+ // and extracted into `continueAndAwaitResult` below.
141
+ const navigationResultPromise = this.navigate(
142
+ () => new Promise(continueNavigation => completeSetup(continueNavigation)),
143
+ stepOptions
144
+ ).catch(err => {
145
+ if (this.currentNavigation) {
146
+ // If the navigation already started, re-throw the error so it is emitted when `navigationResultPromise` is awaited.
147
+ throw err;
148
+ } else {
149
+ // If the navigation has not started, reject the `navigationSetupPromise` so the error throws when it is awaited in `startNavigation`.
150
+ rejectDuringSetup(err);
151
+ }
152
+ });
153
+
154
+ const continueNavigation = await navigationSetupPromise;
116
155
 
117
- return gatherResult;
156
+ async function continueAndAwaitResult() {
157
+ continueNavigation();
158
+ await navigationResultPromise;
159
+ }
160
+
161
+ this.currentNavigation = {continueAndAwaitResult};
162
+ }
163
+
164
+ async endNavigation() {
165
+ if (this.currentTimespan) throw new Error('Timespan already in progress');
166
+ if (!this.currentNavigation) throw new Error('No navigation in progress');
167
+ await this.currentNavigation.continueAndAwaitResult();
168
+ this.currentNavigation = undefined;
118
169
  }
119
170
 
120
171
  /**
@@ -122,6 +173,7 @@ class UserFlow {
122
173
  */
123
174
  async startTimespan(stepOptions) {
124
175
  if (this.currentTimespan) throw new Error('Timespan already in progress');
176
+ if (this.currentNavigation) throw new Error('Navigation already in progress');
125
177
 
126
178
  const options = {...this.options, ...stepOptions};
127
179
  const timespan = await startTimespanGather(options);
@@ -130,14 +182,13 @@ class UserFlow {
130
182
 
131
183
  async endTimespan() {
132
184
  if (!this.currentTimespan) throw new Error('No timespan in progress');
185
+ if (this.currentNavigation) throw new Error('Navigation already in progress');
133
186
 
134
187
  const {timespan, options} = this.currentTimespan;
135
188
  const gatherResult = await timespan.endTimespanGather();
136
189
  this.currentTimespan = undefined;
137
190
 
138
191
  this._addGatherStep(gatherResult, options);
139
-
140
- return gatherResult;
141
192
  }
142
193
 
143
194
  /**
@@ -145,13 +196,12 @@ class UserFlow {
145
196
  */
146
197
  async snapshot(stepOptions) {
147
198
  if (this.currentTimespan) throw new Error('Timespan already in progress');
199
+ if (this.currentNavigation) throw new Error('Navigation already in progress');
148
200
 
149
201
  const options = {...this.options, ...stepOptions};
150
202
  const gatherResult = await snapshotGather(options);
151
203
 
152
204
  this._addGatherStep(gatherResult, options);
153
-
154
- return gatherResult;
155
205
  }
156
206
 
157
207
  /**
@@ -65,29 +65,15 @@ class Scripts extends FRGatherer {
65
65
 
66
66
  constructor() {
67
67
  super();
68
- this.onProtocolMessage = this.onProtocolMessage.bind(this);
68
+ this.onScriptParsed = this.onScriptParsed.bind(this);
69
69
  }
70
70
 
71
71
  /**
72
- * @param {LH.Protocol.RawEventMessage} event
72
+ * @param {LH.Crdp.Debugger.ScriptParsedEvent} params
73
73
  */
74
- onProtocolMessage(event) {
75
- // Go read the comments in network-recorder.js _findRealRequestAndSetSession.
76
- let sessionId = event.sessionId;
77
- if (this._mainSessionId === null) {
78
- this._mainSessionId = sessionId;
79
- }
80
- if (this._mainSessionId === sessionId) {
81
- sessionId = undefined;
82
- }
83
-
84
- // We want to ignore scripts from OOPIFs. In reality, this does more than block just OOPIFs,
85
- // it also blocks scripts from the same origin but that happen to run in a different process,
86
- // like a worker.
87
- if (event.method === 'Debugger.scriptParsed' && !sessionId) {
88
- if (!isLighthouseRuntimeEvaluateScript(event.params)) {
89
- this._scriptParsedEvents.push(event.params);
90
- }
74
+ onScriptParsed(params) {
75
+ if (!isLighthouseRuntimeEvaluateScript(params)) {
76
+ this._scriptParsedEvents.push(params);
91
77
  }
92
78
  }
93
79
 
@@ -96,7 +82,7 @@ class Scripts extends FRGatherer {
96
82
  */
97
83
  async startInstrumentation(context) {
98
84
  const session = context.driver.defaultSession;
99
- session.addProtocolMessageListener(this.onProtocolMessage);
85
+ session.on('Debugger.scriptParsed', this.onScriptParsed);
100
86
  await session.sendCommand('Debugger.enable');
101
87
  }
102
88
 
@@ -107,7 +93,7 @@ class Scripts extends FRGatherer {
107
93
  const session = context.driver.defaultSession;
108
94
  const formFactor = context.baseArtifacts.HostFormFactor;
109
95
 
110
- session.removeProtocolMessageListener(this.onProtocolMessage);
96
+ session.off('Debugger.scriptParsed', this.onScriptParsed);
111
97
 
112
98
  // Without this line the Debugger domain will be off in FR runner,
113
99
  // because only the legacy gatherer has special handling for multiple,
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "lighthouse",
3
- "version": "9.5.0-dev.20220612",
3
+ "version": "9.5.0-dev.20220615",
4
4
  "description": "Automated auditing, performance metrics, and best practices for the web.",
5
5
  "main": "./lighthouse-core/index.js",
6
6
  "bin": {