lighthouse 11.7.0-dev.20240409 → 11.7.0-dev.20240411
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/cli-flags.js +3 -3
- package/cli/test/smokehouse/core-tests.js +0 -16
- package/cli/test/smokehouse/frontends/smokehouse-bin.js +2 -2
- package/core/audits/byte-efficiency/render-blocking-resources.js +25 -26
- package/core/audits/layout-shifts.js +1 -1
- package/core/computed/metrics/lantern-first-contentful-paint.js +3 -2
- package/core/computed/metrics/lantern-first-meaningful-paint.js +3 -2
- package/core/computed/metrics/lantern-interactive.js +3 -2
- package/core/computed/metrics/lantern-largest-contentful-paint.js +3 -2
- package/core/computed/metrics/lantern-max-potential-fid.js +3 -2
- package/core/computed/metrics/lantern-metric.d.ts +5 -0
- package/core/computed/metrics/lantern-metric.js +23 -1
- package/core/computed/metrics/lantern-speed-index.js +3 -2
- package/core/computed/navigation-insights.d.ts +36 -0
- package/core/computed/navigation-insights.js +35 -0
- package/core/computed/trace-engine-result.d.ts +16 -3
- package/core/computed/trace-engine-result.js +19 -14
- package/core/config/default-config.js +6 -51
- package/core/config/filters.js +0 -1
- package/core/gather/gatherers/root-causes.d.ts +2 -2
- package/core/gather/gatherers/root-causes.js +6 -5
- package/core/gather/gatherers/trace-elements.d.ts +2 -2
- package/core/gather/gatherers/trace-elements.js +2 -2
- package/core/lib/lantern/cpu-node.d.ts +7 -1
- package/core/lib/lantern/cpu-node.js +12 -2
- package/core/lib/lantern/lantern-error.d.ts +8 -0
- package/core/lib/lantern/lantern-error.js +9 -0
- package/core/lib/lantern/metrics/first-meaningful-paint.js +2 -4
- package/core/lib/lantern/metrics/interactive.js +1 -1
- package/core/lib/lantern/metrics/largest-contentful-paint.js +3 -3
- package/core/lib/lantern/network-node.js +28 -4
- package/core/lib/lantern/page-dependency-graph.js +14 -2
- package/core/lib/lantern/simulator/simulator.js +1 -1
- package/core/lib/lh-error.js +3 -3
- package/core/runner.js +0 -1
- package/dist/report/bundle.esm.js +11 -95
- package/dist/report/flow.js +16 -100
- package/dist/report/standalone.js +12 -96
- package/flow-report/src/help-dialog.tsx +0 -1
- package/flow-report/src/i18n/i18n.d.ts +0 -4
- package/flow-report/src/i18n/ui-strings.d.ts +0 -1
- package/flow-report/src/i18n/ui-strings.js +0 -2
- package/package.json +1 -1
- package/readme.md +2 -2
- package/report/assets/styles.css +1 -43
- package/report/assets/templates.html +0 -95
- package/report/renderer/components.d.ts +2 -2
- package/report/renderer/components.js +2 -103
- package/report/renderer/report-renderer.js +2 -12
- package/report/renderer/report-ui-features.js +1 -1
- package/report/renderer/report-utils.d.ts +0 -1
- package/report/renderer/report-utils.js +0 -3
- package/shared/localization/locales/ar-XB.json +0 -174
- package/shared/localization/locales/ar.json +0 -174
- package/shared/localization/locales/bg.json +0 -174
- package/shared/localization/locales/ca.json +0 -174
- package/shared/localization/locales/cs.json +0 -174
- package/shared/localization/locales/da.json +0 -174
- package/shared/localization/locales/de.json +0 -174
- package/shared/localization/locales/el.json +0 -174
- package/shared/localization/locales/en-GB.json +0 -174
- package/shared/localization/locales/en-US.json +0 -177
- package/shared/localization/locales/en-XA.json +0 -174
- package/shared/localization/locales/en-XL.json +0 -177
- package/shared/localization/locales/es-419.json +0 -174
- package/shared/localization/locales/es.json +0 -174
- package/shared/localization/locales/fi.json +0 -174
- package/shared/localization/locales/fil.json +0 -174
- package/shared/localization/locales/fr.json +0 -174
- package/shared/localization/locales/he.json +0 -174
- package/shared/localization/locales/hi.json +0 -174
- package/shared/localization/locales/hr.json +0 -174
- package/shared/localization/locales/hu.json +0 -174
- package/shared/localization/locales/id.json +0 -174
- package/shared/localization/locales/it.json +0 -174
- package/shared/localization/locales/ja.json +0 -174
- package/shared/localization/locales/ko.json +0 -174
- package/shared/localization/locales/lt.json +0 -174
- package/shared/localization/locales/lv.json +0 -174
- package/shared/localization/locales/nl.json +0 -174
- package/shared/localization/locales/no.json +0 -174
- package/shared/localization/locales/pl.json +0 -174
- package/shared/localization/locales/pt-PT.json +0 -174
- package/shared/localization/locales/pt.json +0 -174
- package/shared/localization/locales/ro.json +0 -174
- package/shared/localization/locales/ru.json +0 -174
- package/shared/localization/locales/sk.json +0 -174
- package/shared/localization/locales/sl.json +0 -174
- package/shared/localization/locales/sr-Latn.json +0 -174
- package/shared/localization/locales/sr.json +0 -174
- package/shared/localization/locales/sv.json +0 -174
- package/shared/localization/locales/ta.json +0 -174
- package/shared/localization/locales/te.json +0 -174
- package/shared/localization/locales/th.json +0 -174
- package/shared/localization/locales/tr.json +0 -174
- package/shared/localization/locales/uk.json +0 -174
- package/shared/localization/locales/vi.json +0 -174
- package/shared/localization/locales/zh-HK.json +0 -174
- package/shared/localization/locales/zh-TW.json +0 -174
- package/shared/localization/locales/zh.json +0 -174
- package/tsconfig.json +0 -1
- package/types/artifacts.d.ts +15 -90
- package/types/audit.d.ts +0 -10
- package/types/internal/smokehouse.d.ts +1 -1
- package/types/lhr/lhr.d.ts +0 -2
- package/core/audits/content-width.d.ts +0 -17
- package/core/audits/content-width.js +0 -76
- package/core/audits/installable-manifest.d.ts +0 -111
- package/core/audits/installable-manifest.js +0 -248
- package/core/audits/manual/pwa-cross-browser.d.ts +0 -12
- package/core/audits/manual/pwa-cross-browser.js +0 -40
- package/core/audits/manual/pwa-each-page-has-url.d.ts +0 -12
- package/core/audits/manual/pwa-each-page-has-url.js +0 -38
- package/core/audits/manual/pwa-page-transitions.d.ts +0 -12
- package/core/audits/manual/pwa-page-transitions.js +0 -38
- package/core/audits/maskable-icon.d.ts +0 -25
- package/core/audits/maskable-icon.js +0 -70
- package/core/audits/multi-check-audit.d.ts +0 -28
- package/core/audits/multi-check-audit.js +0 -82
- package/core/audits/splash-screen.d.ts +0 -37
- package/core/audits/splash-screen.js +0 -98
- package/core/audits/themed-omnibox.d.ts +0 -42
- package/core/audits/themed-omnibox.js +0 -102
- package/core/computed/manifest-values.d.ts +0 -24
- package/core/computed/manifest-values.js +0 -136
- package/core/gather/gatherers/dobetterweb/tags-blocking-first-paint.d.ts +0 -47
- package/core/gather/gatherers/dobetterweb/tags-blocking-first-paint.js +0 -233
- package/core/gather/gatherers/installability-errors.d.ts +0 -17
- package/core/gather/gatherers/installability-errors.js +0 -56
- package/core/gather/gatherers/web-app-manifest.d.ts +0 -32
- package/core/gather/gatherers/web-app-manifest.js +0 -106
- package/report/renderer/pwa-category-renderer.d.ts +0 -55
- package/report/renderer/pwa-category-renderer.js +0 -184
- package/third-party/chromium-synchronization/installability-errors-test.js +0 -79
|
@@ -90,15 +90,6 @@ const UIStrings = {
|
|
|
90
90
|
seoCrawlingGroupTitle: 'Crawling and Indexing',
|
|
91
91
|
/** Description of the navigation section within the Search Engine Optimization (SEO) category. Within this section are audits with descriptive titles that highlight ways to make a website accessible to search engine crawlers. */
|
|
92
92
|
seoCrawlingGroupDescription: 'To appear in search results, crawlers need access to your app.',
|
|
93
|
-
/** Title of the Progressive Web Application (PWA) category of audits. This is displayed at the top of a list of audits focused on topics related to whether or not a site is a progressive web app, e.g. responds offline, uses a service worker, is on https, etc. Also used as a label of a score gauge. */
|
|
94
|
-
pwaCategoryTitle: 'PWA',
|
|
95
|
-
/** Description of the Progressive Web Application (PWA) category. This is displayed at the top of a list of audits focused on topics related to whether or not a site is a progressive web app, e.g. responds offline, uses a service worker, is on https, etc. No character length limits. The last sentence starting with 'Learn' becomes link text to additional documentation. */
|
|
96
|
-
pwaCategoryDescription: 'These checks validate the aspects of a Progressive Web App. ' +
|
|
97
|
-
'[Learn what makes a good Progressive Web App](https://web.dev/articles/pwa-checklist).',
|
|
98
|
-
/** Description of the Progressive Web Application (PWA) manual checks category, containing a list of additional validators must be run by hand in order to check all PWA best practices. This is displayed at the top of a list of manually run audits focused on topics related to whether or not a site is a progressive web app, e.g. responds offline, uses a service worker, is on https, etc.. No character length limits. */
|
|
99
|
-
pwaCategoryManualDescription: 'These checks are required by the baseline ' +
|
|
100
|
-
'[PWA Checklist](https://web.dev/articles/pwa-checklist) but are ' +
|
|
101
|
-
'not automatically checked by Lighthouse. They do not affect your score but it\'s important that you verify them manually.',
|
|
102
93
|
/** Title of the Best Practices category of audits. This is displayed at the top of a list of audits focused on topics related to following web development best practices and accepted guidelines. Also used as a label of a score gauge; try to limit to 20 characters. */
|
|
103
94
|
bestPracticesCategoryTitle: 'Best Practices',
|
|
104
95
|
/** Title of the Trust & Safety group of audits. This is displayed at the top of a list of audits focused on maintaining user trust and protecting security in web development. */
|
|
@@ -109,10 +100,6 @@ const UIStrings = {
|
|
|
109
100
|
bestPracticesBrowserCompatGroupTitle: 'Browser Compatibility',
|
|
110
101
|
/** Title of the General group of the Best Practices category. Within this section are the audits that don't belong to a specific group but are of general interest. */
|
|
111
102
|
bestPracticesGeneralGroupTitle: 'General',
|
|
112
|
-
/** Title of the Installable section of the web app category. Within this section are audits that check if Chrome supports installing the web site as an app on their device. */
|
|
113
|
-
pwaInstallableGroupTitle: 'Installable',
|
|
114
|
-
/** Title of the "PWA Optimized" section of the web app category. Within this section are audits that check if the developer has taken advantage of features to make their web page more enjoyable and engaging for the user. */
|
|
115
|
-
pwaOptimizedGroupTitle: 'PWA Optimized',
|
|
116
103
|
};
|
|
117
104
|
|
|
118
105
|
const str_ = i18n.createIcuMessageFn(import.meta.url, UIStrings);
|
|
@@ -137,7 +124,6 @@ const defaultConfig = {
|
|
|
137
124
|
{id: 'Inputs', gatherer: 'inputs'},
|
|
138
125
|
{id: 'IFrameElements', gatherer: 'iframe-elements'},
|
|
139
126
|
{id: 'ImageElements', gatherer: 'image-elements'},
|
|
140
|
-
{id: 'InstallabilityErrors', gatherer: 'installability-errors'},
|
|
141
127
|
{id: 'InspectorIssues', gatherer: 'inspector-issues'},
|
|
142
128
|
{id: 'JsUsage', gatherer: 'js-usage'},
|
|
143
129
|
{id: 'LinkElements', gatherer: 'link-elements'},
|
|
@@ -151,10 +137,8 @@ const defaultConfig = {
|
|
|
151
137
|
{id: 'Scripts', gatherer: 'scripts'},
|
|
152
138
|
{id: 'SourceMaps', gatherer: 'source-maps'},
|
|
153
139
|
{id: 'Stacks', gatherer: 'stacks'},
|
|
154
|
-
{id: 'TagsBlockingFirstPaint', gatherer: 'dobetterweb/tags-blocking-first-paint'},
|
|
155
140
|
{id: 'TraceElements', gatherer: 'trace-elements'},
|
|
156
141
|
{id: 'ViewportDimensions', gatherer: 'viewport-dimensions'},
|
|
157
|
-
{id: 'WebAppManifest', gatherer: 'web-app-manifest'},
|
|
158
142
|
|
|
159
143
|
// Artifact copies are renamed for compatibility with legacy artifacts.
|
|
160
144
|
{id: 'devtoolsLogs', gatherer: 'devtools-log-compat'},
|
|
@@ -186,11 +170,6 @@ const defaultConfig = {
|
|
|
186
170
|
'user-timings',
|
|
187
171
|
'critical-request-chains',
|
|
188
172
|
'redirects',
|
|
189
|
-
'installable-manifest',
|
|
190
|
-
'splash-screen',
|
|
191
|
-
'themed-omnibox',
|
|
192
|
-
'maskable-icon',
|
|
193
|
-
'content-width',
|
|
194
173
|
'image-aspect-ratio',
|
|
195
174
|
'image-size-responsive',
|
|
196
175
|
'deprecations',
|
|
@@ -220,9 +199,6 @@ const defaultConfig = {
|
|
|
220
199
|
'prioritize-lcp-image',
|
|
221
200
|
'csp-xss',
|
|
222
201
|
'script-treemap-data',
|
|
223
|
-
'manual/pwa-cross-browser',
|
|
224
|
-
'manual/pwa-page-transitions',
|
|
225
|
-
'manual/pwa-each-page-has-url',
|
|
226
202
|
'accessibility/accesskeys',
|
|
227
203
|
'accessibility/aria-allowed-attr',
|
|
228
204
|
'accessibility/aria-allowed-role',
|
|
@@ -345,12 +321,6 @@ const defaultConfig = {
|
|
|
345
321
|
title: str_(UIStrings.diagnosticsGroupTitle),
|
|
346
322
|
description: str_(UIStrings.diagnosticsGroupDescription),
|
|
347
323
|
},
|
|
348
|
-
'pwa-installable': {
|
|
349
|
-
title: str_(UIStrings.pwaInstallableGroupTitle),
|
|
350
|
-
},
|
|
351
|
-
'pwa-optimized': {
|
|
352
|
-
title: str_(UIStrings.pwaOptimizedGroupTitle),
|
|
353
|
-
},
|
|
354
324
|
'a11y-best-practices': {
|
|
355
325
|
title: str_(UIStrings.a11yBestPracticesGroupTitle),
|
|
356
326
|
description: str_(UIStrings.a11yBestPracticesGroupDescription),
|
|
@@ -603,12 +573,17 @@ const defaultConfig = {
|
|
|
603
573
|
manualDescription: str_(UIStrings.seoCategoryManualDescription),
|
|
604
574
|
supportedModes: ['navigation', 'snapshot'],
|
|
605
575
|
auditRefs: [
|
|
576
|
+
// Should be at least 31% of the score, such that this audit failing
|
|
577
|
+
// results in the SEO category failing.
|
|
578
|
+
// Solve for w:
|
|
579
|
+
// w / (w + T) >= 0.31
|
|
580
|
+
// where T is the sum of all the other weights.
|
|
581
|
+
{id: 'is-crawlable', weight: 93 / 23, group: 'seo-crawl'},
|
|
606
582
|
{id: 'document-title', weight: 1, group: 'seo-content'},
|
|
607
583
|
{id: 'meta-description', weight: 1, group: 'seo-content'},
|
|
608
584
|
{id: 'http-status-code', weight: 1, group: 'seo-crawl'},
|
|
609
585
|
{id: 'link-text', weight: 1, group: 'seo-content'},
|
|
610
586
|
{id: 'crawlable-anchors', weight: 1, group: 'seo-crawl'},
|
|
611
|
-
{id: 'is-crawlable', weight: 1, group: 'seo-crawl'},
|
|
612
587
|
{id: 'robots-txt', weight: 1, group: 'seo-crawl'},
|
|
613
588
|
{id: 'image-alt', weight: 1, group: 'seo-content'},
|
|
614
589
|
{id: 'hreflang', weight: 1, group: 'seo-content'},
|
|
@@ -617,26 +592,6 @@ const defaultConfig = {
|
|
|
617
592
|
{id: 'structured-data', weight: 0},
|
|
618
593
|
],
|
|
619
594
|
},
|
|
620
|
-
'pwa': {
|
|
621
|
-
title: str_(UIStrings.pwaCategoryTitle),
|
|
622
|
-
description: str_(UIStrings.pwaCategoryDescription),
|
|
623
|
-
manualDescription: str_(UIStrings.pwaCategoryManualDescription),
|
|
624
|
-
supportedModes: ['navigation'],
|
|
625
|
-
auditRefs: [
|
|
626
|
-
// Installable
|
|
627
|
-
{id: 'installable-manifest', weight: 2, group: 'pwa-installable'},
|
|
628
|
-
// PWA Optimized
|
|
629
|
-
{id: 'splash-screen', weight: 1, group: 'pwa-optimized'},
|
|
630
|
-
{id: 'themed-omnibox', weight: 1, group: 'pwa-optimized'},
|
|
631
|
-
{id: 'content-width', weight: 1, group: 'pwa-optimized'},
|
|
632
|
-
{id: 'viewport', weight: 2, group: 'pwa-optimized'},
|
|
633
|
-
{id: 'maskable-icon', weight: 1, group: 'pwa-optimized'},
|
|
634
|
-
// Manual audits
|
|
635
|
-
{id: 'pwa-cross-browser', weight: 0},
|
|
636
|
-
{id: 'pwa-page-transitions', weight: 0},
|
|
637
|
-
{id: 'pwa-each-page-has-url', weight: 0},
|
|
638
|
-
],
|
|
639
|
-
},
|
|
640
595
|
},
|
|
641
596
|
};
|
|
642
597
|
|
package/core/config/filters.js
CHANGED
|
@@ -3,10 +3,10 @@ declare class RootCauses extends BaseGatherer {
|
|
|
3
3
|
static symbol: symbol;
|
|
4
4
|
/**
|
|
5
5
|
* @param {LH.Gatherer.Driver} driver
|
|
6
|
-
* @param {LH.Artifacts.TraceEngineResult}
|
|
6
|
+
* @param {LH.Artifacts.TraceEngineResult['data']} traceParsedData
|
|
7
7
|
* @return {Promise<LH.Artifacts.TraceEngineRootCauses>}
|
|
8
8
|
*/
|
|
9
|
-
static runRootCauseAnalysis(driver: LH.Gatherer.Driver,
|
|
9
|
+
static runRootCauseAnalysis(driver: LH.Gatherer.Driver, traceParsedData: LH.Artifacts.TraceEngineResult['data']): Promise<LH.Artifacts.TraceEngineRootCauses>;
|
|
10
10
|
/** @type {LH.Gatherer.GathererMeta<'Trace'>} */
|
|
11
11
|
meta: LH.Gatherer.GathererMeta<'Trace'>;
|
|
12
12
|
/**
|
|
@@ -21,10 +21,10 @@ class RootCauses extends BaseGatherer {
|
|
|
21
21
|
|
|
22
22
|
/**
|
|
23
23
|
* @param {LH.Gatherer.Driver} driver
|
|
24
|
-
* @param {LH.Artifacts.TraceEngineResult}
|
|
24
|
+
* @param {LH.Artifacts.TraceEngineResult['data']} traceParsedData
|
|
25
25
|
* @return {Promise<LH.Artifacts.TraceEngineRootCauses>}
|
|
26
26
|
*/
|
|
27
|
-
static async runRootCauseAnalysis(driver,
|
|
27
|
+
static async runRootCauseAnalysis(driver, traceParsedData) {
|
|
28
28
|
await driver.defaultSession.sendCommand('DOM.enable');
|
|
29
29
|
await driver.defaultSession.sendCommand('CSS.enable');
|
|
30
30
|
|
|
@@ -112,9 +112,10 @@ class RootCauses extends BaseGatherer {
|
|
|
112
112
|
layoutShifts: {},
|
|
113
113
|
};
|
|
114
114
|
const rootCausesEngine = new TraceEngine.RootCauses(protocolInterface);
|
|
115
|
-
const layoutShiftEvents =
|
|
115
|
+
const layoutShiftEvents = traceParsedData.LayoutShifts.clusters.flatMap(c => c.events);
|
|
116
116
|
for (const event of layoutShiftEvents) {
|
|
117
|
-
|
|
117
|
+
// @ts-expect-error The data we do get in the trace processor is still enough here
|
|
118
|
+
const r = await rootCausesEngine.layoutShifts.rootCausesForEvent(traceParsedData, event);
|
|
118
119
|
if (!r) continue;
|
|
119
120
|
|
|
120
121
|
for (const cause of r.fontChanges) {
|
|
@@ -137,7 +138,7 @@ class RootCauses extends BaseGatherer {
|
|
|
137
138
|
async getArtifact(context) {
|
|
138
139
|
const trace = context.dependencies.Trace;
|
|
139
140
|
const traceEngineResult = await TraceEngineResult.request({trace}, context);
|
|
140
|
-
return RootCauses.runRootCauseAnalysis(context.driver, traceEngineResult);
|
|
141
|
+
return RootCauses.runRootCauseAnalysis(context.driver, traceEngineResult.data);
|
|
141
142
|
}
|
|
142
143
|
}
|
|
143
144
|
|
|
@@ -25,12 +25,12 @@ declare class TraceElements extends BaseGatherer {
|
|
|
25
25
|
* that may have caused the shift.
|
|
26
26
|
*
|
|
27
27
|
* @param {LH.Trace} trace
|
|
28
|
-
* @param {LH.Artifacts.TraceEngineResult} traceEngineResult
|
|
28
|
+
* @param {LH.Artifacts.TraceEngineResult['data']} traceEngineResult
|
|
29
29
|
* @param {LH.Artifacts.TraceEngineRootCauses} rootCauses
|
|
30
30
|
* @param {LH.Gatherer.Context} context
|
|
31
31
|
* @return {Promise<Array<{nodeId: number}>>}
|
|
32
32
|
*/
|
|
33
|
-
static getTopLayoutShifts(trace: LH.Trace, traceEngineResult: LH.Artifacts.TraceEngineResult, rootCauses: LH.Artifacts.TraceEngineRootCauses, context: LH.Gatherer.Context): Promise<Array<{
|
|
33
|
+
static getTopLayoutShifts(trace: LH.Trace, traceEngineResult: LH.Artifacts.TraceEngineResult['data'], rootCauses: LH.Artifacts.TraceEngineRootCauses, context: LH.Gatherer.Context): Promise<Array<{
|
|
34
34
|
nodeId: number;
|
|
35
35
|
}>>;
|
|
36
36
|
/**
|
|
@@ -122,7 +122,7 @@ class TraceElements extends BaseGatherer {
|
|
|
122
122
|
* that may have caused the shift.
|
|
123
123
|
*
|
|
124
124
|
* @param {LH.Trace} trace
|
|
125
|
-
* @param {LH.Artifacts.TraceEngineResult} traceEngineResult
|
|
125
|
+
* @param {LH.Artifacts.TraceEngineResult['data']} traceEngineResult
|
|
126
126
|
* @param {LH.Artifacts.TraceEngineRootCauses} rootCauses
|
|
127
127
|
* @param {LH.Gatherer.Context} context
|
|
128
128
|
* @return {Promise<Array<{nodeId: number}>>}
|
|
@@ -322,7 +322,7 @@ class TraceElements extends BaseGatherer {
|
|
|
322
322
|
|
|
323
323
|
const lcpNodeData = await TraceElements.getLcpElement(trace, context);
|
|
324
324
|
const shiftsData = await TraceElements.getTopLayoutShifts(
|
|
325
|
-
trace, traceEngineResult, rootCauses, context);
|
|
325
|
+
trace, traceEngineResult.data, rootCauses, context);
|
|
326
326
|
const animatedElementData = await this.getAnimatedElements(mainThreadEvents);
|
|
327
327
|
const responsivenessElementData = await TraceElements.getResponsivenessElement(trace, context);
|
|
328
328
|
|
|
@@ -6,11 +6,17 @@ export class CPUNode<T = any> extends BaseNode<T> {
|
|
|
6
6
|
/**
|
|
7
7
|
* @param {LH.TraceEvent} parentEvent
|
|
8
8
|
* @param {LH.TraceEvent[]=} childEvents
|
|
9
|
+
* @param {number=} correctedEndTs
|
|
9
10
|
*/
|
|
10
|
-
constructor(parentEvent: LH.TraceEvent, childEvents?: LH.TraceEvent[] | undefined);
|
|
11
|
+
constructor(parentEvent: LH.TraceEvent, childEvents?: LH.TraceEvent[] | undefined, correctedEndTs?: number | undefined);
|
|
11
12
|
_event: LH.TraceEvent;
|
|
12
13
|
_childEvents: LH.TraceEvent[];
|
|
14
|
+
_correctedEndTs: number | undefined;
|
|
13
15
|
get type(): "cpu";
|
|
16
|
+
/**
|
|
17
|
+
* @return {number}
|
|
18
|
+
*/
|
|
19
|
+
get duration(): number;
|
|
14
20
|
/**
|
|
15
21
|
* @return {LH.TraceEvent}
|
|
16
22
|
*/
|
|
@@ -15,13 +15,15 @@ class CPUNode extends BaseNode {
|
|
|
15
15
|
/**
|
|
16
16
|
* @param {LH.TraceEvent} parentEvent
|
|
17
17
|
* @param {LH.TraceEvent[]=} childEvents
|
|
18
|
+
* @param {number=} correctedEndTs
|
|
18
19
|
*/
|
|
19
|
-
constructor(parentEvent, childEvents = []) {
|
|
20
|
+
constructor(parentEvent, childEvents = [], correctedEndTs) {
|
|
20
21
|
const nodeId = `${parentEvent.tid}.${parentEvent.ts}`;
|
|
21
22
|
super(nodeId);
|
|
22
23
|
|
|
23
24
|
this._event = parentEvent;
|
|
24
25
|
this._childEvents = childEvents;
|
|
26
|
+
this._correctedEndTs = correctedEndTs;
|
|
25
27
|
}
|
|
26
28
|
|
|
27
29
|
get type() {
|
|
@@ -39,9 +41,17 @@ class CPUNode extends BaseNode {
|
|
|
39
41
|
* @return {number}
|
|
40
42
|
*/
|
|
41
43
|
get endTime() {
|
|
44
|
+
if (this._correctedEndTs) return this._correctedEndTs;
|
|
42
45
|
return this._event.ts + this._event.dur;
|
|
43
46
|
}
|
|
44
47
|
|
|
48
|
+
/**
|
|
49
|
+
* @return {number}
|
|
50
|
+
*/
|
|
51
|
+
get duration() {
|
|
52
|
+
return this.endTime - this.startTime;
|
|
53
|
+
}
|
|
54
|
+
|
|
45
55
|
/**
|
|
46
56
|
* @return {LH.TraceEvent}
|
|
47
57
|
*/
|
|
@@ -83,7 +93,7 @@ class CPUNode extends BaseNode {
|
|
|
83
93
|
* @return {CPUNode}
|
|
84
94
|
*/
|
|
85
95
|
cloneWithoutRelationships() {
|
|
86
|
-
return new CPUNode(this._event, this._childEvents);
|
|
96
|
+
return new CPUNode(this._event, this._childEvents, this._correctedEndTs);
|
|
87
97
|
}
|
|
88
98
|
}
|
|
89
99
|
|
|
@@ -6,8 +6,6 @@
|
|
|
6
6
|
|
|
7
7
|
import * as Lantern from '../types/lantern.js';
|
|
8
8
|
import {Metric} from '../metric.js';
|
|
9
|
-
// TODO(15841): don't use LighthouseError
|
|
10
|
-
import {LighthouseError} from '../../lh-error.js';
|
|
11
9
|
import {FirstContentfulPaint} from './first-contentful-paint.js';
|
|
12
10
|
|
|
13
11
|
/** @typedef {import('../base-node.js').Node} Node */
|
|
@@ -32,7 +30,7 @@ class FirstMeaningfulPaint extends Metric {
|
|
|
32
30
|
static getOptimisticGraph(dependencyGraph, processedNavigation) {
|
|
33
31
|
const fmp = processedNavigation.timestamps.firstMeaningfulPaint;
|
|
34
32
|
if (!fmp) {
|
|
35
|
-
throw new
|
|
33
|
+
throw new Error('NO_FMP');
|
|
36
34
|
}
|
|
37
35
|
return FirstContentfulPaint.getFirstPaintBasedGraph(dependencyGraph, {
|
|
38
36
|
cutoffTimestamp: fmp,
|
|
@@ -51,7 +49,7 @@ class FirstMeaningfulPaint extends Metric {
|
|
|
51
49
|
static getPessimisticGraph(dependencyGraph, processedNavigation) {
|
|
52
50
|
const fmp = processedNavigation.timestamps.firstMeaningfulPaint;
|
|
53
51
|
if (!fmp) {
|
|
54
|
-
throw new
|
|
52
|
+
throw new Error('NO_FMP');
|
|
55
53
|
}
|
|
56
54
|
|
|
57
55
|
return FirstContentfulPaint.getFirstPaintBasedGraph(dependencyGraph, {
|
|
@@ -37,7 +37,7 @@ class Interactive extends Metric {
|
|
|
37
37
|
return dependencyGraph.cloneWithRelationships(node => {
|
|
38
38
|
// Include everything that might be a long task
|
|
39
39
|
if (node.type === BaseNode.TYPES.CPU) {
|
|
40
|
-
return node.
|
|
40
|
+
return node.duration > minimumCpuTaskDuration;
|
|
41
41
|
}
|
|
42
42
|
|
|
43
43
|
// Include all scripts and high priority requests, exclude all images
|
|
@@ -6,8 +6,8 @@
|
|
|
6
6
|
|
|
7
7
|
import * as Lantern from '../types/lantern.js';
|
|
8
8
|
import {Metric} from '../metric.js';
|
|
9
|
-
import {LighthouseError} from '../../../lib/lh-error.js';
|
|
10
9
|
import {FirstContentfulPaint} from './first-contentful-paint.js';
|
|
10
|
+
import {LanternError} from '../lantern-error.js';
|
|
11
11
|
|
|
12
12
|
/** @typedef {import('../base-node.js').Node} Node */
|
|
13
13
|
|
|
@@ -45,7 +45,7 @@ class LargestContentfulPaint extends Metric {
|
|
|
45
45
|
static getOptimisticGraph(dependencyGraph, processedNavigation) {
|
|
46
46
|
const lcp = processedNavigation.timestamps.largestContentfulPaint;
|
|
47
47
|
if (!lcp) {
|
|
48
|
-
throw new
|
|
48
|
+
throw new LanternError('NO_LCP');
|
|
49
49
|
}
|
|
50
50
|
|
|
51
51
|
return FirstContentfulPaint.getFirstPaintBasedGraph(dependencyGraph, {
|
|
@@ -62,7 +62,7 @@ class LargestContentfulPaint extends Metric {
|
|
|
62
62
|
static getPessimisticGraph(dependencyGraph, processedNavigation) {
|
|
63
63
|
const lcp = processedNavigation.timestamps.largestContentfulPaint;
|
|
64
64
|
if (!lcp) {
|
|
65
|
-
throw new
|
|
65
|
+
throw new LanternError('NO_LCP');
|
|
66
66
|
}
|
|
67
67
|
|
|
68
68
|
return FirstContentfulPaint.getFirstPaintBasedGraph(dependencyGraph, {
|
|
@@ -7,8 +7,32 @@
|
|
|
7
7
|
import * as Lantern from './types/lantern.js';
|
|
8
8
|
import {NetworkRequestTypes} from './lantern.js';
|
|
9
9
|
import {BaseNode} from './base-node.js';
|
|
10
|
-
|
|
11
|
-
|
|
10
|
+
|
|
11
|
+
const NON_NETWORK_SCHEMES = [
|
|
12
|
+
'blob', // @see https://developer.mozilla.org/en-US/docs/Web/API/URL/createObjectURL
|
|
13
|
+
'data', // @see https://developer.mozilla.org/en-US/docs/Web/HTTP/Basics_of_HTTP/Data_URIs
|
|
14
|
+
'intent', // @see https://developer.chrome.com/docs/multidevice/android/intents/
|
|
15
|
+
'file', // @see https://en.wikipedia.org/wiki/File_URI_scheme
|
|
16
|
+
'filesystem', // @see https://developer.mozilla.org/en-US/docs/Web/API/FileSystem
|
|
17
|
+
'chrome-extension',
|
|
18
|
+
];
|
|
19
|
+
|
|
20
|
+
/**
|
|
21
|
+
* Use `NetworkRequest.isNonNetworkRequest(req)` if working with a request.
|
|
22
|
+
* Note: the `protocol` field from CDP can be 'h2', 'http', (not 'https'!) or it'll be url's scheme.
|
|
23
|
+
* https://source.chromium.org/chromium/chromium/src/+/main:content/browser/devtools/protocol/network_handler.cc;l=598-611;drc=56d4a9a9deb30be73adcee8737c73bcb2a5ab64f
|
|
24
|
+
* However, a `new URL(href).protocol` has a colon suffix.
|
|
25
|
+
* https://url.spec.whatwg.org/#dom-url-protocol
|
|
26
|
+
* A URL's `scheme` is specced as the `protocol` sans-colon, but isn't exposed on a URL object.
|
|
27
|
+
* This method can take all 3 of these string types as a parameter.
|
|
28
|
+
* @param {string} protocol Either a networkRequest's `protocol` per CDP or a `new URL(href).protocol`
|
|
29
|
+
* @return {boolean}
|
|
30
|
+
*/
|
|
31
|
+
function isNonNetworkProtocol(protocol) {
|
|
32
|
+
// Strip off any colon
|
|
33
|
+
const urlScheme = protocol.includes(':') ? protocol.slice(0, protocol.indexOf(':')) : protocol;
|
|
34
|
+
return NON_NETWORK_SCHEMES.includes(urlScheme);
|
|
35
|
+
}
|
|
12
36
|
|
|
13
37
|
/**
|
|
14
38
|
* @template [T=any]
|
|
@@ -75,9 +99,9 @@ class NetworkNode extends BaseNode {
|
|
|
75
99
|
*/
|
|
76
100
|
get isNonNetworkProtocol() {
|
|
77
101
|
// The 'protocol' field in devtools a string more like a `scheme`
|
|
78
|
-
return
|
|
102
|
+
return isNonNetworkProtocol(this.request.protocol) ||
|
|
79
103
|
// But `protocol` can fail to be populated if the request fails, so fallback to scheme.
|
|
80
|
-
|
|
104
|
+
isNonNetworkProtocol(this.request.parsedURL.scheme);
|
|
81
105
|
}
|
|
82
106
|
|
|
83
107
|
/**
|
|
@@ -128,6 +128,9 @@ class PageDependencyGraph {
|
|
|
128
128
|
continue;
|
|
129
129
|
}
|
|
130
130
|
|
|
131
|
+
/** @type {number|undefined} */
|
|
132
|
+
let correctedEndTs = undefined;
|
|
133
|
+
|
|
131
134
|
// Capture all events that occurred within the task
|
|
132
135
|
/** @type {Array<LH.TraceEvent>} */
|
|
133
136
|
const children = [];
|
|
@@ -136,10 +139,19 @@ class PageDependencyGraph {
|
|
|
136
139
|
i < mainThreadEvents.length && mainThreadEvents[i].ts < endTime;
|
|
137
140
|
i++
|
|
138
141
|
) {
|
|
142
|
+
// Temporary fix for a Chrome bug where some RunTask events can be overlapping.
|
|
143
|
+
// We correct that here be ensuring each RunTask ends at least 1 microsecond before the next
|
|
144
|
+
// https://github.com/GoogleChrome/lighthouse/issues/15896
|
|
145
|
+
// https://issues.chromium.org/issues/329678173
|
|
146
|
+
if (TraceProcessor.isScheduleableTask(mainThreadEvents[i]) && mainThreadEvents[i].dur) {
|
|
147
|
+
correctedEndTs = mainThreadEvents[i].ts - 1;
|
|
148
|
+
break;
|
|
149
|
+
}
|
|
150
|
+
|
|
139
151
|
children.push(mainThreadEvents[i]);
|
|
140
152
|
}
|
|
141
153
|
|
|
142
|
-
nodes.push(new CPUNode(evt, children));
|
|
154
|
+
nodes.push(new CPUNode(evt, children, correctedEndTs));
|
|
143
155
|
}
|
|
144
156
|
|
|
145
157
|
return nodes;
|
|
@@ -359,7 +371,7 @@ class PageDependencyGraph {
|
|
|
359
371
|
isFirst = foundFirstParse = true;
|
|
360
372
|
}
|
|
361
373
|
|
|
362
|
-
if (isFirst || node.
|
|
374
|
+
if (isFirst || node.duration >= minimumEvtDur) {
|
|
363
375
|
// Don't prune this node. The task is long / important so it will impact simulation.
|
|
364
376
|
continue;
|
|
365
377
|
}
|
|
@@ -276,7 +276,7 @@ class Simulator {
|
|
|
276
276
|
? this._layoutTaskMultiplier
|
|
277
277
|
: this._cpuSlowdownMultiplier;
|
|
278
278
|
const totalDuration = Math.min(
|
|
279
|
-
Math.round(cpuNode.
|
|
279
|
+
Math.round(cpuNode.duration / 1000 * multiplier),
|
|
280
280
|
DEFAULT_MAXIMUM_CPU_TASK_DURATION
|
|
281
281
|
);
|
|
282
282
|
const estimatedTimeElapsed = totalDuration - timingData.timeElapsed;
|
package/core/lib/lh-error.js
CHANGED
|
@@ -76,13 +76,13 @@ const UIStrings = {
|
|
|
76
76
|
criTimeout: 'Timeout waiting for initial Debugger Protocol connection.',
|
|
77
77
|
/**
|
|
78
78
|
* @description Error message explaining that a resource that was required for testing was never collected. "artifactName" will be replaced with the name of the resource that wasn't collected.
|
|
79
|
-
* @example {
|
|
79
|
+
* @example {MainDocumentContent} artifactName
|
|
80
80
|
* */
|
|
81
81
|
missingRequiredArtifact: 'Required {artifactName} gatherer did not run.',
|
|
82
82
|
/**
|
|
83
83
|
* @description Error message explaining that there was an error while trying to collect a resource that was required for testing. "artifactName" will be replaced with the name of the resource that wasn't collected; "errorMessage" will be replaced with a string description of the error that occurred.
|
|
84
|
-
* @example {
|
|
85
|
-
* @example {
|
|
84
|
+
* @example {MainDocumentContent} artifactName
|
|
85
|
+
* @example {Could not find main document} errorMessage
|
|
86
86
|
* */
|
|
87
87
|
erroredRequiredArtifact: 'Required {artifactName} gatherer encountered an error: {errorMessage}',
|
|
88
88
|
|
package/core/runner.js
CHANGED
|
@@ -106,7 +106,6 @@ class Runner {
|
|
|
106
106
|
networkUserAgent: artifacts.NetworkUserAgent,
|
|
107
107
|
hostUserAgent: artifacts.HostUserAgent,
|
|
108
108
|
benchmarkIndex: artifacts.BenchmarkIndex,
|
|
109
|
-
benchmarkIndexes: artifacts.BenchmarkIndexes,
|
|
110
109
|
credits,
|
|
111
110
|
},
|
|
112
111
|
audits: auditResultsById,
|