lighthouse 9.5.0-dev.20220330 → 9.5.0-dev.20220402
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/lighthouse-cli/test/smokehouse/lighthouse-runners/devtools.js +4 -2
- package/lighthouse-core/audits/preload-lcp-image.js +2 -2
- package/lighthouse-core/audits/script-treemap-data.js +31 -32
- package/lighthouse-core/fraggle-rock/gather/runner-helpers.js +0 -3
- package/lighthouse-core/fraggle-rock/gather/snapshot-runner.js +0 -1
- package/lighthouse-core/fraggle-rock/gather/timespan-runner.js +0 -2
- package/lighthouse-core/gather/connections/cri.js +1 -0
- package/lighthouse-core/gather/gatherers/seo/robots-txt.js +2 -1
- package/lighthouse-core/gather/gatherers/web-app-manifest.js +2 -2
- package/package.json +4 -4
- package/shared/localization/locales/en-US.json +1 -1
- package/shared/localization/locales/en-XL.json +1 -1
- package/types/gatherer.d.ts +0 -2
|
@@ -38,13 +38,15 @@ async function spawnAndLog(logs, command, args) {
|
|
|
38
38
|
spawnHandle.on('error', (error) => {
|
|
39
39
|
logs.push(`ERROR: ${error.toString()}`);
|
|
40
40
|
});
|
|
41
|
+
spawnHandle.stdout.setEncoding('utf8');
|
|
41
42
|
spawnHandle.stdout.on('data', data => {
|
|
42
43
|
process.stdout.write(data);
|
|
43
|
-
logs.push(`STDOUT: ${data
|
|
44
|
+
logs.push(`STDOUT: ${data}`);
|
|
44
45
|
});
|
|
46
|
+
spawnHandle.stderr.setEncoding('utf8');
|
|
45
47
|
spawnHandle.stderr.on('data', data => {
|
|
46
48
|
process.stderr.write(data);
|
|
47
|
-
logs.push(`STDERR: ${data
|
|
49
|
+
logs.push(`STDERR: ${data}`);
|
|
48
50
|
});
|
|
49
51
|
});
|
|
50
52
|
await promise;
|
|
@@ -17,8 +17,8 @@ const UIStrings = {
|
|
|
17
17
|
/** Title of a lighthouse audit that tells a user to preload an image in order to improve their LCP time. */
|
|
18
18
|
title: 'Preload Largest Contentful Paint image',
|
|
19
19
|
/** Description of a lighthouse audit that tells a user to preload an image in order to improve their LCP time. */
|
|
20
|
-
description: '
|
|
21
|
-
'
|
|
20
|
+
description: 'If the LCP element is dynamically added to the page, you should preload the ' +
|
|
21
|
+
'image in order to improve LCP. [Learn more](https://web.dev/optimize-lcp/#preload-important-resources).',
|
|
22
22
|
};
|
|
23
23
|
|
|
24
24
|
const str_ = i18n.createMessageInstanceIdFn(__filename, UIStrings);
|
|
@@ -148,10 +148,10 @@ class ScriptTreemapDataAudit extends Audit {
|
|
|
148
148
|
* Returns nodes where the first level of nodes are URLs.
|
|
149
149
|
* Every external script has a node.
|
|
150
150
|
* All inline scripts are combined into a single node.
|
|
151
|
-
* If a script has a source map, that node will be
|
|
151
|
+
* If a script has a source map, that node will be created by makeScriptNode.
|
|
152
152
|
*
|
|
153
153
|
* Example return result:
|
|
154
|
-
- index.html (
|
|
154
|
+
- index.html (inline scripts)
|
|
155
155
|
- main.js
|
|
156
156
|
- - webpack://
|
|
157
157
|
- - - react.js
|
|
@@ -165,43 +165,18 @@ class ScriptTreemapDataAudit extends Audit {
|
|
|
165
165
|
static async makeNodes(artifacts, context) {
|
|
166
166
|
/** @type {LH.Treemap.Node[]} */
|
|
167
167
|
const nodes = [];
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
for (const script of artifacts.Scripts) {
|
|
171
|
-
// Combine so that inline scripts show up as a single root node.
|
|
172
|
-
if (script.url === artifacts.URL.finalUrl) {
|
|
173
|
-
inlineScriptLength += (script.content || '').length;
|
|
174
|
-
}
|
|
175
|
-
}
|
|
176
|
-
if (inlineScriptLength) {
|
|
177
|
-
const name = artifacts.URL.finalUrl;
|
|
178
|
-
nodes.push({
|
|
179
|
-
name,
|
|
180
|
-
resourceBytes: inlineScriptLength,
|
|
181
|
-
});
|
|
182
|
-
}
|
|
183
|
-
|
|
168
|
+
/** @type {Map<string, LH.Treemap.Node>} */
|
|
169
|
+
const htmlNodesByFrameId = new Map();
|
|
184
170
|
const bundles = await JsBundles.request(artifacts, context);
|
|
185
171
|
const duplicationByPath = await ModuleDuplication.request(artifacts, context);
|
|
186
172
|
|
|
187
173
|
for (const script of artifacts.Scripts) {
|
|
188
|
-
if (script.
|
|
174
|
+
if (script.scriptLanguage !== 'JavaScript') continue;
|
|
189
175
|
|
|
190
176
|
const name = script.url;
|
|
191
177
|
const bundle = bundles.find(bundle => script.scriptId === bundle.script.scriptId);
|
|
192
|
-
const scriptCoverage = /** @type {
|
|
178
|
+
const scriptCoverage = /** @type {LH.Artifacts['JsUsage'][string] | undefined} */
|
|
193
179
|
(artifacts.JsUsage[script.scriptId]);
|
|
194
|
-
if (!bundle && !scriptCoverage) {
|
|
195
|
-
// No bundle and no coverage information, so simply make a single node
|
|
196
|
-
// detailing how big the script is.
|
|
197
|
-
|
|
198
|
-
nodes.push({
|
|
199
|
-
name,
|
|
200
|
-
resourceBytes: script.length || 0,
|
|
201
|
-
});
|
|
202
|
-
continue;
|
|
203
|
-
}
|
|
204
|
-
|
|
205
180
|
const unusedJavascriptSummary = scriptCoverage ?
|
|
206
181
|
await UnusedJavaScriptSummary.request(
|
|
207
182
|
{scriptId: script.scriptId, scriptCoverage, bundle}, context) :
|
|
@@ -259,7 +234,31 @@ class ScriptTreemapDataAudit extends Audit {
|
|
|
259
234
|
};
|
|
260
235
|
}
|
|
261
236
|
|
|
262
|
-
|
|
237
|
+
// If this is an inline script, place the node inside a top-level (aka depth-one) node.
|
|
238
|
+
// Also separate each iframe / the main page's inline scripts into their own top-level nodes.
|
|
239
|
+
const isInlineHtmlScript = script.startColumn || script.startLine;
|
|
240
|
+
if (isInlineHtmlScript) {
|
|
241
|
+
let htmlNode = htmlNodesByFrameId.get(script.executionContextAuxData.frameId);
|
|
242
|
+
if (!htmlNode) {
|
|
243
|
+
htmlNode = {
|
|
244
|
+
name,
|
|
245
|
+
resourceBytes: 0,
|
|
246
|
+
unusedBytes: undefined,
|
|
247
|
+
children: [],
|
|
248
|
+
};
|
|
249
|
+
htmlNodesByFrameId.set(script.executionContextAuxData.frameId, htmlNode);
|
|
250
|
+
nodes.push(htmlNode);
|
|
251
|
+
}
|
|
252
|
+
htmlNode.resourceBytes += node.resourceBytes;
|
|
253
|
+
if (node.unusedBytes) htmlNode.unusedBytes = (htmlNode.unusedBytes || 0) + node.unusedBytes;
|
|
254
|
+
node.name = script.content ?
|
|
255
|
+
'(inline) ' + script.content.trimStart().substring(0, 15) + '…' :
|
|
256
|
+
'(inline)';
|
|
257
|
+
htmlNode.children?.push(node);
|
|
258
|
+
} else {
|
|
259
|
+
// Non-inline scripts each have their own top-level node.
|
|
260
|
+
nodes.push(node);
|
|
261
|
+
}
|
|
263
262
|
}
|
|
264
263
|
|
|
265
264
|
return nodes;
|
|
@@ -15,7 +15,6 @@
|
|
|
15
15
|
* @property {LH.Gatherer.GatherMode} gatherMode
|
|
16
16
|
* @property {Map<string, LH.ArbitraryEqualityMap>} computedCache
|
|
17
17
|
* @property {LH.Config.Settings} settings
|
|
18
|
-
* @property {string} url
|
|
19
18
|
*/
|
|
20
19
|
|
|
21
20
|
/** @typedef {Record<string, Promise<any>>} IntermediateArtifacts */
|
|
@@ -75,7 +74,6 @@ async function collectPhaseArtifacts(options) {
|
|
|
75
74
|
gatherMode,
|
|
76
75
|
computedCache,
|
|
77
76
|
settings,
|
|
78
|
-
url,
|
|
79
77
|
} = options;
|
|
80
78
|
const priorPhase = phaseToPriorPhase[phase];
|
|
81
79
|
const priorPhaseArtifacts = (priorPhase && artifactState[priorPhase]) || {};
|
|
@@ -92,7 +90,6 @@ async function collectPhaseArtifacts(options) {
|
|
|
92
90
|
: /** @type {Dependencies} */ ({});
|
|
93
91
|
|
|
94
92
|
return gatherer[phase]({
|
|
95
|
-
url,
|
|
96
93
|
gatherMode,
|
|
97
94
|
driver,
|
|
98
95
|
baseArtifacts,
|
|
@@ -37,7 +37,6 @@ async function startTimespanGather(options) {
|
|
|
37
37
|
const artifactState = getEmptyArtifactState();
|
|
38
38
|
/** @type {Omit<import('./runner-helpers.js').CollectPhaseArtifactOptions, 'phase'>} */
|
|
39
39
|
const phaseOptions = {
|
|
40
|
-
url: initialUrl,
|
|
41
40
|
driver,
|
|
42
41
|
artifactDefinitions,
|
|
43
42
|
artifactState,
|
|
@@ -54,7 +53,6 @@ async function startTimespanGather(options) {
|
|
|
54
53
|
return {
|
|
55
54
|
async endTimespanGather() {
|
|
56
55
|
const finalUrl = await driver.url();
|
|
57
|
-
phaseOptions.url = finalUrl;
|
|
58
56
|
|
|
59
57
|
const runnerOptions = {config, computedCache};
|
|
60
58
|
const artifacts = await Runner.gather(
|
|
@@ -46,7 +46,8 @@ class RobotsTxt extends FRGatherer {
|
|
|
46
46
|
});
|
|
47
47
|
}
|
|
48
48
|
|
|
49
|
-
const
|
|
49
|
+
const {finalUrl} = passContext.baseArtifacts.URL;
|
|
50
|
+
const robotsUrl = new URL('/robots.txt', finalUrl).href;
|
|
50
51
|
await passContext.driver.fetcher.enable();
|
|
51
52
|
return passContext.driver.fetcher.fetchResource(robotsUrl)
|
|
52
53
|
.catch(err => ({status: null, content: null, errorMessage: err.message}));
|
|
@@ -94,8 +94,8 @@ class WebAppManifest extends FRGatherer {
|
|
|
94
94
|
*/
|
|
95
95
|
getArtifact(context) {
|
|
96
96
|
const driver = context.driver;
|
|
97
|
-
|
|
98
|
-
return WebAppManifest.getWebAppManifest(driver.defaultSession,
|
|
97
|
+
const {finalUrl} = context.baseArtifacts.URL;
|
|
98
|
+
return WebAppManifest.getWebAppManifest(driver.defaultSession, finalUrl);
|
|
99
99
|
}
|
|
100
100
|
}
|
|
101
101
|
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "lighthouse",
|
|
3
|
-
"version": "9.5.0-dev.
|
|
3
|
+
"version": "9.5.0-dev.20220402",
|
|
4
4
|
"description": "Automated auditing, performance metrics, and best practices for the web.",
|
|
5
5
|
"main": "./lighthouse-core/index.js",
|
|
6
6
|
"bin": {
|
|
@@ -89,8 +89,8 @@
|
|
|
89
89
|
"compile-proto": "protoc --python_out=./ ./proto/lighthouse-result.proto && mv ./proto/*_pb2.py ./proto/scripts || (echo \"❌ Install protobuf ≥ 3.7.1 to compile the proto file.\" && false)",
|
|
90
90
|
"build-proto-roundtrip": "mkdir -p .tmp && cross-env PROTOCOL_BUFFERS_PYTHON_IMPLEMENTATION_VERSION=2 python proto/scripts/json_roundtrip_via_proto.py",
|
|
91
91
|
"static-server": "node lighthouse-cli/test/fixtures/static-server.js",
|
|
92
|
-
"serve-dist": "cd dist &&
|
|
93
|
-
"serve-gh-pages": "cd dist/gh-pages &&
|
|
92
|
+
"serve-dist": "cd dist && python3 -m http.server",
|
|
93
|
+
"serve-gh-pages": "cd dist/gh-pages && python3 -m http.server",
|
|
94
94
|
"serve-treemap": "yarn serve-gh-pages",
|
|
95
95
|
"serve-viewer": "yarn serve-gh-pages",
|
|
96
96
|
"flow-report": "yarn build-report --flow && node ./lighthouse-core/scripts/build-test-flow-report.js"
|
|
@@ -203,7 +203,7 @@
|
|
|
203
203
|
"robots-parser": "^3.0.0",
|
|
204
204
|
"semver": "^5.3.0",
|
|
205
205
|
"speedline-core": "^1.4.3",
|
|
206
|
-
"third-party-web": "^0.
|
|
206
|
+
"third-party-web": "^0.15.0",
|
|
207
207
|
"ws": "^7.0.0",
|
|
208
208
|
"yargs": "^17.3.1",
|
|
209
209
|
"yargs-parser": "^21.0.0"
|
|
@@ -1272,7 +1272,7 @@
|
|
|
1272
1272
|
"message": "Fonts with `font-display: optional` are preloaded"
|
|
1273
1273
|
},
|
|
1274
1274
|
"lighthouse-core/audits/preload-lcp-image.js | description": {
|
|
1275
|
-
"message": "
|
|
1275
|
+
"message": "If the LCP element is dynamically added to the page, you should preload the image in order to improve LCP. [Learn more](https://web.dev/optimize-lcp/#preload-important-resources)."
|
|
1276
1276
|
},
|
|
1277
1277
|
"lighthouse-core/audits/preload-lcp-image.js | title": {
|
|
1278
1278
|
"message": "Preload Largest Contentful Paint image"
|
|
@@ -1272,7 +1272,7 @@
|
|
|
1272
1272
|
"message": "F̂ón̂t́ŝ ẃît́ĥ `font-display: optional` ár̂é p̂ŕêĺôád̂éd̂"
|
|
1273
1273
|
},
|
|
1274
1274
|
"lighthouse-core/audits/preload-lcp-image.js | description": {
|
|
1275
|
-
"message": "
|
|
1275
|
+
"message": "Îf́ t̂h́ê ĹĈṔ êĺêḿêńt̂ íŝ d́ŷńâḿîćâĺl̂ý âd́d̂éd̂ t́ô t́ĥé p̂áĝé, ŷóû śĥóûĺd̂ ṕr̂él̂óâd́ t̂h́ê ím̂áĝé îń ôŕd̂ér̂ t́ô ím̂ṕr̂óv̂é L̂ĆP̂. [Ĺêár̂ń m̂ór̂é](https://web.dev/optimize-lcp/#preload-important-resources)."
|
|
1276
1276
|
},
|
|
1277
1277
|
"lighthouse-core/audits/preload-lcp-image.js | title": {
|
|
1278
1278
|
"message": "P̂ŕêĺôád̂ Ĺâŕĝéŝt́ Ĉón̂t́êńt̂f́ûĺ P̂áîńt̂ ím̂áĝé"
|
package/types/gatherer.d.ts
CHANGED
|
@@ -47,8 +47,6 @@ declare module Gatherer {
|
|
|
47
47
|
|
|
48
48
|
/** The limited context interface shared between pre and post Fraggle Rock Lighthouse. */
|
|
49
49
|
interface FRTransitionalContext<TDependencies extends DependencyKey = DefaultDependenciesKey> {
|
|
50
|
-
/** The URL of the page that is currently active. Might be `about:blank` in the before phases */
|
|
51
|
-
url: string;
|
|
52
50
|
/** The gather mode Lighthouse is currently in. */
|
|
53
51
|
gatherMode: GatherMode;
|
|
54
52
|
/** The connection to the page being analyzed. */
|