lighthouse 9.5.0-dev.20230123 → 9.5.0-dev.20230125
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/.codecov.yml +0 -5
- package/core/audits/accessibility/accesskeys.js +1 -1
- package/core/audits/accessibility/aria-allowed-attr.js +1 -1
- package/core/audits/accessibility/aria-command-name.js +1 -1
- package/core/audits/accessibility/aria-hidden-body.js +1 -1
- package/core/audits/accessibility/aria-hidden-focus.js +1 -1
- package/core/audits/accessibility/aria-input-field-name.js +1 -1
- package/core/audits/accessibility/aria-meter-name.js +1 -1
- package/core/audits/accessibility/aria-progressbar-name.js +1 -1
- package/core/audits/accessibility/aria-required-attr.js +1 -1
- package/core/audits/accessibility/aria-required-children.js +1 -1
- package/core/audits/accessibility/aria-required-parent.js +1 -1
- package/core/audits/accessibility/aria-roles.js +1 -1
- package/core/audits/accessibility/aria-toggle-field-name.js +1 -1
- package/core/audits/accessibility/aria-tooltip-name.js +1 -1
- package/core/audits/accessibility/aria-treeitem-name.js +1 -1
- package/core/audits/accessibility/aria-valid-attr-value.js +1 -1
- package/core/audits/accessibility/aria-valid-attr.js +1 -1
- package/core/audits/accessibility/button-name.js +1 -1
- package/core/audits/accessibility/bypass.js +1 -1
- package/core/audits/accessibility/color-contrast.js +1 -1
- package/core/audits/accessibility/definition-list.js +1 -1
- package/core/audits/accessibility/dlitem.js +1 -1
- package/core/audits/accessibility/document-title.js +1 -1
- package/core/audits/accessibility/duplicate-id-active.js +1 -1
- package/core/audits/accessibility/duplicate-id-aria.js +1 -1
- package/core/audits/accessibility/form-field-multiple-labels.js +1 -1
- package/core/audits/accessibility/frame-title.js +1 -1
- package/core/audits/accessibility/heading-order.js +1 -1
- package/core/audits/accessibility/html-has-lang.js +1 -1
- package/core/audits/accessibility/html-lang-valid.js +1 -1
- package/core/audits/accessibility/image-alt.js +1 -1
- package/core/audits/accessibility/input-image-alt.js +1 -1
- package/core/audits/accessibility/label.js +1 -1
- package/core/audits/accessibility/link-name.js +1 -1
- package/core/audits/accessibility/list.js +1 -1
- package/core/audits/accessibility/listitem.js +1 -1
- package/core/audits/accessibility/meta-refresh.js +1 -1
- package/core/audits/accessibility/meta-viewport.js +1 -1
- package/core/audits/accessibility/object-alt.js +1 -1
- package/core/audits/accessibility/tabindex.js +1 -1
- package/core/audits/accessibility/td-headers-attr.js +1 -1
- package/core/audits/accessibility/th-has-data-cells.js +1 -1
- package/core/audits/accessibility/valid-lang.js +1 -1
- package/core/audits/accessibility/video-caption.js +1 -1
- package/core/audits/audit.js +1 -1
- package/core/audits/byte-efficiency/legacy-javascript.d.ts +1 -0
- package/core/audits/byte-efficiency/legacy-javascript.js +7 -3
- package/core/audits/dobetterweb/uses-http2.d.ts +5 -2
- package/core/audits/dobetterweb/uses-http2.js +12 -7
- package/core/audits/network-requests.js +7 -6
- package/core/audits/third-party-facades.d.ts +3 -2
- package/core/audits/third-party-facades.js +12 -9
- package/core/audits/third-party-summary.d.ts +7 -6
- package/core/audits/third-party-summary.js +16 -14
- package/core/audits/valid-source-maps.d.ts +5 -3
- package/core/audits/valid-source-maps.js +11 -9
- package/core/computed/entity-classification.d.ts +29 -0
- package/core/computed/entity-classification.js +102 -0
- package/core/computed/metrics/responsiveness.js +5 -2
- package/core/computed/page-dependency-graph.js +1 -1
- package/core/computed/resource-summary.d.ts +4 -2
- package/core/computed/resource-summary.js +8 -5
- package/core/gather/gatherers/accessibility.js +3 -1
- package/core/lib/network-request.d.ts +2 -0
- package/core/lib/network-request.js +3 -0
- package/core/lib/stack-packs.js +4 -0
- package/core/lib/tracehouse/trace-processor.d.ts +14 -5
- package/core/lib/tracehouse/trace-processor.js +85 -30
- package/core/lib/traces/metric-trace-events.js +1 -1
- package/core/lib/url-utils.js +1 -1
- package/core/runner.d.ts +10 -0
- package/core/runner.js +48 -0
- package/dist/report/bundle.esm.js +724 -687
- package/dist/report/flow.js +25 -15
- package/dist/report/standalone.js +25 -15
- package/flow-report/src/common.tsx +1 -1
- package/flow-report/src/i18n/i18n.tsx +17 -16
- package/flow-report/src/sidebar/sidebar.tsx +2 -2
- package/flow-report/src/summary/category.tsx +6 -6
- package/flow-report/src/summary/summary.tsx +2 -2
- package/package.json +7 -8
- package/report/renderer/category-renderer.js +19 -17
- package/report/renderer/crc-details-renderer.js +6 -6
- package/report/renderer/details-renderer.js +7 -6
- package/report/renderer/dom.js +1 -1
- package/report/renderer/element-screenshot-renderer.js +3 -3
- package/report/renderer/performance-category-renderer.js +17 -15
- package/report/renderer/pwa-category-renderer.js +5 -4
- package/report/renderer/report-globals.d.ts +21 -0
- package/report/renderer/report-globals.js +49 -0
- package/report/renderer/report-renderer.js +22 -20
- package/report/renderer/report-ui-features.js +9 -8
- package/report/renderer/report-utils.d.ts +116 -0
- package/report/renderer/{util.js → report-utils.js} +81 -429
- package/report/renderer/snippet-renderer.js +3 -2
- package/report/test/renderer/category-renderer-test.js +9 -4
- package/report/test/renderer/crc-details-renderer-test.js +7 -3
- package/report/test/renderer/details-renderer-test.js +7 -3
- package/report/test/renderer/dom-test.js +7 -3
- package/report/test/renderer/element-screenshot-renderer-test.js +8 -4
- package/report/test/renderer/performance-category-renderer-test.js +14 -9
- package/report/test/renderer/pwa-category-renderer-test.js +10 -5
- package/report/test/renderer/report-renderer-test.js +2 -2
- package/report/test/renderer/report-ui-features-test.js +3 -3
- package/report/test/renderer/{util-test.js → report-utils-test.js} +36 -234
- package/report/test/renderer/snippet-renderer-test.js +7 -3
- package/shared/localization/format.js +5 -2
- package/shared/localization/locales/ar-XB.json +50 -50
- package/shared/localization/locales/ar.json +50 -50
- package/shared/localization/locales/bg.json +50 -50
- package/shared/localization/locales/ca.json +50 -50
- package/shared/localization/locales/cs.json +50 -50
- package/shared/localization/locales/da.json +50 -50
- package/shared/localization/locales/de.json +50 -50
- package/shared/localization/locales/el.json +50 -50
- package/shared/localization/locales/en-GB.json +50 -50
- package/shared/localization/locales/en-US.json +128 -98
- package/shared/localization/locales/en-XA.json +50 -50
- package/shared/localization/locales/en-XL.json +128 -98
- package/shared/localization/locales/es-419.json +50 -50
- package/shared/localization/locales/es.json +50 -50
- package/shared/localization/locales/fi.json +50 -50
- package/shared/localization/locales/fil.json +50 -50
- package/shared/localization/locales/fr.json +50 -50
- package/shared/localization/locales/he.json +50 -50
- package/shared/localization/locales/hi.json +50 -50
- package/shared/localization/locales/hr.json +50 -50
- package/shared/localization/locales/hu.json +50 -50
- package/shared/localization/locales/id.json +50 -50
- package/shared/localization/locales/it.json +50 -50
- package/shared/localization/locales/ja.json +50 -50
- package/shared/localization/locales/ko.json +50 -50
- package/shared/localization/locales/lt.json +50 -50
- package/shared/localization/locales/lv.json +50 -50
- package/shared/localization/locales/nl.json +50 -50
- package/shared/localization/locales/no.json +50 -50
- package/shared/localization/locales/pl.json +50 -50
- package/shared/localization/locales/pt-PT.json +50 -50
- package/shared/localization/locales/pt.json +50 -50
- package/shared/localization/locales/ro.json +50 -50
- package/shared/localization/locales/ru.json +50 -50
- package/shared/localization/locales/sk.json +50 -50
- package/shared/localization/locales/sl.json +50 -50
- package/shared/localization/locales/sr-Latn.json +50 -50
- package/shared/localization/locales/sr.json +50 -50
- package/shared/localization/locales/sv.json +50 -50
- package/shared/localization/locales/ta.json +50 -50
- package/shared/localization/locales/te.json +50 -50
- package/shared/localization/locales/th.json +50 -50
- package/shared/localization/locales/tr.json +50 -50
- package/shared/localization/locales/uk.json +50 -50
- package/shared/localization/locales/vi.json +50 -50
- package/shared/localization/locales/zh-HK.json +50 -50
- package/shared/localization/locales/zh-TW.json +50 -50
- package/shared/localization/locales/zh.json +50 -50
- package/shared/test/util-test.js +214 -0
- package/shared/util.d.ts +122 -0
- package/shared/util.js +332 -0
- package/tsconfig.json +0 -2
- package/types/artifacts.d.ts +21 -2
- package/types/lhr/lhr.d.ts +33 -0
- package/core/lib/minify-trace.d.ts +0 -6
- package/core/lib/minify-trace.js +0 -172
- package/core/util.cjs +0 -845
- package/core/util.d.cts +0 -342
- package/report/renderer/util.d.ts +0 -342
|
@@ -13,7 +13,7 @@
|
|
|
13
13
|
/** @typedef {import('../../lib/dependency-graph/base-node.js').Node} Node */
|
|
14
14
|
|
|
15
15
|
import {Audit} from '../audit.js';
|
|
16
|
-
import
|
|
16
|
+
import {EntityClassification} from '../../computed/entity-classification.js';
|
|
17
17
|
import UrlUtils from '../../lib/url-utils.js';
|
|
18
18
|
import {ByteEfficiencyAudit} from '../byte-efficiency/byte-efficiency-audit.js';
|
|
19
19
|
import {LanternInteractive} from '../../computed/metrics/lantern-interactive.js';
|
|
@@ -120,16 +120,19 @@ class UsesHTTP2Audit extends Audit {
|
|
|
120
120
|
* for the same origin at the exact same time.
|
|
121
121
|
*
|
|
122
122
|
* @param {LH.Artifacts.NetworkRequest} networkRequest
|
|
123
|
+
* @param {LH.Artifacts.EntityClassification} classifiedEntities
|
|
123
124
|
* @return {boolean}
|
|
124
125
|
*/
|
|
125
|
-
static isStaticAsset(networkRequest) {
|
|
126
|
+
static isStaticAsset(networkRequest, classifiedEntities) {
|
|
126
127
|
if (!STATIC_RESOURCE_TYPES.has(networkRequest.resourceType)) return false;
|
|
127
128
|
|
|
128
129
|
// Resources from third-parties that are less than 100 bytes are usually tracking pixels, not actual resources.
|
|
129
130
|
// They can masquerade as static types though (gifs, documents, etc)
|
|
130
131
|
if (networkRequest.resourceSize < 100) {
|
|
131
|
-
|
|
132
|
-
|
|
132
|
+
// This logic needs to be revisited.
|
|
133
|
+
// See https://github.com/GoogleChrome/lighthouse/issues/14661
|
|
134
|
+
const entity = classifiedEntities.entityByUrl.get(networkRequest.url);
|
|
135
|
+
if (entity && !entity.isUnrecognized) return false;
|
|
133
136
|
}
|
|
134
137
|
|
|
135
138
|
return true;
|
|
@@ -155,9 +158,10 @@ class UsesHTTP2Audit extends Audit {
|
|
|
155
158
|
* https://www.cachefly.com/http-2-is-not-a-magic-bullet/
|
|
156
159
|
*
|
|
157
160
|
* @param {Array<LH.Artifacts.NetworkRequest>} networkRecords
|
|
161
|
+
* @param {LH.Artifacts.EntityClassification} classifiedEntities
|
|
158
162
|
* @return {Array<{url: string, protocol: string}>}
|
|
159
163
|
*/
|
|
160
|
-
static determineNonHttp2Resources(networkRecords) {
|
|
164
|
+
static determineNonHttp2Resources(networkRecords, classifiedEntities) {
|
|
161
165
|
/** @type {Array<{url: string, protocol: string}>} */
|
|
162
166
|
const nonHttp2Resources = [];
|
|
163
167
|
|
|
@@ -166,7 +170,7 @@ class UsesHTTP2Audit extends Audit {
|
|
|
166
170
|
/** @type {Map<string, Array<LH.Artifacts.NetworkRequest>>} */
|
|
167
171
|
const groupedByOrigin = new Map();
|
|
168
172
|
for (const record of networkRecords) {
|
|
169
|
-
if (!UsesHTTP2Audit.isStaticAsset(record)) continue;
|
|
173
|
+
if (!UsesHTTP2Audit.isStaticAsset(record, classifiedEntities)) continue;
|
|
170
174
|
if (UrlUtils.isLikeLocalhost(record.parsedURL.host)) continue;
|
|
171
175
|
const existing = groupedByOrigin.get(record.parsedURL.securityOrigin) || [];
|
|
172
176
|
existing.push(record);
|
|
@@ -203,7 +207,8 @@ class UsesHTTP2Audit extends Audit {
|
|
|
203
207
|
const devtoolsLog = artifacts.devtoolsLogs[Audit.DEFAULT_PASS];
|
|
204
208
|
const URL = artifacts.URL;
|
|
205
209
|
const networkRecords = await NetworkRecords.request(devtoolsLog, context);
|
|
206
|
-
const
|
|
210
|
+
const classifiedEntities = await EntityClassification.request({URL, devtoolsLog}, context);
|
|
211
|
+
const resources = UsesHTTP2Audit.determineNonHttp2Resources(networkRecords, classifiedEntities);
|
|
207
212
|
|
|
208
213
|
let displayValue;
|
|
209
214
|
if (resources.length > 0) {
|
|
@@ -31,8 +31,8 @@ class NetworkRequests extends Audit {
|
|
|
31
31
|
static async audit(artifacts, context) {
|
|
32
32
|
const devtoolsLog = artifacts.devtoolsLogs[Audit.DEFAULT_PASS];
|
|
33
33
|
const records = await NetworkRecords.request(devtoolsLog, context);
|
|
34
|
-
const
|
|
35
|
-
(min, record) => Math.min(min, record.
|
|
34
|
+
const earliestRendererStartTime = records.reduce(
|
|
35
|
+
(min, record) => Math.min(min, record.rendererStartTime),
|
|
36
36
|
Infinity
|
|
37
37
|
);
|
|
38
38
|
|
|
@@ -47,8 +47,8 @@ class NetworkRequests extends Audit {
|
|
|
47
47
|
}
|
|
48
48
|
|
|
49
49
|
/** @param {number} time */
|
|
50
|
-
const normalizeTime = time => time <
|
|
51
|
-
undefined : (time -
|
|
50
|
+
const normalizeTime = time => time < earliestRendererStartTime || !Number.isFinite(time) ?
|
|
51
|
+
undefined : (time - earliestRendererStartTime);
|
|
52
52
|
|
|
53
53
|
const results = records.map(record => {
|
|
54
54
|
const endTimeDeltaMs = record.lrStatistics?.endTimeDeltaMs;
|
|
@@ -64,6 +64,7 @@ class NetworkRequests extends Audit {
|
|
|
64
64
|
return {
|
|
65
65
|
url: UrlUtils.elideDataURI(record.url),
|
|
66
66
|
protocol: record.protocol,
|
|
67
|
+
rendererStartTime: normalizeTime(record.rendererStartTime),
|
|
67
68
|
startTime: normalizeTime(record.startTime),
|
|
68
69
|
endTime: normalizeTime(record.endTime),
|
|
69
70
|
finished: record.finished,
|
|
@@ -111,8 +112,8 @@ class NetworkRequests extends Audit {
|
|
|
111
112
|
const tableDetails = Audit.makeTableDetails(headings, results);
|
|
112
113
|
|
|
113
114
|
// Include starting timestamp to allow syncing requests with navStart/metric timestamps.
|
|
114
|
-
const networkStartTimeTs = Number.isFinite(
|
|
115
|
-
|
|
115
|
+
const networkStartTimeTs = Number.isFinite(earliestRendererStartTime) ?
|
|
116
|
+
earliestRendererStartTime * 1000 : undefined;
|
|
116
117
|
tableDetails.debugData = {
|
|
117
118
|
type: 'debugdata',
|
|
118
119
|
networkStartTimeTs,
|
|
@@ -15,10 +15,10 @@ declare class ThirdPartyFacades extends Audit {
|
|
|
15
15
|
static condenseItems(items: import('./third-party-summary.js').URLSummary[]): void;
|
|
16
16
|
/**
|
|
17
17
|
* @param {Map<string, import('./third-party-summary.js').Summary>} byURL
|
|
18
|
-
* @param {
|
|
18
|
+
* @param {LH.Artifacts.EntityClassification} classifiedEntities
|
|
19
19
|
* @return {FacadableProduct[]}
|
|
20
20
|
*/
|
|
21
|
-
static getProductsWithFacade(byURL: Map<string, import('./third-party-summary.js').Summary>,
|
|
21
|
+
static getProductsWithFacade(byURL: Map<string, import('./third-party-summary.js').Summary>, classifiedEntities: LH.Artifacts.EntityClassification): FacadableProduct[];
|
|
22
22
|
/**
|
|
23
23
|
* @param {LH.Artifacts} artifacts
|
|
24
24
|
* @param {LH.Audit.Context} context
|
|
@@ -38,4 +38,5 @@ export namespace UIStrings {
|
|
|
38
38
|
const categorySocial: string;
|
|
39
39
|
}
|
|
40
40
|
import { Audit } from "./audit.js";
|
|
41
|
+
import { EntityClassification } from "../computed/entity-classification.js";
|
|
41
42
|
//# sourceMappingURL=third-party-facades.d.ts.map
|
|
@@ -21,9 +21,9 @@
|
|
|
21
21
|
|
|
22
22
|
import {Audit} from './audit.js';
|
|
23
23
|
import * as i18n from '../lib/i18n/i18n.js';
|
|
24
|
+
import {EntityClassification} from '../computed/entity-classification.js';
|
|
24
25
|
import thirdPartyWeb from '../lib/third-party-web.js';
|
|
25
26
|
import {NetworkRecords} from '../computed/network-records.js';
|
|
26
|
-
import {MainResource} from '../computed/main-resource.js';
|
|
27
27
|
import {MainThreadTasks} from '../computed/main-thread-tasks.js';
|
|
28
28
|
import ThirdPartySummary from './third-party-summary.js';
|
|
29
29
|
|
|
@@ -121,15 +121,15 @@ class ThirdPartyFacades extends Audit {
|
|
|
121
121
|
|
|
122
122
|
/**
|
|
123
123
|
* @param {Map<string, import('./third-party-summary.js').Summary>} byURL
|
|
124
|
-
* @param {
|
|
124
|
+
* @param {LH.Artifacts.EntityClassification} classifiedEntities
|
|
125
125
|
* @return {FacadableProduct[]}
|
|
126
126
|
*/
|
|
127
|
-
static getProductsWithFacade(byURL,
|
|
127
|
+
static getProductsWithFacade(byURL, classifiedEntities) {
|
|
128
128
|
/** @type {Map<string, FacadableProduct>} */
|
|
129
129
|
const facadableProductMap = new Map();
|
|
130
130
|
for (const url of byURL.keys()) {
|
|
131
|
-
const entity =
|
|
132
|
-
if (!entity ||
|
|
131
|
+
const entity = classifiedEntities.entityByUrl.get(url);
|
|
132
|
+
if (!entity || classifiedEntities.isFirstParty(url)) continue;
|
|
133
133
|
|
|
134
134
|
const product = thirdPartyWeb.getProduct(url);
|
|
135
135
|
if (!product || !product.facades || !product.facades.length) continue;
|
|
@@ -151,14 +151,15 @@ class ThirdPartyFacades extends Audit {
|
|
|
151
151
|
const trace = artifacts.traces[Audit.DEFAULT_PASS];
|
|
152
152
|
const devtoolsLog = artifacts.devtoolsLogs[Audit.DEFAULT_PASS];
|
|
153
153
|
const networkRecords = await NetworkRecords.request(devtoolsLog, context);
|
|
154
|
-
const
|
|
155
|
-
|
|
154
|
+
const classifiedEntities = await EntityClassification.request(
|
|
155
|
+
{URL: artifacts.URL, devtoolsLog}, context);
|
|
156
156
|
const tasks = await MainThreadTasks.request(trace, context);
|
|
157
157
|
const multiplier = settings.throttlingMethod === 'simulate' ?
|
|
158
158
|
settings.throttling.cpuSlowdownMultiplier : 1;
|
|
159
|
-
const summaries = ThirdPartySummary.getSummaries(networkRecords, tasks, multiplier
|
|
159
|
+
const summaries = ThirdPartySummary.getSummaries(networkRecords, tasks, multiplier,
|
|
160
|
+
classifiedEntities);
|
|
160
161
|
const facadableProducts =
|
|
161
|
-
ThirdPartyFacades.getProductsWithFacade(summaries.byURL,
|
|
162
|
+
ThirdPartyFacades.getProductsWithFacade(summaries.byURL, classifiedEntities);
|
|
162
163
|
|
|
163
164
|
/** @type {LH.Audit.Details.TableItem[]} */
|
|
164
165
|
const results = [];
|
|
@@ -188,6 +189,8 @@ class ThirdPartyFacades extends Audit {
|
|
|
188
189
|
transferSize: entitySummary.transferSize,
|
|
189
190
|
blockingTime: entitySummary.blockingTime,
|
|
190
191
|
subItems: {type: 'subitems', items},
|
|
192
|
+
// Add entity manually since facades don't have a single `url`.
|
|
193
|
+
entity: entity.name,
|
|
191
194
|
});
|
|
192
195
|
}
|
|
193
196
|
|
|
@@ -1,5 +1,4 @@
|
|
|
1
1
|
export default ThirdPartySummary;
|
|
2
|
-
export type ThirdPartyEntity = import("third-party-web").IEntity;
|
|
3
2
|
export type Summary = {
|
|
4
3
|
mainThreadTime: number;
|
|
5
4
|
transferSize: number;
|
|
@@ -14,7 +13,7 @@ export type SummaryMaps = {
|
|
|
14
13
|
/**
|
|
15
14
|
* Map of impact summaries for each entity.
|
|
16
15
|
*/
|
|
17
|
-
byEntity: Map<
|
|
16
|
+
byEntity: Map<LH.Artifacts.Entity, Summary>;
|
|
18
17
|
/**
|
|
19
18
|
* Map of impact summaries for each URL.
|
|
20
19
|
*/
|
|
@@ -22,7 +21,7 @@ export type SummaryMaps = {
|
|
|
22
21
|
/**
|
|
23
22
|
* Map of URLs under each entity.
|
|
24
23
|
*/
|
|
25
|
-
urls: Map<
|
|
24
|
+
urls: Map<LH.Artifacts.Entity, string[]>;
|
|
26
25
|
};
|
|
27
26
|
declare class ThirdPartySummary extends Audit {
|
|
28
27
|
/**
|
|
@@ -30,16 +29,17 @@ declare class ThirdPartySummary extends Audit {
|
|
|
30
29
|
* @param {Array<LH.Artifacts.NetworkRequest>} networkRecords
|
|
31
30
|
* @param {Array<LH.Artifacts.TaskNode>} mainThreadTasks
|
|
32
31
|
* @param {number} cpuMultiplier
|
|
32
|
+
* @param {LH.Artifacts.EntityClassification} entityClassification
|
|
33
33
|
* @return {SummaryMaps}
|
|
34
34
|
*/
|
|
35
|
-
static getSummaries(networkRecords: Array<LH.Artifacts.NetworkRequest>, mainThreadTasks: Array<LH.Artifacts.TaskNode>, cpuMultiplier: number): SummaryMaps;
|
|
35
|
+
static getSummaries(networkRecords: Array<LH.Artifacts.NetworkRequest>, mainThreadTasks: Array<LH.Artifacts.TaskNode>, cpuMultiplier: number, entityClassification: LH.Artifacts.EntityClassification): SummaryMaps;
|
|
36
36
|
/**
|
|
37
|
-
* @param {
|
|
37
|
+
* @param {LH.Artifacts.Entity} entity
|
|
38
38
|
* @param {SummaryMaps} summaries
|
|
39
39
|
* @param {Summary} stats
|
|
40
40
|
* @return {Array<URLSummary>}
|
|
41
41
|
*/
|
|
42
|
-
static makeSubItems(entity:
|
|
42
|
+
static makeSubItems(entity: LH.Artifacts.Entity, summaries: SummaryMaps, stats: Summary): Array<URLSummary>;
|
|
43
43
|
/**
|
|
44
44
|
* @param {LH.Artifacts} artifacts
|
|
45
45
|
* @param {LH.Audit.Context} context
|
|
@@ -55,4 +55,5 @@ export namespace UIStrings {
|
|
|
55
55
|
const displayValue: string;
|
|
56
56
|
}
|
|
57
57
|
import { Audit } from "./audit.js";
|
|
58
|
+
import { EntityClassification } from "../computed/entity-classification.js";
|
|
58
59
|
//# sourceMappingURL=third-party-summary.d.ts.map
|
|
@@ -5,8 +5,8 @@
|
|
|
5
5
|
*/
|
|
6
6
|
|
|
7
7
|
import {Audit} from './audit.js';
|
|
8
|
+
import {EntityClassification} from '../computed/entity-classification.js';
|
|
8
9
|
import * as i18n from '../lib/i18n/i18n.js';
|
|
9
|
-
import thirdPartyWeb from '../lib/third-party-web.js';
|
|
10
10
|
import {NetworkRecords} from '../computed/network-records.js';
|
|
11
11
|
import {MainThreadTasks} from '../computed/main-thread-tasks.js';
|
|
12
12
|
import {getJavaScriptURLs, getAttributableURLForTask} from '../lib/tracehouse/task-summary.js';
|
|
@@ -33,8 +33,6 @@ const str_ = i18n.createIcuMessageFn(import.meta.url, UIStrings);
|
|
|
33
33
|
// A page passes when all third-party code blocks for less than 250 ms.
|
|
34
34
|
const PASS_THRESHOLD_IN_MS = 250;
|
|
35
35
|
|
|
36
|
-
/** @typedef {import("third-party-web").IEntity} ThirdPartyEntity */
|
|
37
|
-
|
|
38
36
|
/**
|
|
39
37
|
* @typedef Summary
|
|
40
38
|
* @property {number} mainThreadTime
|
|
@@ -50,9 +48,9 @@ const PASS_THRESHOLD_IN_MS = 250;
|
|
|
50
48
|
*/
|
|
51
49
|
|
|
52
50
|
/** @typedef SummaryMaps
|
|
53
|
-
* @property {Map<
|
|
51
|
+
* @property {Map<LH.Artifacts.Entity, Summary>} byEntity Map of impact summaries for each entity.
|
|
54
52
|
* @property {Map<string, Summary>} byURL Map of impact summaries for each URL.
|
|
55
|
-
* @property {Map<
|
|
53
|
+
* @property {Map<LH.Artifacts.Entity, string[]>} urls Map of URLs under each entity.
|
|
56
54
|
*/
|
|
57
55
|
|
|
58
56
|
/**
|
|
@@ -83,12 +81,13 @@ class ThirdPartySummary extends Audit {
|
|
|
83
81
|
* @param {Array<LH.Artifacts.NetworkRequest>} networkRecords
|
|
84
82
|
* @param {Array<LH.Artifacts.TaskNode>} mainThreadTasks
|
|
85
83
|
* @param {number} cpuMultiplier
|
|
84
|
+
* @param {LH.Artifacts.EntityClassification} entityClassification
|
|
86
85
|
* @return {SummaryMaps}
|
|
87
86
|
*/
|
|
88
|
-
static getSummaries(networkRecords, mainThreadTasks, cpuMultiplier) {
|
|
87
|
+
static getSummaries(networkRecords, mainThreadTasks, cpuMultiplier, entityClassification) {
|
|
89
88
|
/** @type {Map<string, Summary>} */
|
|
90
89
|
const byURL = new Map();
|
|
91
|
-
/** @type {Map<
|
|
90
|
+
/** @type {Map<LH.Artifacts.Entity, Summary>} */
|
|
92
91
|
const byEntity = new Map();
|
|
93
92
|
const defaultSummary = {mainThreadTime: 0, blockingTime: 0, transferSize: 0};
|
|
94
93
|
|
|
@@ -114,11 +113,11 @@ class ThirdPartySummary extends Audit {
|
|
|
114
113
|
byURL.set(attributableURL, urlSummary);
|
|
115
114
|
}
|
|
116
115
|
|
|
117
|
-
// Map each URL's stat to a particular
|
|
118
|
-
/** @type {Map<
|
|
116
|
+
// Map each URL's stat to a particular entity.
|
|
117
|
+
/** @type {Map<LH.Artifacts.Entity, string[]>} */
|
|
119
118
|
const urls = new Map();
|
|
120
119
|
for (const [url, urlSummary] of byURL.entries()) {
|
|
121
|
-
const entity =
|
|
120
|
+
const entity = entityClassification.entityByUrl.get(url);
|
|
122
121
|
if (!entity) {
|
|
123
122
|
byURL.delete(url);
|
|
124
123
|
continue;
|
|
@@ -139,7 +138,7 @@ class ThirdPartySummary extends Audit {
|
|
|
139
138
|
}
|
|
140
139
|
|
|
141
140
|
/**
|
|
142
|
-
* @param {
|
|
141
|
+
* @param {LH.Artifacts.Entity} entity
|
|
143
142
|
* @param {SummaryMaps} summaries
|
|
144
143
|
* @param {Summary} stats
|
|
145
144
|
* @return {Array<URLSummary>}
|
|
@@ -197,18 +196,21 @@ class ThirdPartySummary extends Audit {
|
|
|
197
196
|
const trace = artifacts.traces[Audit.DEFAULT_PASS];
|
|
198
197
|
const devtoolsLog = artifacts.devtoolsLogs[Audit.DEFAULT_PASS];
|
|
199
198
|
const networkRecords = await NetworkRecords.request(devtoolsLog, context);
|
|
200
|
-
const
|
|
199
|
+
const classifiedEntities = await EntityClassification.request(
|
|
200
|
+
{URL: artifacts.URL, devtoolsLog}, context);
|
|
201
|
+
const firstPartyEntity = classifiedEntities.firstParty;
|
|
201
202
|
const tasks = await MainThreadTasks.request(trace, context);
|
|
202
203
|
const multiplier = settings.throttlingMethod === 'simulate' ?
|
|
203
204
|
settings.throttling.cpuSlowdownMultiplier : 1;
|
|
204
205
|
|
|
205
|
-
const summaries = ThirdPartySummary.getSummaries(
|
|
206
|
+
const summaries = ThirdPartySummary.getSummaries(
|
|
207
|
+
networkRecords, tasks, multiplier, classifiedEntities);
|
|
206
208
|
const overallSummary = {wastedBytes: 0, wastedMs: 0};
|
|
207
209
|
|
|
208
210
|
const results = Array.from(summaries.byEntity.entries())
|
|
209
211
|
// Don't consider the page we're on to be third-party.
|
|
210
212
|
// e.g. Facebook SDK isn't a third-party script on facebook.com
|
|
211
|
-
.filter(([entity]) => !(
|
|
213
|
+
.filter(([entity]) => !(firstPartyEntity && firstPartyEntity === entity))
|
|
212
214
|
.map(([entity, stats]) => {
|
|
213
215
|
overallSummary.wastedBytes += stats.transferSize;
|
|
214
216
|
overallSummary.wastedMs += stats.blockingTime;
|
|
@@ -3,14 +3,15 @@ declare class ValidSourceMaps extends Audit {
|
|
|
3
3
|
/**
|
|
4
4
|
* Returns true if the size of the script exceeds a static threshold.
|
|
5
5
|
* @param {LH.Artifacts.Script} script
|
|
6
|
-
* @param {
|
|
6
|
+
* @param {LH.Artifacts.EntityClassification} classifiedEntities
|
|
7
7
|
* @return {boolean}
|
|
8
8
|
*/
|
|
9
|
-
static isLargeFirstPartyJS(script: LH.Artifacts.Script,
|
|
9
|
+
static isLargeFirstPartyJS(script: LH.Artifacts.Script, classifiedEntities: LH.Artifacts.EntityClassification): boolean;
|
|
10
10
|
/**
|
|
11
11
|
* @param {LH.Artifacts} artifacts
|
|
12
|
+
* @param {LH.Audit.Context} context
|
|
12
13
|
*/
|
|
13
|
-
static audit(artifacts: LH.Artifacts): Promise<{
|
|
14
|
+
static audit(artifacts: LH.Artifacts, context: LH.Audit.Context): Promise<{
|
|
14
15
|
score: number;
|
|
15
16
|
details: import("../../types/lhr/audit-details.js").default.Table;
|
|
16
17
|
}>;
|
|
@@ -24,4 +25,5 @@ export namespace UIStrings {
|
|
|
24
25
|
const missingSourceMapItemsWarningMesssage: string;
|
|
25
26
|
}
|
|
26
27
|
import { Audit } from "./audit.js";
|
|
28
|
+
import { EntityClassification } from "../computed/entity-classification.js";
|
|
27
29
|
//# sourceMappingURL=valid-source-maps.d.ts.map
|
|
@@ -4,8 +4,8 @@
|
|
|
4
4
|
* 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.
|
|
5
5
|
*/
|
|
6
6
|
|
|
7
|
-
import thirdPartyWeb from '../lib/third-party-web.js';
|
|
8
7
|
import {Audit} from './audit.js';
|
|
8
|
+
import {EntityClassification} from '../computed/entity-classification.js';
|
|
9
9
|
import * as i18n from '../lib/i18n/i18n.js';
|
|
10
10
|
|
|
11
11
|
const UIStrings = {
|
|
@@ -43,31 +43,33 @@ class ValidSourceMaps extends Audit {
|
|
|
43
43
|
title: str_(UIStrings.title),
|
|
44
44
|
failureTitle: str_(UIStrings.failureTitle),
|
|
45
45
|
description: str_(UIStrings.description),
|
|
46
|
-
requiredArtifacts: ['Scripts', 'SourceMaps', 'URL'],
|
|
46
|
+
requiredArtifacts: ['Scripts', 'SourceMaps', 'URL', 'devtoolsLogs'],
|
|
47
47
|
};
|
|
48
48
|
}
|
|
49
49
|
|
|
50
50
|
/**
|
|
51
51
|
* Returns true if the size of the script exceeds a static threshold.
|
|
52
52
|
* @param {LH.Artifacts.Script} script
|
|
53
|
-
* @param {
|
|
53
|
+
* @param {LH.Artifacts.EntityClassification} classifiedEntities
|
|
54
54
|
* @return {boolean}
|
|
55
55
|
*/
|
|
56
|
-
static isLargeFirstPartyJS(script,
|
|
56
|
+
static isLargeFirstPartyJS(script, classifiedEntities) {
|
|
57
57
|
if (!script.length) return false;
|
|
58
58
|
|
|
59
59
|
const isLargeJS = script.length >= LARGE_JS_BYTE_THRESHOLD;
|
|
60
|
-
const isFirstPartyJS = script.url ?
|
|
61
|
-
thirdPartyWeb.isFirstParty(script.url, thirdPartyWeb.getEntity(finalURL)) : false;
|
|
62
|
-
|
|
60
|
+
const isFirstPartyJS = script.url ? classifiedEntities.isFirstParty(script.url) : false;
|
|
63
61
|
return isLargeJS && isFirstPartyJS;
|
|
64
62
|
}
|
|
65
63
|
|
|
66
64
|
/**
|
|
67
65
|
* @param {LH.Artifacts} artifacts
|
|
66
|
+
* @param {LH.Audit.Context} context
|
|
68
67
|
*/
|
|
69
|
-
static async audit(artifacts) {
|
|
68
|
+
static async audit(artifacts, context) {
|
|
70
69
|
const {SourceMaps} = artifacts;
|
|
70
|
+
const devtoolsLog = artifacts.devtoolsLogs[Audit.DEFAULT_PASS];
|
|
71
|
+
const classifiedEntities = await EntityClassification.request(
|
|
72
|
+
{URL: artifacts.URL, devtoolsLog}, context);
|
|
71
73
|
|
|
72
74
|
/** @type {Set<string>} */
|
|
73
75
|
const isMissingMapForLargeFirstPartyScriptUrl = new Set();
|
|
@@ -77,7 +79,7 @@ class ValidSourceMaps extends Audit {
|
|
|
77
79
|
for (const script of artifacts.Scripts) {
|
|
78
80
|
const sourceMap = SourceMaps.find(m => m.scriptId === script.scriptId);
|
|
79
81
|
const errors = [];
|
|
80
|
-
const isLargeFirstParty = this.isLargeFirstPartyJS(script,
|
|
82
|
+
const isLargeFirstParty = this.isLargeFirstPartyJS(script, classifiedEntities);
|
|
81
83
|
|
|
82
84
|
if (isLargeFirstParty && (!sourceMap || !sourceMap.map)) {
|
|
83
85
|
missingMapsForLargeFirstPartyFile = true;
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
export { EntityClassificationComputed as EntityClassification };
|
|
2
|
+
export type EntityCache = Map<string, LH.Artifacts.Entity>;
|
|
3
|
+
declare const EntityClassificationComputed: typeof EntityClassification & {
|
|
4
|
+
request: (dependencies: {
|
|
5
|
+
URL: LH.Artifacts['URL'];
|
|
6
|
+
devtoolsLog: import("../index.js").DevtoolsLog;
|
|
7
|
+
}, context: import("../../types/utility-types.js").default.ImmutableObject<{
|
|
8
|
+
computedCache: Map<string, import("../lib/arbitrary-equality-map.js").ArbitraryEqualityMap>;
|
|
9
|
+
}>) => Promise<import("../index.js").Artifacts.EntityClassification>;
|
|
10
|
+
};
|
|
11
|
+
/** @typedef {Map<string, LH.Artifacts.Entity>} EntityCache */
|
|
12
|
+
declare class EntityClassification {
|
|
13
|
+
/**
|
|
14
|
+
* @param {EntityCache} entityCache
|
|
15
|
+
* @param {string} url
|
|
16
|
+
* @return {LH.Artifacts.Entity | undefined}
|
|
17
|
+
*/
|
|
18
|
+
static makeUpAnEntity(entityCache: EntityCache, url: string): LH.Artifacts.Entity | undefined;
|
|
19
|
+
/**
|
|
20
|
+
* @param {{URL: LH.Artifacts['URL'], devtoolsLog: LH.DevtoolsLog}} data
|
|
21
|
+
* @param {LH.Artifacts.ComputedContext} context
|
|
22
|
+
* @return {Promise<LH.Artifacts.EntityClassification>}
|
|
23
|
+
*/
|
|
24
|
+
static compute_(data: {
|
|
25
|
+
URL: LH.Artifacts['URL'];
|
|
26
|
+
devtoolsLog: import("../index.js").DevtoolsLog;
|
|
27
|
+
}, context: LH.Artifacts.ComputedContext): Promise<LH.Artifacts.EntityClassification>;
|
|
28
|
+
}
|
|
29
|
+
//# sourceMappingURL=entity-classification.d.ts.map
|
|
@@ -0,0 +1,102 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @license Copyright 2022 The Lighthouse Authors. All Rights Reserved.
|
|
3
|
+
* 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
|
|
4
|
+
* 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.
|
|
5
|
+
*/
|
|
6
|
+
|
|
7
|
+
import {makeComputedArtifact} from './computed-artifact.js';
|
|
8
|
+
import {NetworkRecords} from './network-records.js';
|
|
9
|
+
import {Util} from '../../shared/util.js';
|
|
10
|
+
import UrlUtils from '../lib/url-utils.js';
|
|
11
|
+
import thirdPartyWeb from '../lib/third-party-web.js';
|
|
12
|
+
|
|
13
|
+
/** @typedef {Map<string, LH.Artifacts.Entity>} EntityCache */
|
|
14
|
+
|
|
15
|
+
class EntityClassification {
|
|
16
|
+
/**
|
|
17
|
+
* @param {EntityCache} entityCache
|
|
18
|
+
* @param {string} url
|
|
19
|
+
* @return {LH.Artifacts.Entity | undefined}
|
|
20
|
+
*/
|
|
21
|
+
static makeUpAnEntity(entityCache, url) {
|
|
22
|
+
if (!UrlUtils.isValid(url)) return;
|
|
23
|
+
// We can make up an entity only for those URLs with a valid domain attached.
|
|
24
|
+
// So we further restrict from allowed URLs to (http/https).
|
|
25
|
+
if (!Util.createOrReturnURL(url).protocol.startsWith('http')) return;
|
|
26
|
+
|
|
27
|
+
const rootDomain = Util.getRootDomain(url);
|
|
28
|
+
if (!rootDomain) return;
|
|
29
|
+
if (entityCache.has(rootDomain)) return entityCache.get(rootDomain);
|
|
30
|
+
|
|
31
|
+
const unrecognizedEntity = {
|
|
32
|
+
name: rootDomain,
|
|
33
|
+
company: rootDomain,
|
|
34
|
+
category: '',
|
|
35
|
+
categories: [],
|
|
36
|
+
domains: [rootDomain],
|
|
37
|
+
averageExecutionTime: 0,
|
|
38
|
+
totalExecutionTime: 0,
|
|
39
|
+
totalOccurrences: 0,
|
|
40
|
+
isUnrecognized: true,
|
|
41
|
+
};
|
|
42
|
+
entityCache.set(rootDomain, unrecognizedEntity);
|
|
43
|
+
return unrecognizedEntity;
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
/**
|
|
47
|
+
* @param {{URL: LH.Artifacts['URL'], devtoolsLog: LH.DevtoolsLog}} data
|
|
48
|
+
* @param {LH.Artifacts.ComputedContext} context
|
|
49
|
+
* @return {Promise<LH.Artifacts.EntityClassification>}
|
|
50
|
+
*/
|
|
51
|
+
static async compute_(data, context) {
|
|
52
|
+
const networkRecords = await NetworkRecords.request(data.devtoolsLog, context);
|
|
53
|
+
/** @type {EntityCache} */
|
|
54
|
+
const madeUpEntityCache = new Map();
|
|
55
|
+
/** @type {Map<string, LH.Artifacts.Entity>} */
|
|
56
|
+
const entityByUrl = new Map();
|
|
57
|
+
/** @type {Map<LH.Artifacts.Entity, Set<string>>} */
|
|
58
|
+
const urlsByEntity = new Map();
|
|
59
|
+
|
|
60
|
+
for (const record of networkRecords) {
|
|
61
|
+
const {url} = record;
|
|
62
|
+
if (entityByUrl.has(url)) continue;
|
|
63
|
+
|
|
64
|
+
const entity = thirdPartyWeb.getEntity(url) ||
|
|
65
|
+
EntityClassification.makeUpAnEntity(madeUpEntityCache, url);
|
|
66
|
+
if (!entity) continue;
|
|
67
|
+
|
|
68
|
+
const entityURLs = urlsByEntity.get(entity) || new Set();
|
|
69
|
+
entityURLs.add(url);
|
|
70
|
+
urlsByEntity.set(entity, entityURLs);
|
|
71
|
+
entityByUrl.set(url, entity);
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
// When available, first party identification will be done via
|
|
75
|
+
// `mainDocumentUrl` (for navigations), and falls back to `finalDisplayedUrl` (for timespan/snapshot).
|
|
76
|
+
// See https://github.com/GoogleChrome/lighthouse/issues/13706
|
|
77
|
+
const firstPartyUrl = data.URL.mainDocumentUrl || data.URL.finalDisplayedUrl;
|
|
78
|
+
const firstParty = thirdPartyWeb.getEntity(firstPartyUrl) ||
|
|
79
|
+
EntityClassification.makeUpAnEntity(madeUpEntityCache, firstPartyUrl);
|
|
80
|
+
|
|
81
|
+
/**
|
|
82
|
+
* Convenience function to check if a URL belongs to first party.
|
|
83
|
+
* @param {string} url
|
|
84
|
+
* @return {boolean}
|
|
85
|
+
*/
|
|
86
|
+
function isFirstParty(url) {
|
|
87
|
+
const entityUrl = entityByUrl.get(url);
|
|
88
|
+
if (!entityUrl) throw new Error('A url not in devtoolsLog was used for first-party check.');
|
|
89
|
+
return entityUrl === firstParty;
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
return {
|
|
93
|
+
entityByUrl,
|
|
94
|
+
urlsByEntity,
|
|
95
|
+
firstParty,
|
|
96
|
+
isFirstParty,
|
|
97
|
+
};
|
|
98
|
+
}
|
|
99
|
+
}
|
|
100
|
+
|
|
101
|
+
const EntityClassificationComputed = makeComputedArtifact(EntityClassification, null);
|
|
102
|
+
export {EntityClassificationComputed as EntityClassification};
|
|
@@ -87,8 +87,11 @@ class Responsiveness {
|
|
|
87
87
|
return evt.name === 'EventTiming' && evt.ph !== 'e';
|
|
88
88
|
});
|
|
89
89
|
|
|
90
|
-
|
|
91
|
-
|
|
90
|
+
// If trace is from < m103, the timestamps cannot be trusted, so we craft a fallback
|
|
91
|
+
// <m103 traces (bad) had a args.frame
|
|
92
|
+
// m103+ traces (good) have a args.data.frame (https://crrev.com/c/3632661)
|
|
93
|
+
// TODO(compat): remove FallbackTiming handling when we don't care about <m103
|
|
94
|
+
if (candidates.length && candidates.every(candidate => !candidate.args.data?.frame)) {
|
|
92
95
|
return {
|
|
93
96
|
name: 'FallbackTiming',
|
|
94
97
|
duration: responsivenessEvent.args.data.maxDuration,
|
|
@@ -468,7 +468,7 @@ class PageDependencyGraph {
|
|
|
468
468
|
* @return {URLArtifact}
|
|
469
469
|
*/
|
|
470
470
|
static getDocumentUrls(devtoolsLog, networkRecords, processedTrace) {
|
|
471
|
-
const mainFrameId = processedTrace.
|
|
471
|
+
const mainFrameId = processedTrace.mainFrameInfo.frameId;
|
|
472
472
|
|
|
473
473
|
/** @type {string|undefined} */
|
|
474
474
|
let requestedUrl;
|
|
@@ -24,9 +24,10 @@ declare class ResourceSummary {
|
|
|
24
24
|
* @param {Array<LH.Artifacts.NetworkRequest>} networkRecords
|
|
25
25
|
* @param {LH.Artifacts.URL} URLArtifact
|
|
26
26
|
* @param {LH.Util.ImmutableObject<LH.Budget[]|null>} budgets
|
|
27
|
+
* @param {LH.Artifacts.EntityClassification} classifiedEntities
|
|
27
28
|
* @return {Record<LH.Budget.ResourceType, ResourceEntry>}
|
|
28
29
|
*/
|
|
29
|
-
static summarize(networkRecords: Array<LH.Artifacts.NetworkRequest>, URLArtifact: LH.Artifacts.URL, budgets: LH.Util.ImmutableObject<LH.Budget[] | null
|
|
30
|
+
static summarize(networkRecords: Array<LH.Artifacts.NetworkRequest>, URLArtifact: LH.Artifacts.URL, budgets: LH.Util.ImmutableObject<LH.Budget[] | null>, classifiedEntities: LH.Artifacts.EntityClassification): Record<LH.Budget.ResourceType, ResourceEntry>;
|
|
30
31
|
/**
|
|
31
32
|
* @param {{URL: LH.Artifacts['URL'], devtoolsLog: LH.DevtoolsLog, budgets: LH.Util.ImmutableObject<LH.Budget[]|null>}} data
|
|
32
33
|
* @param {LH.Artifacts.ComputedContext} context
|
|
@@ -38,7 +39,8 @@ declare class ResourceSummary {
|
|
|
38
39
|
budgets: LH.Util.ImmutableObject<LH.Budget[] | null>;
|
|
39
40
|
}, context: LH.Artifacts.ComputedContext): Promise<Record<LH.Budget.ResourceType, ResourceEntry>>;
|
|
40
41
|
}
|
|
41
|
-
import { Util } from "
|
|
42
|
+
import { Util } from "../../shared/util.js";
|
|
42
43
|
import { Budget } from "../config/budget.js";
|
|
43
44
|
import { NetworkRequest } from "../lib/network-request.js";
|
|
45
|
+
import { EntityClassification } from "./entity-classification.js";
|
|
44
46
|
//# sourceMappingURL=resource-summary.d.ts.map
|
|
@@ -4,11 +4,12 @@
|
|
|
4
4
|
* 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.
|
|
5
5
|
*/
|
|
6
6
|
|
|
7
|
+
import {EntityClassification} from './entity-classification.js';
|
|
7
8
|
import {makeComputedArtifact} from './computed-artifact.js';
|
|
8
9
|
import {NetworkRecords} from './network-records.js';
|
|
9
10
|
import {NetworkRequest} from '../lib/network-request.js';
|
|
10
11
|
import {Budget} from '../config/budget.js';
|
|
11
|
-
import {Util} from '
|
|
12
|
+
import {Util} from '../../shared/util.js';
|
|
12
13
|
|
|
13
14
|
/** @typedef {{count: number, resourceSize: number, transferSize: number}} ResourceEntry */
|
|
14
15
|
|
|
@@ -35,9 +36,10 @@ class ResourceSummary {
|
|
|
35
36
|
* @param {Array<LH.Artifacts.NetworkRequest>} networkRecords
|
|
36
37
|
* @param {LH.Artifacts.URL} URLArtifact
|
|
37
38
|
* @param {LH.Util.ImmutableObject<LH.Budget[]|null>} budgets
|
|
39
|
+
* @param {LH.Artifacts.EntityClassification} classifiedEntities
|
|
38
40
|
* @return {Record<LH.Budget.ResourceType, ResourceEntry>}
|
|
39
41
|
*/
|
|
40
|
-
static summarize(networkRecords, URLArtifact, budgets) {
|
|
42
|
+
static summarize(networkRecords, URLArtifact, budgets, classifiedEntities) {
|
|
41
43
|
/** @type {Record<LH.Budget.ResourceType, ResourceEntry>} */
|
|
42
44
|
const resourceSummary = {
|
|
43
45
|
'stylesheet': {count: 0, resourceSize: 0, transferSize: 0},
|
|
@@ -56,8 +58,8 @@ class ResourceSummary {
|
|
|
56
58
|
if (budget?.options?.firstPartyHostnames) {
|
|
57
59
|
firstPartyHosts = budget.options.firstPartyHostnames;
|
|
58
60
|
} else {
|
|
59
|
-
|
|
60
|
-
|
|
61
|
+
firstPartyHosts = classifiedEntities.firstParty?.domains.map(domain => `*.${domain}`) ||
|
|
62
|
+
[`*.${Util.getRootDomain(URLArtifact.finalDisplayedUrl)}`];
|
|
61
63
|
}
|
|
62
64
|
|
|
63
65
|
networkRecords.filter(record => {
|
|
@@ -105,7 +107,8 @@ class ResourceSummary {
|
|
|
105
107
|
*/
|
|
106
108
|
static async compute_(data, context) {
|
|
107
109
|
const networkRecords = await NetworkRecords.request(data.devtoolsLog, context);
|
|
108
|
-
|
|
110
|
+
const classifiedEntities = await EntityClassification.request(data, context);
|
|
111
|
+
return ResourceSummary.summarize(networkRecords, data.URL, data.budgets, classifiedEntities);
|
|
109
112
|
}
|
|
110
113
|
}
|
|
111
114
|
|
|
@@ -61,10 +61,12 @@ async function runA11yChecks() {
|
|
|
61
61
|
'frame-focusable-content': {enabled: false},
|
|
62
62
|
'aria-roledescription': {enabled: false},
|
|
63
63
|
'scrollable-region-focusable': {enabled: false},
|
|
64
|
-
// TODO(paulirish): create audits and enable these
|
|
64
|
+
// TODO(paulirish): create audits and enable these 5.
|
|
65
65
|
'input-button-name': {enabled: false},
|
|
66
66
|
'role-img-alt': {enabled: false},
|
|
67
67
|
'select-name': {enabled: false},
|
|
68
|
+
'link-in-text-block': {enabled: false},
|
|
69
|
+
'frame-title-unique': {enabled: false},
|
|
68
70
|
},
|
|
69
71
|
});
|
|
70
72
|
|