lighthouse 9.5.0-dev.20220607 → 9.5.0-dev.20220608

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.
@@ -1,8 +1,6 @@
1
1
  {
2
2
  "extends": "../tsconfig-base.json",
3
3
  "compilerOptions": {
4
- "outDir": "../.tmp/tsbuildinfo/flow-report",
5
-
6
4
  // Limit to base JS and DOM defs.
7
5
  "lib": ["es2020", "dom", "dom.iterable"],
8
6
  // Selectively include types from node_modules/.
@@ -38,6 +38,7 @@ const BASE_ARTIFACT_BLANKS = {
38
38
  HostUserAgent: '',
39
39
  NetworkUserAgent: '',
40
40
  BenchmarkIndex: '',
41
+ BenchmarkIndexes: '',
41
42
  WebAppManifest: '',
42
43
  GatherContext: '',
43
44
  InstallabilityErrors: '',
@@ -14,6 +14,7 @@ const baseArtifactKeySource = {
14
14
  fetchTime: '',
15
15
  LighthouseRunWarnings: '',
16
16
  BenchmarkIndex: '',
17
+ BenchmarkIndexes: '',
17
18
  settings: '',
18
19
  Timing: '',
19
20
  URL: '',
@@ -16,7 +16,7 @@ const throwNotConnectedFn = () => {
16
16
  };
17
17
 
18
18
  /** @type {LH.Gatherer.FRProtocolSession} */
19
- const defaultSession = {
19
+ const throwingSession = {
20
20
  setTargetInfo: throwNotConnectedFn,
21
21
  hasNextProtocolTimeout: throwNotConnectedFn,
22
22
  getNextProtocolTimeout: throwNotConnectedFn,
@@ -39,14 +39,12 @@ class Driver {
39
39
  */
40
40
  constructor(page) {
41
41
  this._page = page;
42
- /** @type {LH.Gatherer.FRProtocolSession|undefined} */
43
- this._session = undefined;
44
42
  /** @type {ExecutionContext|undefined} */
45
43
  this._executionContext = undefined;
46
44
  /** @type {Fetcher|undefined} */
47
45
  this._fetcher = undefined;
48
46
 
49
- this.defaultSession = defaultSession;
47
+ this.defaultSession = throwingSession;
50
48
  }
51
49
 
52
50
  /** @return {LH.Gatherer.FRTransitionalDriver['executionContext']} */
@@ -68,20 +66,20 @@ class Driver {
68
66
 
69
67
  /** @return {Promise<void>} */
70
68
  async connect() {
71
- if (this._session) return;
69
+ if (this.defaultSession !== throwingSession) return;
72
70
  const status = {msg: 'Connecting to browser', id: 'lh:driver:connect'};
73
71
  log.time(status);
74
72
  const session = await this._page.target().createCDPSession();
75
- this._session = this.defaultSession = new ProtocolSession(session);
76
- this._executionContext = new ExecutionContext(this._session);
77
- this._fetcher = new Fetcher(this._session);
73
+ this.defaultSession = new ProtocolSession(session);
74
+ this._executionContext = new ExecutionContext(this.defaultSession);
75
+ this._fetcher = new Fetcher(this.defaultSession);
78
76
  log.timeEnd(status);
79
77
  }
80
78
 
81
79
  /** @return {Promise<void>} */
82
80
  async disconnect() {
83
- if (!this._session) return;
84
- await this._session.dispose();
81
+ if (this.defaultSession === throwingSession) return;
82
+ await this.defaultSession.dispose();
85
83
  }
86
84
  }
87
85
 
@@ -13,10 +13,10 @@ const DEFAULT_PROTOCOL_TIMEOUT = 30000;
13
13
  /** @implements {LH.Gatherer.FRProtocolSession} */
14
14
  class ProtocolSession {
15
15
  /**
16
- * @param {LH.Puppeteer.CDPSession} session
16
+ * @param {LH.Puppeteer.CDPSession} cdpSession
17
17
  */
18
- constructor(session) {
19
- this._session = session;
18
+ constructor(cdpSession) {
19
+ this._cdpSession = cdpSession;
20
20
  /** @type {LH.Crdp.Target.TargetInfo|undefined} */
21
21
  this._targetInfo = undefined;
22
22
  /** @type {number|undefined} */
@@ -64,7 +64,7 @@ class ProtocolSession {
64
64
  * @param {(...args: LH.CrdpEvents[E]) => void} callback
65
65
  */
66
66
  on(eventName, callback) {
67
- this._session.on(eventName, /** @type {*} */ (callback));
67
+ this._cdpSession.on(eventName, /** @type {*} */ (callback));
68
68
  }
69
69
 
70
70
  /**
@@ -74,7 +74,7 @@ class ProtocolSession {
74
74
  * @param {(...args: LH.CrdpEvents[E]) => void} callback
75
75
  */
76
76
  once(eventName, callback) {
77
- this._session.once(eventName, /** @type {*} */ (callback));
77
+ this._cdpSession.once(eventName, /** @type {*} */ (callback));
78
78
  }
79
79
 
80
80
  /**
@@ -114,7 +114,7 @@ class ProtocolSession {
114
114
  sessionId: this.sessionId(),
115
115
  });
116
116
  this._callbackMap.set(callback, listener);
117
- this._session.on('*', /** @type {*} */ (listener));
117
+ this._cdpSession.on('*', /** @type {*} */ (listener));
118
118
  }
119
119
 
120
120
  /**
@@ -123,7 +123,7 @@ class ProtocolSession {
123
123
  removeProtocolMessageListener(callback) {
124
124
  const listener = this._callbackMap.get(callback);
125
125
  if (!listener) return;
126
- this._session.off('*', /** @type {*} */ (listener));
126
+ this._cdpSession.off('*', /** @type {*} */ (listener));
127
127
  }
128
128
 
129
129
  /**
@@ -133,7 +133,7 @@ class ProtocolSession {
133
133
  * @param {(...args: LH.CrdpEvents[E]) => void} callback
134
134
  */
135
135
  off(eventName, callback) {
136
- this._session.off(eventName, /** @type {*} */ (callback));
136
+ this._cdpSession.off(eventName, /** @type {*} */ (callback));
137
137
  }
138
138
 
139
139
  /**
@@ -156,7 +156,7 @@ class ProtocolSession {
156
156
  }));
157
157
  });
158
158
 
159
- const resultPromise = this._session.send(method, ...params);
159
+ const resultPromise = this._cdpSession.send(method, ...params);
160
160
  const resultWithTimeoutPromise = Promise.race([resultPromise, timeoutPromise]);
161
161
 
162
162
  return resultWithTimeoutPromise.finally(() => {
@@ -169,12 +169,12 @@ class ProtocolSession {
169
169
  * @return {Promise<void>}
170
170
  */
171
171
  async dispose() {
172
- this._session.removeAllListeners();
173
- await this._session.detach();
172
+ this._cdpSession.removeAllListeners();
173
+ await this._cdpSession.detach();
174
174
  }
175
175
 
176
176
  _getConnection() {
177
- const connection = this._session.connection();
177
+ const connection = this._cdpSession.connection();
178
178
  if (!connection) throw new Error('Connection has been closed.');
179
179
  return connection;
180
180
  }
@@ -103,13 +103,20 @@ class NetworkMonitor {
103
103
  };
104
104
 
105
105
  this._networkRecorder.on('requeststarted', reEmit('requeststarted'));
106
- this._networkRecorder.on('requestloaded', reEmit('requestloaded'));
106
+ this._networkRecorder.on('requestfinished', reEmit('requestfinished'));
107
107
 
108
108
  this._session.on('Page.frameNavigated', this._onFrameNavigated);
109
- this._targetManager.addTargetAttachedListener(this._onTargetAttached);
110
-
111
109
  await this._session.sendCommand('Page.enable');
112
- await this._targetManager.enable();
110
+
111
+ // Legacy driver does its own target management.
112
+ // @ts-expect-error
113
+ const isLegacyRunner = Boolean(this._session._domainEnabledCounts);
114
+ if (isLegacyRunner) {
115
+ this._session.addProtocolMessageListener(this._onProtocolMessage);
116
+ } else {
117
+ this._targetManager.addTargetAttachedListener(this._onTargetAttached);
118
+ await this._targetManager.enable();
119
+ }
113
120
  }
114
121
 
115
122
  /**
@@ -119,13 +126,21 @@ class NetworkMonitor {
119
126
  if (!this._targetManager) return;
120
127
 
121
128
  this._session.off('Page.frameNavigated', this._onFrameNavigated);
122
- this._targetManager.removeTargetAttachedListener(this._onTargetAttached);
123
129
 
124
- for (const session of this._sessions.values()) {
125
- session.removeProtocolMessageListener(this._onProtocolMessage);
126
- }
130
+ // Legacy driver does its own target management.
131
+ // @ts-expect-error
132
+ const isLegacyRunner = Boolean(this._session._domainEnabledCounts);
133
+ if (isLegacyRunner) {
134
+ this._session.removeProtocolMessageListener(this._onProtocolMessage);
135
+ } else {
136
+ this._targetManager.removeTargetAttachedListener(this._onTargetAttached);
127
137
 
128
- await this._targetManager.disable();
138
+ for (const session of this._sessions.values()) {
139
+ session.removeProtocolMessageListener(this._onProtocolMessage);
140
+ }
141
+
142
+ await this._targetManager.disable();
143
+ }
129
144
 
130
145
  this._frameNavigations = [];
131
146
  this._networkRecorder = undefined;
@@ -164,7 +164,8 @@ function waitForNetworkIdle(session, networkMonitor, networkQuietOptions) {
164
164
  const inflightRecords = networkMonitor.getInflightRequests();
165
165
  // If there are more than 20 inflight requests, load is still in full swing.
166
166
  // Wait until it calms down a bit to be a little less spammy.
167
- if (inflightRecords.length < 20) {
167
+ if (log.isVerbose() && inflightRecords.length < 20 && inflightRecords.length > 0) {
168
+ log.verbose('waitFor', `=== Waiting on ${inflightRecords.length} requests to finish`);
168
169
  for (const record of inflightRecords) {
169
170
  log.verbose('waitFor', `Waiting on ${record.url.slice(0, 120)} to finish`);
170
171
  }
@@ -172,7 +173,7 @@ function waitForNetworkIdle(session, networkMonitor, networkQuietOptions) {
172
173
  };
173
174
 
174
175
  networkMonitor.on('requeststarted', logStatus);
175
- networkMonitor.on('requestloaded', logStatus);
176
+ networkMonitor.on('requestfinished', logStatus);
176
177
  networkMonitor.on(busyEvent, logStatus);
177
178
 
178
179
  if (!networkQuietOptions.pretendDCLAlreadyFired) {
@@ -192,7 +193,7 @@ function waitForNetworkIdle(session, networkMonitor, networkQuietOptions) {
192
193
  networkMonitor.removeListener(busyEvent, onBusy);
193
194
  networkMonitor.removeListener(idleEvent, onIdle);
194
195
  networkMonitor.removeListener('requeststarted', logStatus);
195
- networkMonitor.removeListener('requestloaded', logStatus);
196
+ networkMonitor.removeListener('requestfinished', logStatus);
196
197
  networkMonitor.removeListener(busyEvent, logStatus);
197
198
  };
198
199
  });
@@ -20,6 +20,7 @@ const WebAppManifest = require('./gatherers/web-app-manifest.js');
20
20
  const InstallabilityErrors = require('./gatherers/installability-errors.js');
21
21
  const NetworkUserAgent = require('./gatherers/network-user-agent.js');
22
22
  const Stacks = require('./gatherers/stacks.js');
23
+ const URL = require('../lib/url-shim.js');
23
24
  const {finalizeArtifacts} = require('../fraggle-rock/gather/base-artifacts.js');
24
25
 
25
26
  /** @typedef {import('../gather/driver.js')} Driver */
@@ -491,6 +492,20 @@ class GatherRunner {
491
492
  const baseArtifacts = await GatherRunner.initializeBaseArtifacts(options);
492
493
  baseArtifacts.BenchmarkIndex = await getBenchmarkIndex(driver.executionContext);
493
494
 
495
+ // Hack for running benchmarkIndex extra times.
496
+ // Add a `bidx=20` query param, eg: https://www.example.com/?bidx=50
497
+ const parsedUrl = URL.isValid(options.requestedUrl) && new URL(options.requestedUrl);
498
+ if (options.settings.channel === 'lr' && parsedUrl && parsedUrl.searchParams.has('bidx')) {
499
+ const bidxRunCount = parsedUrl.searchParams.get('bidx') || 0;
500
+ // Add the first bidx into the new set
501
+ const indexes = [baseArtifacts.BenchmarkIndex];
502
+ for (let i = 0; i < bidxRunCount; i++) {
503
+ const bidx = await getBenchmarkIndex(driver.executionContext);
504
+ indexes.push(bidx);
505
+ }
506
+ baseArtifacts.BenchmarkIndexes = indexes;
507
+ }
508
+
494
509
  await GatherRunner.setupDriver(driver, options);
495
510
 
496
511
  let isFirstPass = true;
@@ -30,7 +30,7 @@ class DevtoolsLog extends FRGatherer {
30
30
  /** @type {NetworkMonitor|undefined} */
31
31
  this._networkMonitor = undefined;
32
32
 
33
- this._messageLog = new MessageLog(/^(Page|Network)\./);
33
+ this._messageLog = new MessageLog(/^(Page|Network|Target|Runtime)\./);
34
34
 
35
35
  /** @param {LH.Protocol.RawEventMessage} e */
36
36
  this._onProtocolMessage = e => this._messageLog.record(e);
@@ -9,7 +9,7 @@ const log = require('lighthouse-logger');
9
9
  const NetworkRequest = require('./network-request.js');
10
10
  const EventEmitter = require('events').EventEmitter;
11
11
 
12
- /** @typedef {'requeststarted'|'requestloaded'} NetworkRecorderEvent */
12
+ /** @typedef {'requeststarted'|'requestfinished'} NetworkRecorderEvent */
13
13
 
14
14
  class NetworkRecorder extends EventEmitter {
15
15
  /**
@@ -71,7 +71,7 @@ class NetworkRecorder extends EventEmitter {
71
71
  * @private
72
72
  */
73
73
  onRequestFinished(request) {
74
- this.emit('requestloaded', request);
74
+ this.emit('requestfinished', request);
75
75
  }
76
76
 
77
77
  // The below methods proxy network data into the NetworkRequest object which mimics the
@@ -95,6 +95,7 @@ class Runner {
95
95
  networkUserAgent: artifacts.NetworkUserAgent,
96
96
  hostUserAgent: artifacts.HostUserAgent,
97
97
  benchmarkIndex: artifacts.BenchmarkIndex,
98
+ benchmarkIndexes: artifacts.BenchmarkIndexes,
98
99
  credits,
99
100
  },
100
101
  audits: auditResultsById,
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "lighthouse",
3
- "version": "9.5.0-dev.20220607",
3
+ "version": "9.5.0-dev.20220608",
4
4
  "description": "Automated auditing, performance metrics, and best practices for the web.",
5
5
  "main": "./lighthouse-core/index.js",
6
6
  "bin": {
@@ -125,8 +125,8 @@
125
125
  "@types/ws": "^7.0.0",
126
126
  "@types/yargs": "^17.0.8",
127
127
  "@types/yargs-parser": "^20.2.1",
128
- "@typescript-eslint/eslint-plugin": "^5.6.0",
129
- "@typescript-eslint/parser": "^5.6.0",
128
+ "@typescript-eslint/eslint-plugin": "^5.26.0",
129
+ "@typescript-eslint/parser": "^5.26.0",
130
130
  "acorn": "^8.5.0",
131
131
  "angular": "^1.7.4",
132
132
  "archiver": "^3.0.0",
@@ -175,7 +175,7 @@
175
175
  "terser": "^5.3.8",
176
176
  "ts-jest": "^27.0.4",
177
177
  "typed-query-selector": "^2.6.1",
178
- "typescript": "^4.5.2",
178
+ "typescript": "^4.7.2",
179
179
  "wait-for-expect": "^3.0.2",
180
180
  "webtreemap-cdt": "^3.2.1"
181
181
  },
@@ -1,8 +1,6 @@
1
1
  {
2
2
  "extends": "../../tsconfig-base.json",
3
3
  "compilerOptions": {
4
- "outDir": "../../.tmp/tsbuildinfo/report/generator",
5
-
6
4
  // Limit defs to base JS and DOM (for URL: https://github.com/DefinitelyTyped/DefinitelyTyped/issues/34960).
7
5
  "lib": ["es2020", "dom"],
8
6
  // Only include `@types/node` from node_modules/.
@@ -57,8 +57,8 @@ export class SwapLocaleFeature {
57
57
  const optionLocaleDisplay = new Intl.DisplayNames([locale], {type: 'language'});
58
58
 
59
59
  const optionLocaleName = optionLocaleDisplay.of(locale);
60
- const currentLocaleName = currentLocaleDisplay.of(locale);
61
- if (optionLocaleName !== currentLocaleName) {
60
+ const currentLocaleName = currentLocaleDisplay.of(locale) || locale;
61
+ if (optionLocaleName && optionLocaleName !== currentLocaleName) {
62
62
  optionEl.textContent = `${optionLocaleName} – ${currentLocaleName}`;
63
63
  } else {
64
64
  optionEl.textContent = currentLocaleName;
@@ -1,8 +1,6 @@
1
1
  {
2
2
  "extends": "../tsconfig-base.json",
3
3
  "compilerOptions": {
4
- "outDir": "../.tmp/tsbuildinfo/report",
5
-
6
4
  // Limit to base JS and DOM defs.
7
5
  "lib": ["es2020", "dom", "dom.iterable"],
8
6
  // Don't include any types from node_modules/.
@@ -1,8 +1,6 @@
1
1
  {
2
2
  "extends": "../tsconfig-base.json",
3
3
  "compilerOptions": {
4
- "outDir": "../../.tmp/tsbuildinfo/shared/",
5
-
6
4
  // Limit defs to base JS.
7
5
  "lib": ["es2020"],
8
6
  // Only include `@types/node` from node_modules/.
@@ -3,8 +3,13 @@
3
3
  {
4
4
  "compilerOptions": {
5
5
  "composite": true,
6
+
7
+ // Set up incremental builds. All sub-projects emit under outDir, maintaining
8
+ // directory structure relative to rootDir. No effect on include, exclude, etc.
6
9
  "emitDeclarationOnly": true,
7
10
  "declarationMap": true,
11
+ "outDir": ".tmp/tsbuildinfo/",
12
+ "rootDir": ".",
8
13
 
9
14
  "target": "es2020",
10
15
  "module": "es2020",
package/tsconfig.json CHANGED
@@ -1,8 +1,6 @@
1
1
  {
2
2
  "extends": "./tsconfig-base.json",
3
3
  "compilerOptions": {
4
- "outDir": ".tmp/tsbuildinfo/",
5
-
6
4
  // TODO(esmodules): included to support require('file.json'). Remove on the switch to ES Modules.
7
5
  "resolveJsonModule": true,
8
6
  },
@@ -49,6 +49,8 @@ interface UniversalBaseArtifacts {
49
49
  LighthouseRunWarnings: Array<string | IcuMessage>;
50
50
  /** The benchmark index that indicates rough device class. */
51
51
  BenchmarkIndex: number;
52
+ /** Many benchmark indexes. Many. */
53
+ BenchmarkIndexes?: number[];
52
54
  /** An object containing information about the testing configuration used by Lighthouse. */
53
55
  settings: Config.Settings;
54
56
  /** The timing instrumentation of the gather portion of a run. */
@@ -59,6 +59,8 @@ declare module Result {
59
59
  networkUserAgent: string;
60
60
  /** The benchmark index number that indicates rough device class. */
61
61
  benchmarkIndex: number;
62
+ /** Many benchmark indexes. */
63
+ benchmarkIndexes?: number[];
62
64
  /** The version of libraries with which these results were generated. Ex: axe-core. */
63
65
  credits?: Record<string, string|undefined>,
64
66
  }
@@ -1,8 +1,6 @@
1
1
  {
2
2
  "extends": "../../tsconfig-base.json",
3
3
  "compilerOptions": {
4
- "outDir": "../../.tmp/tsbuildinfo/types/lhr",
5
-
6
4
  // We only need the base JS definitions, no DOM, etc.
7
5
  "lib": ["esnext"],
8
6
  // Don't include any types from node_modules/.
@@ -11,6 +11,7 @@ declare module 'lighthouse-logger' {
11
11
  args?: any[];
12
12
  }
13
13
  export function setLevel(level: string): void;
14
+ export function isVerbose(): boolean;
14
15
  export function formatProtocol(prefix: string, data: Object, level?: string): void;
15
16
  export function log(title: string, ...args: any[]): void;
16
17
  export function warn(title: string, ...args: any[]): void;