lighthouse 9.5.0-dev.20220413 → 9.5.0-dev.20220416

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.
@@ -194,27 +194,6 @@ async function potentiallyKillChrome(launchedChrome) {
194
194
  });
195
195
  }
196
196
 
197
- /**
198
- * @param {string} url
199
- * @param {LH.CliFlags} flags
200
- * @param {LH.Config.Json|undefined} config
201
- * @param {ChromeLauncher.LaunchedChrome} launchedChrome
202
- * @return {Promise<LH.RunnerResult|undefined>}
203
- */
204
- async function runLighthouseWithFraggleRock(url, flags, config, launchedChrome) {
205
- const fraggleRock = (await import('../lighthouse-core/fraggle-rock/api.js')).default;
206
- const puppeteer = (await import('puppeteer')).default;
207
- const browser = await puppeteer.connect({browserURL: `http://localhost:${launchedChrome.port}`});
208
- const page = await browser.newPage();
209
- flags.channel = 'fraggle-rock-cli';
210
- const configContext = {
211
- configPath: flags.configPath,
212
- settingsOverrides: flags,
213
- logLevel: flags.logLevel,
214
- };
215
- return fraggleRock.navigation(url, {page, config, configContext});
216
- }
217
-
218
197
  /**
219
198
  * @param {string} url
220
199
  * @param {LH.CliFlags} flags
@@ -247,9 +226,15 @@ async function runLighthouse(url, flags, config) {
247
226
  flags.port = launchedChrome.port;
248
227
  }
249
228
 
250
- const runnerResult = flags.fraggleRock && launchedChrome ?
251
- await runLighthouseWithFraggleRock(url, flags, config, launchedChrome) :
252
- await lighthouse(url, flags, config);
229
+ if (flags.fraggleRock) {
230
+ flags.channel = 'fraggle-rock-cli';
231
+ } else {
232
+ flags.channel = 'cli';
233
+ }
234
+
235
+ const runnerResult = flags.fraggleRock ?
236
+ await lighthouse(url, flags, config) :
237
+ await lighthouse.legacyNavigation(url, flags, config);
253
238
 
254
239
  // If in gatherMode only, there will be no runnerResult.
255
240
  if (runnerResult) {
@@ -13,11 +13,13 @@
13
13
 
14
14
  import fs from 'fs';
15
15
 
16
+ import puppeteer from 'puppeteer-core';
16
17
  import ChromeLauncher from 'chrome-launcher';
17
18
 
18
19
  import ChromeProtocol from '../../../../lighthouse-core/gather/connections/cri.js';
19
20
  import {LH_ROOT} from '../../../../root.js';
20
21
 
22
+ const originalBuffer = global.Buffer;
21
23
  const originalRequire = global.require;
22
24
  if (typeof globalThis === 'undefined') {
23
25
  // @ts-expect-error - exposing for loading of dt-bundle.
@@ -28,28 +30,38 @@ if (typeof globalThis === 'undefined') {
28
30
  eval(fs.readFileSync(LH_ROOT + '/dist/lighthouse-dt-bundle.js', 'utf-8'));
29
31
 
30
32
  global.require = originalRequire;
33
+ global.Buffer = originalBuffer;
31
34
 
32
35
  /** @type {import('../../../../lighthouse-core/index.js')} */
33
36
  // @ts-expect-error - not worth giving test global an actual type.
34
37
  const lighthouse = global.runBundledLighthouse;
35
38
 
36
39
  /**
37
- * Launch Chrome and do a full Lighthouse run via the Lighthouse CLI.
40
+ * Launch Chrome and do a full Lighthouse run via the Lighthouse DevTools bundle.
38
41
  * @param {string} url
39
42
  * @param {LH.Config.Json=} configJson
40
- * @param {{isDebug?: boolean}=} testRunnerOptions
43
+ * @param {{isDebug?: boolean, useFraggleRock?: boolean}=} testRunnerOptions
41
44
  * @return {Promise<{lhr: LH.Result, artifacts: LH.Artifacts, log: string}>}
42
45
  */
43
46
  async function runLighthouse(url, configJson, testRunnerOptions = {}) {
44
47
  // Launch and connect to Chrome.
45
48
  const launchedChrome = await ChromeLauncher.launch();
46
49
  const port = launchedChrome.port;
47
- const connection = new ChromeProtocol(port);
48
50
 
49
51
  try {
50
52
  // Run Lighthouse.
51
53
  const logLevel = testRunnerOptions.isDebug ? 'info' : undefined;
52
- const runnerResult = await lighthouse(url, {port, logLevel}, configJson, connection);
54
+ let runnerResult;
55
+ if (testRunnerOptions.useFraggleRock) {
56
+ // Puppeteer is not included in the bundle, we must create the page here.
57
+ const browser = await puppeteer.connect({browserURL: `http://localhost:${port}`});
58
+ const page = await browser.newPage();
59
+ runnerResult = await lighthouse(url, {port, logLevel}, configJson, page);
60
+ } else {
61
+ const connection = new ChromeProtocol(port);
62
+ runnerResult =
63
+ await lighthouse.legacyNavigation(url, {port, logLevel}, configJson, connection);
64
+ }
53
65
  if (!runnerResult) throw new Error('No runnerResult');
54
66
 
55
67
  return {
@@ -220,10 +220,10 @@ function makeComparison(name, actualResult, expectedResult) {
220
220
  * @param {LocalConsole} localConsole
221
221
  * @param {LH.Result} lhr
222
222
  * @param {Smokehouse.ExpectedRunnerResult} expected
223
- * @param {{runner?: string, isBundled?: boolean}=} reportOptions
223
+ * @param {{runner?: string, isBundled?: boolean, useFraggleRock?: boolean}=} reportOptions
224
224
  */
225
225
  function pruneExpectations(localConsole, lhr, expected, reportOptions) {
226
- const isFraggleRock = lhr.configSettings.channel === 'fraggle-rock-cli';
226
+ const isFraggleRock = reportOptions?.useFraggleRock;
227
227
  const isBundled = reportOptions?.isBundled;
228
228
 
229
229
  /**
@@ -456,7 +456,7 @@ function reportAssertion(localConsole, assertion) {
456
456
  * summary. Returns count of passed and failed tests.
457
457
  * @param {{lhr: LH.Result, artifacts: LH.Artifacts, networkRequests?: string[]}} actual
458
458
  * @param {Smokehouse.ExpectedRunnerResult} expected
459
- * @param {{runner?: string, isDebug?: boolean, isBundled?: boolean}=} reportOptions
459
+ * @param {{runner?: string, isDebug?: boolean, isBundled?: boolean, useFraggleRock?: boolean}=} reportOptions
460
460
  * @return {{passed: number, failed: number, log: string}}
461
461
  */
462
462
  function getAssertionReport(actual, expected, reportOptions = {}) {
@@ -162,6 +162,7 @@ async function runSmokeTest(smokeTestDefn, testOptions) {
162
162
  report = getAssertionReport(result, expectations, {
163
163
  runner: lighthouseRunner.runnerName,
164
164
  isDebug,
165
+ useFraggleRock,
165
166
  });
166
167
 
167
168
  runs.push({
@@ -13,7 +13,7 @@ const {generateFlowReportHtml} = require('../../report/generator/report-generato
13
13
  const Runner = require('../runner.js');
14
14
 
15
15
  /**
16
- * @param {import('puppeteer').Page} page
16
+ * @param {LH.Puppeteer.Page} page
17
17
  * @param {ConstructorParameters<LH.UserFlow>[1]} [options]
18
18
  */
19
19
  async function startFlow(page, options) {
@@ -35,7 +35,7 @@ const defaultSession = {
35
35
  /** @implements {LH.Gatherer.FRTransitionalDriver} */
36
36
  class Driver {
37
37
  /**
38
- * @param {import('puppeteer').Page} page
38
+ * @param {LH.Puppeteer.Page} page
39
39
  */
40
40
  constructor(page) {
41
41
  this._page = page;
@@ -298,8 +298,8 @@ async function _cleanup({requestedUrl, driver, config}) {
298
298
  }
299
299
 
300
300
  /**
301
- * @param {LH.NavigationRequestor} requestor
302
- * @param {{page: import('puppeteer').Page, config?: LH.Config.Json, configContext?: LH.Config.FRContext}} options
301
+ * @param {LH.NavigationRequestor|undefined} requestor
302
+ * @param {{page: LH.Puppeteer.Page, config?: LH.Config.Json, configContext?: LH.Config.FRContext}} options
303
303
  * @return {Promise<LH.Gatherer.FRGatherResult>}
304
304
  */
305
305
  async function navigationGather(requestor, options) {
@@ -313,7 +313,8 @@ async function navigationGather(requestor, options) {
313
313
  };
314
314
 
315
315
  // We can't trigger the navigation through user interaction if we reset the page before starting.
316
- if (typeof requestor !== 'string') {
316
+ const isCallback = typeof requestor === 'function';
317
+ if (isCallback) {
317
318
  internalOptions.skipAboutBlank = true;
318
319
  }
319
320
 
@@ -324,7 +325,7 @@ async function navigationGather(requestor, options) {
324
325
  const context = {
325
326
  driver,
326
327
  config,
327
- requestor: typeof requestor === 'string' ? URL.normalizeUrl(requestor) : requestor,
328
+ requestor: isCallback ? requestor : URL.normalizeUrl(requestor),
328
329
  options: internalOptions,
329
330
  };
330
331
  const {baseArtifacts} = await _setup(context);
@@ -14,7 +14,7 @@ const DEFAULT_PROTOCOL_TIMEOUT = 30000;
14
14
  /** @implements {LH.Gatherer.FRProtocolSession} */
15
15
  class ProtocolSession {
16
16
  /**
17
- * @param {import('puppeteer').CDPSession} session
17
+ * @param {LH.Puppeteer.CDPSession} session
18
18
  */
19
19
  constructor(session) {
20
20
  this._session = session;
@@ -93,7 +93,7 @@ class ProtocolSession {
93
93
  * @param {(session: ProtocolSession) => void} callback
94
94
  */
95
95
  addSessionAttachedListener(callback) {
96
- /** @param {import('puppeteer').CDPSession} session */
96
+ /** @param {LH.Puppeteer.CDPSession} session */
97
97
  const listener = session => callback(new ProtocolSession(session));
98
98
  this._callbackMap.set(callback, listener);
99
99
  this._session.connection().on('sessionattached', listener);
@@ -17,7 +17,7 @@ const {initializeConfig} = require('../config/config.js');
17
17
  const {getBaseArtifacts, finalizeArtifacts} = require('./base-artifacts.js');
18
18
 
19
19
  /**
20
- * @param {{page: import('puppeteer').Page, config?: LH.Config.Json, configContext?: LH.Config.FRContext}} options
20
+ * @param {{page: LH.Puppeteer.Page, config?: LH.Config.Json, configContext?: LH.Config.FRContext}} options
21
21
  * @return {Promise<LH.Gatherer.FRGatherResult>}
22
22
  */
23
23
  async function snapshotGather(options) {
@@ -18,7 +18,7 @@ const {initializeConfig} = require('../config/config.js');
18
18
  const {getBaseArtifacts, finalizeArtifacts} = require('./base-artifacts.js');
19
19
 
20
20
  /**
21
- * @param {{page: import('puppeteer').Page, config?: LH.Config.Json, configContext?: LH.Config.FRContext}} options
21
+ * @param {{page: LH.Puppeteer.Page, config?: LH.Config.Json, configContext?: LH.Config.FRContext}} options
22
22
  * @return {Promise<{endTimespanGather(): Promise<LH.Gatherer.FRGatherResult>}>}
23
23
  */
24
24
  async function startTimespanGather(options) {
@@ -5,14 +5,19 @@
5
5
  */
6
6
  'use strict';
7
7
 
8
+ const puppeteer = require('puppeteer-core');
8
9
  const Runner = require('./runner.js');
9
10
  const log = require('lighthouse-logger');
10
11
  const ChromeProtocol = require('./gather/connections/cri.js');
11
12
  const Config = require('./config/config.js');
12
13
  const URL = require('./lib/url-shim.js');
14
+ const fraggleRock = require('./fraggle-rock/api.js');
13
15
 
14
16
  /** @typedef {import('./gather/connections/connection.js')} Connection */
15
17
 
18
+ const DEFAULT_HOSTNAME = '127.0.0.1';
19
+ const DEFAULT_PORT = 9222;
20
+
16
21
  /*
17
22
  * The relationship between these root modules:
18
23
  *
@@ -33,10 +38,35 @@ const URL = require('./lib/url-shim.js');
33
38
  * they will override any settings in the config.
34
39
  * @param {LH.Config.Json=} configJSON Configuration for the Lighthouse run. If
35
40
  * not present, the default config is used.
41
+ * @param {LH.Puppeteer.Page=} page
42
+ * @return {Promise<LH.RunnerResult|undefined>}
43
+ */
44
+ async function lighthouse(url, flags = {}, configJSON, page) {
45
+ if (!page) {
46
+ const {hostname = DEFAULT_HOSTNAME, port = DEFAULT_PORT} = flags;
47
+ const browser = await puppeteer.connect({browserURL: `http://${hostname}:${port}`});
48
+ page = await browser.newPage();
49
+ }
50
+ const configContext = {
51
+ configPath: flags.configPath,
52
+ settingsOverrides: flags,
53
+ logLevel: flags.logLevel,
54
+ };
55
+ return fraggleRock.navigation(url, {page, config: configJSON, configContext});
56
+ }
57
+
58
+ /**
59
+ * Run Lighthouse using the legacy navigation runner.
60
+ * This is left in place for any clients that don't support FR navigations yet (e.g. Lightrider)
61
+ * @param {string=} url The URL to test. Optional if running in auditMode.
62
+ * @param {LH.Flags=} flags Optional settings for the Lighthouse run. If present,
63
+ * they will override any settings in the config.
64
+ * @param {LH.Config.Json=} configJSON Configuration for the Lighthouse run. If
65
+ * not present, the default config is used.
36
66
  * @param {Connection=} userConnection
37
67
  * @return {Promise<LH.RunnerResult|undefined>}
38
68
  */
39
- async function lighthouse(url, flags = {}, configJSON, userConnection) {
69
+ async function legacyNavigation(url, flags = {}, configJSON, userConnection) {
40
70
  // set logging preferences, assume quiet
41
71
  flags.logLevel = flags.logLevel || 'error';
42
72
  log.setLevel(flags.logLevel);
@@ -66,6 +96,7 @@ function generateConfig(configJson, flags) {
66
96
  return new Config(configJson, flags);
67
97
  }
68
98
 
99
+ lighthouse.legacyNavigation = legacyNavigation;
69
100
  lighthouse.generateConfig = generateConfig;
70
101
  lighthouse.getAuditList = Runner.getAuditList;
71
102
  lighthouse.traceCategories = require('./gather/driver.js').traceCategories;
@@ -82,11 +82,15 @@ class TraceProcessor {
82
82
  * Returns true if the event is a navigation start event of a document whose URL seems valid.
83
83
  *
84
84
  * @param {LH.TraceEvent} event
85
+ * @return {boolean}
85
86
  */
86
87
  static _isNavigationStartOfInterest(event) {
87
- return event.name === 'navigationStart' &&
88
- (!event.args.data || !event.args.data.documentLoaderURL ||
89
- ACCEPTABLE_NAVIGATION_URL_REGEX.test(event.args.data.documentLoaderURL));
88
+ if (event.name !== 'navigationStart') return false;
89
+ // COMPAT: support pre-m67 test traces before `args.data` added to all navStart events.
90
+ // TODO: remove next line when old test traces (e.g. progressive-app-m60.json) are updated.
91
+ if (event.args.data?.documentLoaderURL === undefined) return true;
92
+ if (!event.args.data?.documentLoaderURL) return false;
93
+ return ACCEPTABLE_NAVIGATION_URL_REGEX.test(event.args.data.documentLoaderURL);
90
94
  }
91
95
 
92
96
  /**
@@ -462,8 +466,9 @@ class TraceProcessor {
462
466
  // If we can't find either TracingStarted event, then we'll fallback to the first navStart that
463
467
  // looks like it was loading the main frame with a real URL. Because the schema for this event
464
468
  // has changed across Chrome versions, we'll be extra defensive about finding this case.
465
- const navStartEvt = events.find(e => Boolean(e.name === 'navigationStart' &&
466
- e.args?.data?.isLoadingMainFrame && e.args.data.documentLoaderURL));
469
+ const navStartEvt = events.find(e =>
470
+ this._isNavigationStartOfInterest(e) && e.args.data?.isLoadingMainFrame
471
+ );
467
472
  // Find the first resource that was requested and make sure it agrees on the id.
468
473
  const firstResourceSendEvt = events.find(e => e.name === 'ResourceSendRequest');
469
474
  // We know that these properties exist if we found the events, but TSC doesn't.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "lighthouse",
3
- "version": "9.5.0-dev.20220413",
3
+ "version": "9.5.0-dev.20220416",
4
4
  "description": "Automated auditing, performance metrics, and best practices for the web.",
5
5
  "main": "./lighthouse-core/index.js",
6
6
  "bin": {
@@ -24,7 +24,7 @@
24
24
  "build-smokehouse-bundle": "node ./build/build-smokehouse-bundle.js",
25
25
  "build-lr": "yarn reset-link && node ./build/build-lightrider-bundles.js",
26
26
  "build-pack": "bash build/build-pack.sh",
27
- "build-report": "node build/build-report-components.js && yarn eslint --fix report/renderer/components.js && bash lighthouse-core/scripts/copy-util-commonjs.sh && node build/build-report.js",
27
+ "build-report": "node build/build-report-components.js && bash lighthouse-core/scripts/copy-util-commonjs.sh && node build/build-report.js",
28
28
  "build-sample-reports": "yarn build-report && node build/build-sample-reports.js",
29
29
  "build-treemap": "node ./build/build-treemap.js",
30
30
  "build-viewer": "node ./build/build-viewer.js",
@@ -37,7 +37,7 @@
37
37
  "start": "yarn build-report --standalone && node ./lighthouse-cli/index.js",
38
38
  "jest": "node --experimental-vm-modules ./node_modules/jest/bin/jest.js",
39
39
  "test": "yarn diff:sample-json && yarn lint --quiet && yarn unit && yarn type-check",
40
- "test-bundle": "yarn smoke --runner bundle -j=1 --retries=2 --invert-match forms",
40
+ "test-bundle": "yarn smoke --runner bundle -j=1 --retries=2",
41
41
  "test-clients": "yarn jest \"$PWD/clients/\" && yarn jest --testMatch=\"**/clients/test/**/*-test-pptr.js\"",
42
42
  "test-viewer": "yarn unit-viewer && yarn jest --testMatch=\"**/viewer/**/*-test-pptr.js\"",
43
43
  "test-treemap": "yarn unit-treemap && yarn jest --testMatch=\"**/treemap/**/*-test-pptr.js\"",
@@ -164,7 +164,7 @@
164
164
  "pako": "^2.0.3",
165
165
  "preact": "^10.5.14",
166
166
  "pretty-json-stringify": "^0.0.2",
167
- "puppeteer": "^10.2.0",
167
+ "puppeteer": "10.2.0",
168
168
  "resolve": "^1.20.0",
169
169
  "rollup": "^2.52.7",
170
170
  "rollup-plugin-node-resolve": "^5.2.0",
@@ -200,6 +200,7 @@
200
200
  "open": "^8.4.0",
201
201
  "parse-cache-control": "1.0.1",
202
202
  "ps-list": "^8.0.0",
203
+ "puppeteer-core": "^10.2.0",
203
204
  "robots-parser": "^3.0.0",
204
205
  "semver": "^5.3.0",
205
206
  "speedline-core": "^1.4.3",
@@ -209,7 +210,8 @@
209
210
  "yargs-parser": "^21.0.0"
210
211
  },
211
212
  "resolutions": {
212
- "puppeteer/**/devtools-protocol": "0.0.975298"
213
+ "puppeteer/**/devtools-protocol": "0.0.975298",
214
+ "puppeteer-core/**/devtools-protocol": "0.0.975298"
213
215
  },
214
216
  "repository": "GoogleChrome/lighthouse",
215
217
  "keywords": [