lighthouse 11.7.0-dev.20240415 → 11.7.0-dev.20240417
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/cli/bin.js +0 -7
- package/cli/cli-flags.d.ts +1 -5
- package/cli/cli-flags.js +1 -5
- package/cli/test/smokehouse/config/exclusions.js +2 -0
- package/cli/test/smokehouse/core-tests.js +2 -2
- package/core/audits/byte-efficiency/render-blocking-resources.js +3 -1
- package/core/audits/byte-efficiency/unminified-css.js +2 -2
- package/core/audits/byte-efficiency/unused-css-rules.js +3 -1
- package/core/audits/font-display.js +2 -2
- package/core/audits/resource-summary.d.ts +2 -0
- package/core/audits/resource-summary.js +5 -4
- package/core/audits/seo/link-text.js +12 -0
- package/core/computed/page-dependency-graph.js +1 -6
- package/core/computed/resource-summary.d.ts +10 -12
- package/core/computed/resource-summary.js +12 -19
- package/core/computed/unused-css.d.ts +3 -1
- package/core/computed/unused-css.js +6 -5
- package/core/config/config-helpers.js +0 -4
- package/core/config/constants.js +0 -1
- package/core/config/default-config.js +1 -14
- package/core/gather/driver/navigation.js +4 -1
- package/core/gather/driver/prepare.js +1 -1
- package/core/gather/driver/target-manager.js +3 -2
- package/core/gather/driver.d.ts +12 -0
- package/core/gather/driver.js +26 -0
- package/core/gather/gatherers/css-usage.d.ts +0 -21
- package/core/gather/gatherers/css-usage.js +9 -119
- package/core/gather/gatherers/stylesheets.d.ts +26 -0
- package/core/gather/gatherers/stylesheets.js +138 -0
- package/core/gather/navigation-runner.js +3 -1
- package/core/gather/session.js +2 -1
- package/core/lib/emulation.js +2 -2
- package/core/lib/i18n/i18n.d.ts +0 -1
- package/core/lib/i18n/i18n.js +0 -2
- package/core/lib/lh-error.d.ts +9 -0
- package/core/lib/lh-error.js +10 -0
- package/core/lib/navigation-error.js +3 -0
- package/core/runner.js +0 -1
- package/dist/report/bundle.esm.js +2 -19
- package/dist/report/flow.js +5 -22
- package/dist/report/standalone.js +3 -20
- package/package.json +3 -3
- package/readme.md +2 -2
- package/report/assets/styles.css +0 -17
- package/report/renderer/components.js +1 -1
- package/report/renderer/dom.d.ts +1 -1
- package/report/renderer/dom.js +1 -1
- package/report/renderer/performance-category-renderer.js +0 -21
- package/shared/localization/locales/ar-XB.json +61 -91
- package/shared/localization/locales/ar.json +61 -91
- package/shared/localization/locales/bg.json +61 -91
- package/shared/localization/locales/ca.json +61 -91
- package/shared/localization/locales/cs.json +61 -91
- package/shared/localization/locales/da.json +61 -91
- package/shared/localization/locales/de.json +61 -91
- package/shared/localization/locales/el.json +61 -91
- package/shared/localization/locales/en-GB.json +61 -91
- package/shared/localization/locales/en-US.json +3 -30
- package/shared/localization/locales/en-XA.json +61 -91
- package/shared/localization/locales/en-XL.json +3 -30
- package/shared/localization/locales/es-419.json +61 -91
- package/shared/localization/locales/es.json +61 -91
- package/shared/localization/locales/fi.json +61 -91
- package/shared/localization/locales/fil.json +60 -90
- package/shared/localization/locales/fr.json +61 -91
- package/shared/localization/locales/he.json +61 -91
- package/shared/localization/locales/hi.json +61 -91
- package/shared/localization/locales/hr.json +62 -92
- package/shared/localization/locales/hu.json +61 -91
- package/shared/localization/locales/id.json +61 -91
- package/shared/localization/locales/it.json +61 -91
- package/shared/localization/locales/ja.json +61 -91
- package/shared/localization/locales/ko.json +61 -91
- package/shared/localization/locales/lt.json +61 -91
- package/shared/localization/locales/lv.json +61 -91
- package/shared/localization/locales/nl.json +61 -91
- package/shared/localization/locales/no.json +61 -91
- package/shared/localization/locales/pl.json +60 -90
- package/shared/localization/locales/pt-PT.json +61 -91
- package/shared/localization/locales/pt.json +63 -93
- package/shared/localization/locales/ro.json +61 -91
- package/shared/localization/locales/ru.json +61 -91
- package/shared/localization/locales/sk.json +61 -91
- package/shared/localization/locales/sl.json +61 -91
- package/shared/localization/locales/sr-Latn.json +61 -91
- package/shared/localization/locales/sr.json +61 -91
- package/shared/localization/locales/sv.json +61 -91
- package/shared/localization/locales/ta.json +60 -90
- package/shared/localization/locales/te.json +61 -91
- package/shared/localization/locales/th.json +61 -91
- package/shared/localization/locales/tr.json +61 -91
- package/shared/localization/locales/uk.json +61 -91
- package/shared/localization/locales/vi.json +60 -90
- package/shared/localization/locales/zh-HK.json +61 -91
- package/shared/localization/locales/zh-TW.json +60 -90
- package/shared/localization/locales/zh.json +61 -91
- package/tsconfig.json +0 -1
- package/types/artifacts.d.ts +3 -1
- package/types/externs.d.ts +0 -2
- package/types/gatherer.d.ts +2 -0
- package/types/lh.d.ts +0 -2
- package/types/lhr/settings.d.ts +0 -4
- package/core/audits/performance-budget.d.ts +0 -39
- package/core/audits/performance-budget.js +0 -154
- package/core/audits/timing-budget.d.ts +0 -43
- package/core/audits/timing-budget.js +0 -175
- package/core/config/budget.d.ts +0 -74
- package/core/config/budget.js +0 -340
- package/types/lhr/budget.d.ts +0 -60
package/cli/bin.js
CHANGED
|
@@ -79,13 +79,6 @@ async function begin() {
|
|
|
79
79
|
config = (await import(`../core/config/${cliFlags.preset}-config.js`)).default;
|
|
80
80
|
}
|
|
81
81
|
|
|
82
|
-
if (cliFlags.budgetPath) {
|
|
83
|
-
cliFlags.budgetPath = path.resolve(process.cwd(), cliFlags.budgetPath);
|
|
84
|
-
/** @type {Array<LH.Budget>} */
|
|
85
|
-
const parsedBudget = JSON.parse(fs.readFileSync(cliFlags.budgetPath, 'utf8'));
|
|
86
|
-
cliFlags.budgets = parsedBudget;
|
|
87
|
-
}
|
|
88
|
-
|
|
89
82
|
// set logging preferences
|
|
90
83
|
cliFlags.logLevel = 'info';
|
|
91
84
|
if (cliFlags.verbose) {
|
package/cli/cli-flags.d.ts
CHANGED
|
@@ -24,7 +24,7 @@ export function getYargsParser(manualArgv?: string | undefined): yargs.Argv<yarg
|
|
|
24
24
|
default: boolean;
|
|
25
25
|
describe: string;
|
|
26
26
|
};
|
|
27
|
-
}>, "port" | "screenEmulation" | "emulatedUserAgent" | "hostname" | "preset" | "save-assets" | "list-all-audits" | "list-locales" | "list-trace-categories" | "debug-navigation" | "additional-trace-categories" | "config-path" | "chrome-flags" | "form-factor" | "max-wait-for-load" | "enable-error-reporting" | "gather-mode" | "audit-mode" | "only-audits" | "only-categories" | "skip-audits" | "
|
|
27
|
+
}>, "port" | "screenEmulation" | "emulatedUserAgent" | "hostname" | "preset" | "save-assets" | "list-all-audits" | "list-locales" | "list-trace-categories" | "debug-navigation" | "additional-trace-categories" | "config-path" | "chrome-flags" | "form-factor" | "max-wait-for-load" | "enable-error-reporting" | "gather-mode" | "audit-mode" | "only-audits" | "only-categories" | "skip-audits" | "disable-full-page-screenshot" | "ignore-status-code"> & yargs.InferredOptionTypes<{
|
|
28
28
|
'save-assets': {
|
|
29
29
|
type: "boolean";
|
|
30
30
|
default: boolean;
|
|
@@ -125,10 +125,6 @@ export function getYargsParser(manualArgv?: string | undefined): yargs.Argv<yarg
|
|
|
125
125
|
coerce: typeof splitCommaSeparatedValues;
|
|
126
126
|
describe: string;
|
|
127
127
|
};
|
|
128
|
-
'budget-path': {
|
|
129
|
-
type: "string";
|
|
130
|
-
describe: string;
|
|
131
|
-
};
|
|
132
128
|
'disable-full-page-screenshot': {
|
|
133
129
|
type: "boolean";
|
|
134
130
|
describe: string;
|
package/cli/cli-flags.js
CHANGED
|
@@ -196,10 +196,6 @@ function getYargsParser(manualArgv) {
|
|
|
196
196
|
coerce: splitCommaSeparatedValues,
|
|
197
197
|
describe: 'Run everything except these audits',
|
|
198
198
|
},
|
|
199
|
-
'budget-path': {
|
|
200
|
-
type: 'string',
|
|
201
|
-
describe: 'The path to the budget.json file for LightWallet.',
|
|
202
|
-
},
|
|
203
199
|
'disable-full-page-screenshot': {
|
|
204
200
|
type: 'boolean',
|
|
205
201
|
describe: 'Disables collection of the full page screenshot, which can be quite large',
|
|
@@ -213,7 +209,7 @@ function getYargsParser(manualArgv) {
|
|
|
213
209
|
'save-assets', 'list-all-audits', 'list-locales', 'list-trace-categories', 'additional-trace-categories',
|
|
214
210
|
'config-path', 'preset', 'chrome-flags', 'port', 'hostname', 'form-factor', 'screenEmulation', 'emulatedUserAgent',
|
|
215
211
|
'max-wait-for-load', 'enable-error-reporting', 'gather-mode', 'audit-mode',
|
|
216
|
-
'only-audits', 'only-categories', 'skip-audits', '
|
|
212
|
+
'only-audits', 'only-categories', 'skip-audits', 'disable-full-page-screenshot', 'ignore-status-code',
|
|
217
213
|
], 'Configuration:')
|
|
218
214
|
|
|
219
215
|
// Output
|
|
@@ -26,6 +26,8 @@ const exclusions = {
|
|
|
26
26
|
'metrics-tricky-tti', 'metrics-tricky-tti-late-fcp', 'screenshot',
|
|
27
27
|
// Disabled because of differences that need further investigation
|
|
28
28
|
'byte-efficiency', 'byte-gzip', 'perf-preload',
|
|
29
|
+
// Disabled because a renderer crash also breaks devtools frontend
|
|
30
|
+
'crash',
|
|
29
31
|
],
|
|
30
32
|
};
|
|
31
33
|
|
|
@@ -7,6 +7,7 @@
|
|
|
7
7
|
import a11y from './test-definitions/a11y.js';
|
|
8
8
|
import byteEfficiency from './test-definitions/byte-efficiency.js';
|
|
9
9
|
import byteGzip from './test-definitions/byte-gzip.js';
|
|
10
|
+
import crash from './test-definitions/crash.js';
|
|
10
11
|
import cspAllowAll from './test-definitions/csp-allow-all.js';
|
|
11
12
|
import cspBlockAll from './test-definitions/csp-block-all.js';
|
|
12
13
|
import dbw from './test-definitions/dobetterweb.js';
|
|
@@ -34,7 +35,6 @@ import metricsTrickyTti from './test-definitions/metrics-tricky-tti.js';
|
|
|
34
35
|
import metricsTrickyTtiLateFcp from './test-definitions/metrics-tricky-tti-late-fcp.js';
|
|
35
36
|
import oopifRequests from './test-definitions/oopif-requests.js';
|
|
36
37
|
import oopifScripts from './test-definitions/oopif-scripts.js';
|
|
37
|
-
import perfBudgets from './test-definitions/perf-budgets.js';
|
|
38
38
|
import perfDebug from './test-definitions/perf-debug.js';
|
|
39
39
|
import perfDiagnosticsAnimations from './test-definitions/perf-diagnostics-animations.js';
|
|
40
40
|
import perfDiagnosticsThirdParty from './test-definitions/perf-diagnostics-third-party.js';
|
|
@@ -65,6 +65,7 @@ const smokeTests = [
|
|
|
65
65
|
a11y,
|
|
66
66
|
byteEfficiency,
|
|
67
67
|
byteGzip,
|
|
68
|
+
crash,
|
|
68
69
|
cspAllowAll,
|
|
69
70
|
cspBlockAll,
|
|
70
71
|
dbw,
|
|
@@ -92,7 +93,6 @@ const smokeTests = [
|
|
|
92
93
|
metricsTrickyTtiLateFcp,
|
|
93
94
|
oopifRequests,
|
|
94
95
|
oopifScripts,
|
|
95
|
-
perfBudgets,
|
|
96
96
|
perfDebug,
|
|
97
97
|
perfDiagnosticsAnimations,
|
|
98
98
|
perfDiagnosticsThirdParty,
|
|
@@ -117,7 +117,8 @@ class RenderBlockingResources extends Audit {
|
|
|
117
117
|
guidanceLevel: 2,
|
|
118
118
|
// TODO: look into adding an `optionalArtifacts` property that captures the non-required nature
|
|
119
119
|
// of CSSUsage
|
|
120
|
-
requiredArtifacts:
|
|
120
|
+
requiredArtifacts:
|
|
121
|
+
['URL', 'traces', 'devtoolsLogs', 'Stylesheets', 'CSSUsage', 'GatherContext', 'Stacks'],
|
|
121
122
|
};
|
|
122
123
|
}
|
|
123
124
|
|
|
@@ -263,6 +264,7 @@ class RenderBlockingResources extends Audit {
|
|
|
263
264
|
const wastedBytesByUrl = new Map();
|
|
264
265
|
try {
|
|
265
266
|
const unusedCssItems = await UnusedCSS.request({
|
|
267
|
+
Stylesheets: artifacts.Stylesheets,
|
|
266
268
|
CSSUsage: artifacts.CSSUsage,
|
|
267
269
|
devtoolsLog: artifacts.devtoolsLogs[Audit.DEFAULT_PASS],
|
|
268
270
|
}, context);
|
|
@@ -37,7 +37,7 @@ class UnminifiedCSS extends ByteEfficiencyAudit {
|
|
|
37
37
|
description: str_(UIStrings.description),
|
|
38
38
|
scoreDisplayMode: ByteEfficiencyAudit.SCORING_MODES.METRIC_SAVINGS,
|
|
39
39
|
guidanceLevel: 3,
|
|
40
|
-
requiredArtifacts: ['
|
|
40
|
+
requiredArtifacts: ['Stylesheets', 'devtoolsLogs', 'traces', 'URL', 'GatherContext'],
|
|
41
41
|
};
|
|
42
42
|
}
|
|
43
43
|
|
|
@@ -85,7 +85,7 @@ class UnminifiedCSS extends ByteEfficiencyAudit {
|
|
|
85
85
|
*/
|
|
86
86
|
static audit_(artifacts, networkRecords) {
|
|
87
87
|
const items = [];
|
|
88
|
-
for (const stylesheet of artifacts.
|
|
88
|
+
for (const stylesheet of artifacts.Stylesheets) {
|
|
89
89
|
const networkRecord = networkRecords
|
|
90
90
|
.find(record => record.url === stylesheet.header.sourceURL);
|
|
91
91
|
if (!stylesheet.content) continue;
|
|
@@ -34,7 +34,8 @@ class UnusedCSSRules extends ByteEfficiencyAudit {
|
|
|
34
34
|
description: str_(UIStrings.description),
|
|
35
35
|
scoreDisplayMode: ByteEfficiencyAudit.SCORING_MODES.METRIC_SAVINGS,
|
|
36
36
|
guidanceLevel: 1,
|
|
37
|
-
requiredArtifacts:
|
|
37
|
+
requiredArtifacts:
|
|
38
|
+
['Stylesheets', 'CSSUsage', 'URL', 'devtoolsLogs', 'traces', 'GatherContext'],
|
|
38
39
|
};
|
|
39
40
|
}
|
|
40
41
|
|
|
@@ -46,6 +47,7 @@ class UnusedCSSRules extends ByteEfficiencyAudit {
|
|
|
46
47
|
*/
|
|
47
48
|
static async audit_(artifacts, _, context) {
|
|
48
49
|
const unusedCssItems = await UnusedCSS.request({
|
|
50
|
+
Stylesheets: artifacts.Stylesheets,
|
|
49
51
|
CSSUsage: artifacts.CSSUsage,
|
|
50
52
|
devtoolsLog: artifacts.devtoolsLogs[ByteEfficiencyAudit.DEFAULT_PASS],
|
|
51
53
|
}, context);
|
|
@@ -50,7 +50,7 @@ class FontDisplay extends Audit {
|
|
|
50
50
|
description: str_(UIStrings.description),
|
|
51
51
|
supportedModes: ['navigation'],
|
|
52
52
|
guidanceLevel: 3,
|
|
53
|
-
requiredArtifacts: ['devtoolsLogs', '
|
|
53
|
+
requiredArtifacts: ['devtoolsLogs', 'Stylesheets', 'URL'],
|
|
54
54
|
scoreDisplayMode: Audit.SCORING_MODES.METRIC_SAVINGS,
|
|
55
55
|
};
|
|
56
56
|
}
|
|
@@ -67,7 +67,7 @@ class FontDisplay extends Audit {
|
|
|
67
67
|
const failingURLs = new Set();
|
|
68
68
|
|
|
69
69
|
// Go through all the stylesheets to find all @font-face declarations
|
|
70
|
-
for (const stylesheet of artifacts.
|
|
70
|
+
for (const stylesheet of artifacts.Stylesheets) {
|
|
71
71
|
// Eliminate newlines so we can more easily scan through with a regex
|
|
72
72
|
const newlinesStripped = stylesheet.content.replace(/(\r|\n)+/g, ' ');
|
|
73
73
|
// Find the @font-faces
|
|
@@ -1,4 +1,6 @@
|
|
|
1
1
|
export default ResourceSummary;
|
|
2
|
+
export type ResourceType = import('../computed/resource-summary.js').ResourceType;
|
|
3
|
+
/** @typedef {import('../computed/resource-summary.js').ResourceType} ResourceType */
|
|
2
4
|
declare class ResourceSummary extends Audit {
|
|
3
5
|
/**
|
|
4
6
|
* @param {LH.Artifacts} artifacts
|
|
@@ -10,6 +10,8 @@ import * as i18n from '../lib/i18n/i18n.js';
|
|
|
10
10
|
|
|
11
11
|
const str_ = i18n.createIcuMessageFn(import.meta.url);
|
|
12
12
|
|
|
13
|
+
/** @typedef {import('../computed/resource-summary.js').ResourceType} ResourceType */
|
|
14
|
+
|
|
13
15
|
class ResourceSummary extends Audit {
|
|
14
16
|
/**
|
|
15
17
|
* @return {LH.Audit.Meta}
|
|
@@ -32,7 +34,7 @@ class ResourceSummary extends Audit {
|
|
|
32
34
|
static async audit(artifacts, context) {
|
|
33
35
|
const devtoolsLog = artifacts.devtoolsLogs[Audit.DEFAULT_PASS];
|
|
34
36
|
const summary = await ComputedResourceSummary
|
|
35
|
-
.request({devtoolsLog, URL: artifacts.URL
|
|
37
|
+
.request({devtoolsLog, URL: artifacts.URL}, context);
|
|
36
38
|
|
|
37
39
|
/** @type {LH.Audit.Details.Table['headings']} */
|
|
38
40
|
const headings = [
|
|
@@ -41,8 +43,7 @@ class ResourceSummary extends Audit {
|
|
|
41
43
|
{key: 'transferSize', valueType: 'bytes', label: str_(i18n.UIStrings.columnTransferSize)},
|
|
42
44
|
];
|
|
43
45
|
|
|
44
|
-
|
|
45
|
-
/** @type {Record<LH.Budget.ResourceType, LH.IcuMessage>} */
|
|
46
|
+
/** @type {Record<ResourceType, LH.IcuMessage>} */
|
|
46
47
|
const strMappings = {
|
|
47
48
|
'total': str_(i18n.UIStrings.totalResourceType),
|
|
48
49
|
'document': str_(i18n.UIStrings.documentResourceType),
|
|
@@ -55,7 +56,7 @@ class ResourceSummary extends Audit {
|
|
|
55
56
|
'third-party': str_(i18n.UIStrings.thirdPartyResourceType),
|
|
56
57
|
};
|
|
57
58
|
|
|
58
|
-
const types = /** @type {Array<
|
|
59
|
+
const types = /** @type {Array<ResourceType>} */ (Object.keys(summary));
|
|
59
60
|
const rows = types.map(type => {
|
|
60
61
|
return {
|
|
61
62
|
// ResourceType is included as an "id" for ease of use.
|
|
@@ -84,6 +84,18 @@ const BLOCKLIST = new Set([
|
|
|
84
84
|
'மேலும் தரவுகளுக்கு',
|
|
85
85
|
'தயவுசெய்து இங்கே அழுத்தவும்',
|
|
86
86
|
'இங்கே கிளிக் செய்யவும்',
|
|
87
|
+
// Persian
|
|
88
|
+
'اطلاعات بیشتر',
|
|
89
|
+
'اطلاعات',
|
|
90
|
+
'این',
|
|
91
|
+
'اینجا بزنید',
|
|
92
|
+
'اینجا کلیک کنید',
|
|
93
|
+
'اینجا',
|
|
94
|
+
'برو',
|
|
95
|
+
'بیشتر بخوانید',
|
|
96
|
+
'بیشتر بدانید',
|
|
97
|
+
'بیشتر',
|
|
98
|
+
'شروع',
|
|
87
99
|
]);
|
|
88
100
|
|
|
89
101
|
const UIStrings = {
|
|
@@ -9,7 +9,6 @@ import {PageDependencyGraph as LanternPageDependencyGraph} from '../lib/lantern/
|
|
|
9
9
|
import {NetworkRequest} from '../lib/network-request.js';
|
|
10
10
|
import {ProcessedTrace} from './processed-trace.js';
|
|
11
11
|
import {NetworkRecords} from './network-records.js';
|
|
12
|
-
import {DocumentUrls} from './document-urls.js';
|
|
13
12
|
|
|
14
13
|
/** @typedef {import('../lib/lantern/base-node.js').Node<LH.Artifacts.NetworkRequest>} Node */
|
|
15
14
|
|
|
@@ -20,16 +19,12 @@ class PageDependencyGraph {
|
|
|
20
19
|
* @return {Promise<Node>}
|
|
21
20
|
*/
|
|
22
21
|
static async compute_(data, context) {
|
|
23
|
-
const {trace, devtoolsLog} = data;
|
|
22
|
+
const {trace, devtoolsLog, URL} = data;
|
|
24
23
|
const [processedTrace, networkRecords] = await Promise.all([
|
|
25
24
|
ProcessedTrace.request(trace, context),
|
|
26
25
|
NetworkRecords.request(devtoolsLog, context),
|
|
27
26
|
]);
|
|
28
27
|
|
|
29
|
-
// COMPAT: Backport for pre-10.0 clients that don't pass the URL artifact here (e.g. pubads).
|
|
30
|
-
// Calculates the URL artifact from the processed trace and DT log.
|
|
31
|
-
const URL = data.URL || await DocumentUrls.request(data, context);
|
|
32
|
-
|
|
33
28
|
const mainThreadEvents = processedTrace.mainThreadEvents;
|
|
34
29
|
const lanternRequests = networkRecords.map(NetworkRequest.asLanternNetworkRequest);
|
|
35
30
|
return LanternPageDependencyGraph.createGraph(mainThreadEvents, lanternRequests, URL);
|
|
@@ -4,42 +4,40 @@ export type ResourceEntry = {
|
|
|
4
4
|
resourceSize: number;
|
|
5
5
|
transferSize: number;
|
|
6
6
|
};
|
|
7
|
+
export type ResourceType = 'stylesheet' | 'image' | 'media' | 'font' | 'script' | 'document' | 'other' | 'third-party' | 'total';
|
|
7
8
|
declare const ResourceSummaryComputed: typeof ResourceSummary & {
|
|
8
9
|
request: (dependencies: {
|
|
9
10
|
URL: LH.Artifacts['URL'];
|
|
10
11
|
devtoolsLog: import("../index.js").DevtoolsLog;
|
|
11
|
-
budgets: LH.Util.ImmutableObject<LH.Budget[] | null>;
|
|
12
12
|
}, context: import("../../types/utility-types.js").default.ImmutableObject<{
|
|
13
13
|
computedCache: Map<string, import("../lib/arbitrary-equality-map.js").ArbitraryEqualityMap>;
|
|
14
|
-
}>) => Promise<Record<
|
|
14
|
+
}>) => Promise<Record<ResourceType, ResourceEntry>>;
|
|
15
15
|
};
|
|
16
16
|
/** @typedef {{count: number, resourceSize: number, transferSize: number}} ResourceEntry */
|
|
17
|
+
/** @typedef {'stylesheet'|'image'|'media'|'font'|'script'|'document'|'other'|'third-party'|'total'} ResourceType */
|
|
17
18
|
declare class ResourceSummary {
|
|
18
19
|
/**
|
|
19
20
|
* @param {LH.Artifacts.NetworkRequest} record
|
|
20
|
-
* @return {
|
|
21
|
+
* @return {ResourceType}
|
|
21
22
|
*/
|
|
22
|
-
static determineResourceType(record: LH.Artifacts.NetworkRequest):
|
|
23
|
+
static determineResourceType(record: LH.Artifacts.NetworkRequest): ResourceType;
|
|
23
24
|
/**
|
|
24
25
|
* @param {Array<LH.Artifacts.NetworkRequest>} networkRecords
|
|
25
26
|
* @param {LH.Artifacts.URL} URLArtifact
|
|
26
|
-
* @param {LH.Util.ImmutableObject<LH.Budget[]|null>} budgets
|
|
27
27
|
* @param {LH.Artifacts.EntityClassification} classifiedEntities
|
|
28
|
-
* @return {Record<
|
|
28
|
+
* @return {Record<ResourceType, ResourceEntry>}
|
|
29
29
|
*/
|
|
30
|
-
static summarize(networkRecords: Array<LH.Artifacts.NetworkRequest>, URLArtifact: LH.Artifacts.URL,
|
|
30
|
+
static summarize(networkRecords: Array<LH.Artifacts.NetworkRequest>, URLArtifact: LH.Artifacts.URL, classifiedEntities: LH.Artifacts.EntityClassification): Record<ResourceType, ResourceEntry>;
|
|
31
31
|
/**
|
|
32
|
-
* @param {{URL: LH.Artifacts['URL'], devtoolsLog: LH.DevtoolsLog
|
|
32
|
+
* @param {{URL: LH.Artifacts['URL'], devtoolsLog: LH.DevtoolsLog}} data
|
|
33
33
|
* @param {LH.Artifacts.ComputedContext} context
|
|
34
|
-
* @return {Promise<Record<
|
|
34
|
+
* @return {Promise<Record<ResourceType,ResourceEntry>>}
|
|
35
35
|
*/
|
|
36
36
|
static compute_(data: {
|
|
37
37
|
URL: LH.Artifacts['URL'];
|
|
38
38
|
devtoolsLog: import("../index.js").DevtoolsLog;
|
|
39
|
-
|
|
40
|
-
}, context: LH.Artifacts.ComputedContext): Promise<Record<LH.Budget.ResourceType, ResourceEntry>>;
|
|
39
|
+
}, context: LH.Artifacts.ComputedContext): Promise<Record<ResourceType, ResourceEntry>>;
|
|
41
40
|
}
|
|
42
|
-
import { Budget } from '../config/budget.js';
|
|
43
41
|
import { NetworkRequest } from '../lib/network-request.js';
|
|
44
42
|
import { EntityClassification } from './entity-classification.js';
|
|
45
43
|
//# sourceMappingURL=resource-summary.d.ts.map
|
|
@@ -8,19 +8,19 @@ import {EntityClassification} from './entity-classification.js';
|
|
|
8
8
|
import {makeComputedArtifact} from './computed-artifact.js';
|
|
9
9
|
import {NetworkRecords} from './network-records.js';
|
|
10
10
|
import {NetworkRequest} from '../lib/network-request.js';
|
|
11
|
-
import {Budget} from '../config/budget.js';
|
|
12
11
|
import UrlUtils from '../lib/url-utils.js';
|
|
13
12
|
|
|
14
13
|
/** @typedef {{count: number, resourceSize: number, transferSize: number}} ResourceEntry */
|
|
14
|
+
/** @typedef {'stylesheet'|'image'|'media'|'font'|'script'|'document'|'other'|'third-party'|'total'} ResourceType */
|
|
15
15
|
|
|
16
16
|
class ResourceSummary {
|
|
17
17
|
/**
|
|
18
18
|
* @param {LH.Artifacts.NetworkRequest} record
|
|
19
|
-
* @return {
|
|
19
|
+
* @return {ResourceType}
|
|
20
20
|
*/
|
|
21
21
|
static determineResourceType(record) {
|
|
22
22
|
if (!record.resourceType) return 'other';
|
|
23
|
-
/** @type {Partial<Record<LH.Crdp.Network.ResourceType,
|
|
23
|
+
/** @type {Partial<Record<LH.Crdp.Network.ResourceType, ResourceType>>} */
|
|
24
24
|
const requestToResourceType = {
|
|
25
25
|
'Stylesheet': 'stylesheet',
|
|
26
26
|
'Image': 'image',
|
|
@@ -35,12 +35,11 @@ class ResourceSummary {
|
|
|
35
35
|
/**
|
|
36
36
|
* @param {Array<LH.Artifacts.NetworkRequest>} networkRecords
|
|
37
37
|
* @param {LH.Artifacts.URL} URLArtifact
|
|
38
|
-
* @param {LH.Util.ImmutableObject<LH.Budget[]|null>} budgets
|
|
39
38
|
* @param {LH.Artifacts.EntityClassification} classifiedEntities
|
|
40
|
-
* @return {Record<
|
|
39
|
+
* @return {Record<ResourceType, ResourceEntry>}
|
|
41
40
|
*/
|
|
42
|
-
static summarize(networkRecords, URLArtifact,
|
|
43
|
-
/** @type {Record<
|
|
41
|
+
static summarize(networkRecords, URLArtifact, classifiedEntities) {
|
|
42
|
+
/** @type {Record<ResourceType, ResourceEntry>} */
|
|
44
43
|
const resourceSummary = {
|
|
45
44
|
'stylesheet': {count: 0, resourceSize: 0, transferSize: 0},
|
|
46
45
|
'image': {count: 0, resourceSize: 0, transferSize: 0},
|
|
@@ -52,15 +51,9 @@ class ResourceSummary {
|
|
|
52
51
|
'total': {count: 0, resourceSize: 0, transferSize: 0},
|
|
53
52
|
'third-party': {count: 0, resourceSize: 0, transferSize: 0},
|
|
54
53
|
};
|
|
55
|
-
const budget = Budget.getMatchingBudget(budgets, URLArtifact.mainDocumentUrl);
|
|
56
54
|
/** @type {ReadonlyArray<string>} */
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
firstPartyHosts = budget.options.firstPartyHostnames;
|
|
60
|
-
} else {
|
|
61
|
-
firstPartyHosts = classifiedEntities.firstParty?.domains.map(domain => `*.${domain}`) ||
|
|
62
|
-
[`*.${UrlUtils.getRootDomain(URLArtifact.finalDisplayedUrl)}`];
|
|
63
|
-
}
|
|
55
|
+
const firstPartyHosts = classifiedEntities.firstParty?.domains.map(domain => `*.${domain}`) ||
|
|
56
|
+
[`*.${UrlUtils.getRootDomain(URLArtifact.finalDisplayedUrl)}`];
|
|
64
57
|
|
|
65
58
|
networkRecords.filter(record => {
|
|
66
59
|
// Ignore favicon.co
|
|
@@ -101,18 +94,18 @@ class ResourceSummary {
|
|
|
101
94
|
}
|
|
102
95
|
|
|
103
96
|
/**
|
|
104
|
-
* @param {{URL: LH.Artifacts['URL'], devtoolsLog: LH.DevtoolsLog
|
|
97
|
+
* @param {{URL: LH.Artifacts['URL'], devtoolsLog: LH.DevtoolsLog}} data
|
|
105
98
|
* @param {LH.Artifacts.ComputedContext} context
|
|
106
|
-
* @return {Promise<Record<
|
|
99
|
+
* @return {Promise<Record<ResourceType,ResourceEntry>>}
|
|
107
100
|
*/
|
|
108
101
|
static async compute_(data, context) {
|
|
109
102
|
const networkRecords = await NetworkRecords.request(data.devtoolsLog, context);
|
|
110
103
|
const classifiedEntities = await EntityClassification.request(
|
|
111
104
|
{URL: data.URL, devtoolsLog: data.devtoolsLog}, context);
|
|
112
|
-
return ResourceSummary.summarize(networkRecords, data.URL,
|
|
105
|
+
return ResourceSummary.summarize(networkRecords, data.URL, classifiedEntities);
|
|
113
106
|
}
|
|
114
107
|
}
|
|
115
108
|
|
|
116
109
|
const ResourceSummaryComputed =
|
|
117
|
-
makeComputedArtifact(ResourceSummary, ['URL', 'devtoolsLog'
|
|
110
|
+
makeComputedArtifact(ResourceSummary, ['URL', 'devtoolsLog']);
|
|
118
111
|
export {ResourceSummaryComputed as ResourceSummary};
|
|
@@ -5,6 +5,7 @@ export type StyleSheetInfo = LH.Artifacts.CSSStyleSheetInfo & {
|
|
|
5
5
|
};
|
|
6
6
|
declare const UnusedCSSComputed: typeof UnusedCSS & {
|
|
7
7
|
request: (dependencies: {
|
|
8
|
+
Stylesheets: LH.Artifacts['Stylesheets'];
|
|
8
9
|
CSSUsage: LH.Artifacts['CSSUsage'];
|
|
9
10
|
devtoolsLog: import("../index.js").DevtoolsLog;
|
|
10
11
|
}, context: import("../../types/utility-types.js").default.ImmutableObject<{
|
|
@@ -50,11 +51,12 @@ declare class UnusedCSS {
|
|
|
50
51
|
*/
|
|
51
52
|
static mapSheetToResult(stylesheetInfo: StyleSheetInfo): LH.Audit.ByteEfficiencyItem;
|
|
52
53
|
/**
|
|
53
|
-
* @param {{CSSUsage: LH.Artifacts['CSSUsage'], devtoolsLog: LH.DevtoolsLog}} data
|
|
54
|
+
* @param {{Stylesheets: LH.Artifacts['Stylesheets'], CSSUsage: LH.Artifacts['CSSUsage'], devtoolsLog: LH.DevtoolsLog}} data
|
|
54
55
|
* @param {LH.Artifacts.ComputedContext} context
|
|
55
56
|
* @return {Promise<LH.Audit.ByteEfficiencyItem[]>}
|
|
56
57
|
*/
|
|
57
58
|
static compute_(data: {
|
|
59
|
+
Stylesheets: LH.Artifacts['Stylesheets'];
|
|
58
60
|
CSSUsage: LH.Artifacts['CSSUsage'];
|
|
59
61
|
devtoolsLog: import("../index.js").DevtoolsLog;
|
|
60
62
|
}, context: LH.Artifacts.ComputedContext): Promise<LH.Audit.ByteEfficiencyItem[]>;
|
|
@@ -134,15 +134,15 @@ class UnusedCSS {
|
|
|
134
134
|
}
|
|
135
135
|
|
|
136
136
|
/**
|
|
137
|
-
* @param {{CSSUsage: LH.Artifacts['CSSUsage'], devtoolsLog: LH.DevtoolsLog}} data
|
|
137
|
+
* @param {{Stylesheets: LH.Artifacts['Stylesheets'], CSSUsage: LH.Artifacts['CSSUsage'], devtoolsLog: LH.DevtoolsLog}} data
|
|
138
138
|
* @param {LH.Artifacts.ComputedContext} context
|
|
139
139
|
* @return {Promise<LH.Audit.ByteEfficiencyItem[]>}
|
|
140
140
|
*/
|
|
141
141
|
static async compute_(data, context) {
|
|
142
|
-
const {CSSUsage, devtoolsLog} = data;
|
|
142
|
+
const {CSSUsage, Stylesheets, devtoolsLog} = data;
|
|
143
143
|
const networkRecords = await NetworkRecords.request(devtoolsLog, context);
|
|
144
|
-
const indexedSheets = UnusedCSS.indexStylesheetsById(
|
|
145
|
-
UnusedCSS.indexUsedRules(CSSUsage
|
|
144
|
+
const indexedSheets = UnusedCSS.indexStylesheetsById(Stylesheets, networkRecords);
|
|
145
|
+
UnusedCSS.indexUsedRules(CSSUsage, indexedSheets);
|
|
146
146
|
|
|
147
147
|
const items = Object.keys(indexedSheets)
|
|
148
148
|
.map(sheetId => UnusedCSS.mapSheetToResult(indexedSheets[sheetId]));
|
|
@@ -150,5 +150,6 @@ class UnusedCSS {
|
|
|
150
150
|
}
|
|
151
151
|
}
|
|
152
152
|
|
|
153
|
-
const UnusedCSSComputed = makeComputedArtifact(UnusedCSS,
|
|
153
|
+
const UnusedCSSComputed = makeComputedArtifact(UnusedCSS,
|
|
154
|
+
['Stylesheets', 'CSSUsage', 'devtoolsLog']);
|
|
154
155
|
export {UnusedCSSComputed as UnusedCSS};
|
|
@@ -11,7 +11,6 @@ import url from 'url';
|
|
|
11
11
|
import isDeepEqual from 'lodash/isEqual.js';
|
|
12
12
|
|
|
13
13
|
import * as constants from './constants.js';
|
|
14
|
-
import {Budget} from './budget.js';
|
|
15
14
|
import ConfigPlugin from './config-plugin.js';
|
|
16
15
|
import {Runner} from '../runner.js';
|
|
17
16
|
import * as i18n from '../lib/i18n/i18n.js';
|
|
@@ -347,9 +346,6 @@ function resolveSettings(settingsJson = {}, overrides = undefined) {
|
|
|
347
346
|
true
|
|
348
347
|
);
|
|
349
348
|
|
|
350
|
-
if (settingsWithFlags.budgets) {
|
|
351
|
-
settingsWithFlags.budgets = Budget.initializeBudget(settingsWithFlags.budgets);
|
|
352
|
-
}
|
|
353
349
|
// Locale is special and comes only from flags/settings/lookupLocale.
|
|
354
350
|
settingsWithFlags.locale = locale;
|
|
355
351
|
|
package/core/config/constants.js
CHANGED
|
@@ -118,7 +118,6 @@ const defaultSettings = {
|
|
|
118
118
|
|
|
119
119
|
// the following settings have no defaults but we still want ensure that `key in settings`
|
|
120
120
|
// in config will work in a typechecked way
|
|
121
|
-
budgets: null,
|
|
122
121
|
locale: 'en-US', // actual default determined by Config using lib/i18n
|
|
123
122
|
blockedUrlPatterns: null,
|
|
124
123
|
additionalTraceCategories: null,
|
|
@@ -13,10 +13,6 @@ import * as i18n from '../lib/i18n/i18n.js';
|
|
|
13
13
|
const UIStrings = {
|
|
14
14
|
/** Title of the Performance category of audits. Equivalent to 'Web performance', this term is inclusive of all web page speed and loading optimization topics. Also used as a label of a score gauge; try to limit to 20 characters. */
|
|
15
15
|
performanceCategoryTitle: 'Performance',
|
|
16
|
-
/** Title of the Budgets section of the Performance Category. 'Budgets' refers to a budget (like a financial budget), but applied to the amount of resources on a page, rather than money. */
|
|
17
|
-
budgetsGroupTitle: 'Budgets',
|
|
18
|
-
/** Description of the Budgets section of the Performance category. Within this section the budget results are displayed. */
|
|
19
|
-
budgetsGroupDescription: 'Performance budgets set standards for the performance of your site.',
|
|
20
16
|
/** Title of the speed metrics section of the Performance category. Within this section are various speed metrics which quantify the pageload performance into values presented in seconds and milliseconds. */
|
|
21
17
|
metricGroupTitle: 'Metrics',
|
|
22
18
|
/** Title of an opportunity sub-section of the Performance category. Within this section are audits with imperative titles that suggest actions the user can take to improve the time of the first initial render of the webpage. */
|
|
@@ -136,6 +132,7 @@ const defaultConfig = {
|
|
|
136
132
|
{id: 'Scripts', gatherer: 'scripts'},
|
|
137
133
|
{id: 'SourceMaps', gatherer: 'source-maps'},
|
|
138
134
|
{id: 'Stacks', gatherer: 'stacks'},
|
|
135
|
+
{id: 'Stylesheets', gatherer: 'stylesheets'},
|
|
139
136
|
{id: 'TraceElements', gatherer: 'trace-elements'},
|
|
140
137
|
{id: 'ViewportDimensions', gatherer: 'viewport-dimensions'},
|
|
141
138
|
|
|
@@ -183,8 +180,6 @@ const defaultConfig = {
|
|
|
183
180
|
'network-server-latency',
|
|
184
181
|
'main-thread-tasks',
|
|
185
182
|
'metrics',
|
|
186
|
-
'performance-budget',
|
|
187
|
-
'timing-budget',
|
|
188
183
|
'resource-summary',
|
|
189
184
|
'third-party-summary',
|
|
190
185
|
'third-party-facades',
|
|
@@ -312,10 +307,6 @@ const defaultConfig = {
|
|
|
312
307
|
'metrics': {
|
|
313
308
|
title: str_(UIStrings.metricGroupTitle),
|
|
314
309
|
},
|
|
315
|
-
'budgets': {
|
|
316
|
-
title: str_(UIStrings.budgetsGroupTitle),
|
|
317
|
-
description: str_(UIStrings.budgetsGroupDescription),
|
|
318
|
-
},
|
|
319
310
|
'diagnostics': {
|
|
320
311
|
title: str_(UIStrings.diagnosticsGroupTitle),
|
|
321
312
|
description: str_(UIStrings.diagnosticsGroupDescription),
|
|
@@ -437,10 +428,6 @@ const defaultConfig = {
|
|
|
437
428
|
{id: 'work-during-interaction', weight: 0, group: 'diagnostics'},
|
|
438
429
|
{id: 'bf-cache', weight: 0, group: 'diagnostics'},
|
|
439
430
|
|
|
440
|
-
// Budget audits.
|
|
441
|
-
{id: 'performance-budget', weight: 0, group: 'budgets'},
|
|
442
|
-
{id: 'timing-budget', weight: 0, group: 'budgets'},
|
|
443
|
-
|
|
444
431
|
// Audits past this point contain useful data but are not displayed with other audits.
|
|
445
432
|
{id: 'network-requests', weight: 0, group: 'hidden'},
|
|
446
433
|
{id: 'network-rtt', weight: 0, group: 'hidden'},
|
|
@@ -122,7 +122,10 @@ async function gotoURL(driver, requestor, options) {
|
|
|
122
122
|
throw new Error('Cannot wait for FCP without waiting for page load');
|
|
123
123
|
}
|
|
124
124
|
|
|
125
|
-
const waitConditions = await Promise.
|
|
125
|
+
const waitConditions = await Promise.race([
|
|
126
|
+
driver.fatalRejection.promise,
|
|
127
|
+
Promise.all(waitConditionPromises),
|
|
128
|
+
]);
|
|
126
129
|
const timedOut = waitConditions.some(condition => condition.timedOut);
|
|
127
130
|
const navigationUrls = await networkMonitor.getNavigationUrls();
|
|
128
131
|
|
|
@@ -45,7 +45,7 @@ async function enableAsyncStacks(session) {
|
|
|
45
45
|
await enable();
|
|
46
46
|
|
|
47
47
|
return async () => {
|
|
48
|
-
await session.
|
|
48
|
+
await session.sendCommandAndIgnore('Debugger.disable');
|
|
49
49
|
session.off('Debugger.paused', onDebuggerPaused);
|
|
50
50
|
session.off('Page.frameNavigated', onFrameNavigated);
|
|
51
51
|
};
|
|
@@ -266,8 +266,9 @@ class TargetManager extends ProtocolEventEmitter {
|
|
|
266
266
|
cdpSession.off('sessionattached', this._onSessionAttached);
|
|
267
267
|
}
|
|
268
268
|
|
|
269
|
-
|
|
270
|
-
await this._rootCdpSession.send('
|
|
269
|
+
// Ignore failures on these in case the tab has crashed.
|
|
270
|
+
await this._rootCdpSession.send('Page.disable').catch(_ => {});
|
|
271
|
+
await this._rootCdpSession.send('Runtime.disable').catch(_ => {});
|
|
271
272
|
|
|
272
273
|
this._enabled = false;
|
|
273
274
|
this._targetIdToTargets = new Map();
|
package/core/gather/driver.d.ts
CHANGED
|
@@ -14,6 +14,10 @@ export class Driver implements LH.Gatherer.Driver {
|
|
|
14
14
|
/** @type {Fetcher|undefined} */
|
|
15
15
|
_fetcher: Fetcher | undefined;
|
|
16
16
|
defaultSession: import("../../types/gatherer.js").default.ProtocolSession;
|
|
17
|
+
fatalRejection: {
|
|
18
|
+
promise: Promise<never>;
|
|
19
|
+
rej: (_: Error) => void;
|
|
20
|
+
};
|
|
17
21
|
/** @return {LH.Gatherer.Driver['executionContext']} */
|
|
18
22
|
get executionContext(): ExecutionContext;
|
|
19
23
|
get fetcher(): any;
|
|
@@ -23,6 +27,14 @@ export class Driver implements LH.Gatherer.Driver {
|
|
|
23
27
|
url(): Promise<string>;
|
|
24
28
|
/** @return {Promise<void>} */
|
|
25
29
|
connect(): Promise<void>;
|
|
30
|
+
/**
|
|
31
|
+
* If the target crashes, we can't continue gathering.
|
|
32
|
+
*
|
|
33
|
+
* FWIW, if the target unexpectedly detaches (eg the user closed the tab), pptr will
|
|
34
|
+
* catch that and reject into our this._cdpSession.send, which we'll alrady handle appropriately
|
|
35
|
+
* @return {void}
|
|
36
|
+
*/
|
|
37
|
+
listenForCrashes(): void;
|
|
26
38
|
/** @return {Promise<void>} */
|
|
27
39
|
disconnect(): Promise<void>;
|
|
28
40
|
}
|
package/core/gather/driver.js
CHANGED
|
@@ -8,6 +8,7 @@ import log from 'lighthouse-logger';
|
|
|
8
8
|
|
|
9
9
|
import {ExecutionContext} from './driver/execution-context.js';
|
|
10
10
|
import {TargetManager} from './driver/target-manager.js';
|
|
11
|
+
import {LighthouseError} from '../lib/lh-error.js';
|
|
11
12
|
import {Fetcher} from './fetcher.js';
|
|
12
13
|
import {NetworkMonitor} from './driver/network-monitor.js';
|
|
13
14
|
|
|
@@ -47,6 +48,12 @@ class Driver {
|
|
|
47
48
|
this._fetcher = undefined;
|
|
48
49
|
|
|
49
50
|
this.defaultSession = throwingSession;
|
|
51
|
+
|
|
52
|
+
// Poor man's Promise.withResolvers()
|
|
53
|
+
/** @param {Error} _ */
|
|
54
|
+
let rej = _ => {};
|
|
55
|
+
const promise = /** @type {Promise<never>} */ (new Promise((_, theRej) => rej = theRej));
|
|
56
|
+
this.fatalRejection = {promise, rej};
|
|
50
57
|
}
|
|
51
58
|
|
|
52
59
|
/** @return {LH.Gatherer.Driver['executionContext']} */
|
|
@@ -86,11 +93,30 @@ class Driver {
|
|
|
86
93
|
this._networkMonitor = new NetworkMonitor(this._targetManager);
|
|
87
94
|
await this._networkMonitor.enable();
|
|
88
95
|
this.defaultSession = this._targetManager.rootSession();
|
|
96
|
+
this.listenForCrashes();
|
|
89
97
|
this._executionContext = new ExecutionContext(this.defaultSession);
|
|
90
98
|
this._fetcher = new Fetcher(this.defaultSession);
|
|
91
99
|
log.timeEnd(status);
|
|
92
100
|
}
|
|
93
101
|
|
|
102
|
+
/**
|
|
103
|
+
* If the target crashes, we can't continue gathering.
|
|
104
|
+
*
|
|
105
|
+
* FWIW, if the target unexpectedly detaches (eg the user closed the tab), pptr will
|
|
106
|
+
* catch that and reject into our this._cdpSession.send, which we'll alrady handle appropriately
|
|
107
|
+
* @return {void}
|
|
108
|
+
*/
|
|
109
|
+
listenForCrashes() {
|
|
110
|
+
this.defaultSession.on('Inspector.targetCrashed', async _ => {
|
|
111
|
+
log.error('Driver', 'Inspector.targetCrashed');
|
|
112
|
+
// Manually detach so no more CDP traffic is attempted.
|
|
113
|
+
// Don't await, else our rejection will be a 'Target closed' protocol error on cross-talk CDP calls.
|
|
114
|
+
void this.defaultSession.dispose();
|
|
115
|
+
this.fatalRejection.rej(new LighthouseError(LighthouseError.errors.TARGET_CRASHED));
|
|
116
|
+
});
|
|
117
|
+
}
|
|
118
|
+
|
|
119
|
+
|
|
94
120
|
/** @return {Promise<void>} */
|
|
95
121
|
async disconnect() {
|
|
96
122
|
if (this.defaultSession === throwingSession) return;
|