forked from GoogleChrome/lighthouse
-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathjs-usage.js
111 lines (98 loc) · 4.06 KB
/
js-usage.js
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
/**
* @license Copyright 2017 The Lighthouse Authors. All Rights Reserved.
* Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0
* Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License.
*/
'use strict';
const FRGatherer = require('../../fraggle-rock/gather/base-gatherer.js');
/**
* @fileoverview Tracks unused JavaScript
*/
class JsUsage extends FRGatherer {
/** @type {LH.Gatherer.GathererMeta} */
meta = {
// TODO(FR-COMPAT): special snapshot case for scriptId -> URL mappings.
supportedModes: ['timespan', 'navigation'],
}
constructor() {
super();
/** @type {LH.Crdp.Debugger.ScriptParsedEvent[]} */
this._scriptParsedEvents = [];
/** @type {LH.Crdp.Profiler.ScriptCoverage[]} */
this._scriptUsages = [];
this.onScriptParsed = this.onScriptParsed.bind(this);
}
/**
* @param {LH.Crdp.Debugger.ScriptParsedEvent} event
*/
onScriptParsed(event) {
if (event.embedderName) {
this._scriptParsedEvents.push(event);
}
}
/**
* @param {LH.Gatherer.FRTransitionalContext} context
*/
async startInstrumentation(context) {
const session = context.driver.defaultSession;
await session.sendCommand('Profiler.enable');
await session.sendCommand('Profiler.startPreciseCoverage', {detailed: false});
}
/**
* @param {LH.Gatherer.FRTransitionalContext} context
*/
async stopInstrumentation(context) {
const session = context.driver.defaultSession;
const coverageResponse = await session.sendCommand('Profiler.takePreciseCoverage');
this._scriptUsages = coverageResponse.result;
await session.sendCommand('Profiler.stopPreciseCoverage');
await session.sendCommand('Profiler.disable');
}
/**
* @param {LH.Gatherer.FRTransitionalContext} context
*/
async startSensitiveInstrumentation(context) {
const session = context.driver.defaultSession;
await session.sendCommand('Debugger.enable');
await session.on('Debugger.scriptParsed', this.onScriptParsed);
}
/**
* @param {LH.Gatherer.FRTransitionalContext} context
*/
async stopSensitiveInstrumentation(context) {
const session = context.driver.defaultSession;
await session.off('Debugger.scriptParsed', this.onScriptParsed);
await session.sendCommand('Debugger.disable');
}
/**
* @return {Promise<LH.Artifacts['JsUsage']>}
*/
async getArtifact() {
/** @type {Record<string, Array<LH.Crdp.Profiler.ScriptCoverage>>} */
const usageByUrl = {};
for (const scriptUsage of this._scriptUsages) {
// `ScriptCoverage.url` can be overridden by a magic sourceURL comment.
// Get the associated ScriptParsedEvent and use embedderName, which is the original url.
// See https://chromium-review.googlesource.com/c/v8/v8/+/2317310
let url = scriptUsage.url;
const scriptParsedEvent =
this._scriptParsedEvents.find(e => e.scriptId === scriptUsage.scriptId);
if (scriptParsedEvent && scriptParsedEvent.embedderName) {
url = scriptParsedEvent.embedderName;
}
// If `url` is blank, that means the script was anonymous (eval, new Function, onload, ...).
// Or, it's because it was code Lighthouse over the protocol via `Runtime.evaluate`.
// We currently don't consider coverage of anonymous scripts, and we definitely don't want
// coverage of code Lighthouse ran to inspect the page, so we ignore this ScriptCoverage if
// url is blank.
if (scriptUsage.url === '' || (scriptParsedEvent && scriptParsedEvent.embedderName === '')) {
continue;
}
const scripts = usageByUrl[url] || [];
scripts.push(scriptUsage);
usageByUrl[url] = scripts;
}
return usageByUrl;
}
}
module.exports = JsUsage;