lighthouse 11.7.0 → 12.0.0-dev.20240422
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/CONTRIBUTING.md +2 -2
- package/cli/bin.js +0 -7
- package/cli/cli-flags.d.ts +1 -5
- package/cli/cli-flags.js +4 -8
- package/cli/test/smokehouse/__snapshots__/report-assert-test.js.snap +14 -14
- package/cli/test/smokehouse/config/exclusions.js +3 -0
- package/cli/test/smokehouse/core-tests.js +6 -20
- package/cli/test/smokehouse/frontends/smokehouse-bin.js +2 -2
- package/core/audits/accessibility/accesskeys.js +1 -1
- package/core/audits/accessibility/aria-allowed-attr.js +1 -1
- package/core/audits/accessibility/aria-allowed-role.js +1 -1
- package/core/audits/accessibility/aria-command-name.js +1 -1
- package/core/audits/accessibility/aria-conditional-attr.d.ts +10 -0
- package/core/audits/accessibility/aria-conditional-attr.js +43 -0
- package/core/audits/accessibility/{duplicate-id-active.d.ts → aria-deprecated-role.d.ts} +3 -3
- package/core/audits/accessibility/aria-deprecated-role.js +43 -0
- package/core/audits/accessibility/aria-dialog-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-prohibited-attr.d.ts +10 -0
- package/core/audits/accessibility/aria-prohibited-attr.js +44 -0
- 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-text.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-aria.js +1 -1
- package/core/audits/accessibility/empty-heading.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/html-xml-lang-mismatch.js +1 -1
- package/core/audits/accessibility/identical-links-same-purpose.js +1 -1
- package/core/audits/accessibility/image-alt.js +1 -1
- package/core/audits/accessibility/image-redundant-alt.js +1 -1
- package/core/audits/accessibility/input-button-name.js +1 -1
- package/core/audits/accessibility/input-image-alt.js +1 -1
- package/core/audits/accessibility/label-content-name-mismatch.js +1 -1
- package/core/audits/accessibility/label.js +1 -1
- package/core/audits/accessibility/landmark-one-main.js +1 -1
- package/core/audits/accessibility/link-in-text-block.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/select-name.js +1 -1
- package/core/audits/accessibility/skip-link.js +1 -1
- package/core/audits/accessibility/tabindex.js +1 -1
- package/core/audits/accessibility/table-duplicate-name.js +1 -1
- package/core/audits/accessibility/table-fake-caption.js +1 -1
- package/core/audits/accessibility/target-size.js +1 -2
- package/core/audits/accessibility/td-has-header.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/byte-efficiency/byte-efficiency-audit.d.ts +0 -16
- package/core/audits/byte-efficiency/byte-efficiency-audit.js +1 -38
- package/core/audits/byte-efficiency/offscreen-images.d.ts +0 -11
- package/core/audits/byte-efficiency/offscreen-images.js +0 -15
- package/core/audits/byte-efficiency/render-blocking-resources.js +27 -26
- package/core/audits/byte-efficiency/unminified-css.js +2 -2
- package/core/audits/byte-efficiency/unused-css-rules.js +3 -1
- package/core/audits/dobetterweb/uses-http2.d.ts +0 -13
- package/core/audits/dobetterweb/uses-http2.js +4 -38
- package/core/audits/font-display.js +2 -2
- package/core/audits/layout-shifts.js +2 -2
- package/core/audits/preload-fonts.d.ts +1 -5
- package/core/audits/preload-fonts.js +1 -10
- package/core/audits/prioritize-lcp-image.js +2 -2
- package/core/audits/redirects-http.d.ts +19 -0
- package/core/audits/redirects-http.js +75 -0
- package/core/audits/resource-summary.d.ts +2 -0
- package/core/audits/resource-summary.js +5 -4
- package/core/audits/seo/is-crawlable.d.ts +2 -1
- package/core/audits/seo/link-text.js +12 -0
- package/core/audits/uses-rel-preload.d.ts +1 -5
- package/core/audits/uses-rel-preload.js +5 -15
- package/core/audits/work-during-interaction.d.ts +2 -2
- package/core/audits/work-during-interaction.js +2 -2
- package/core/computed/js-bundles.d.ts +1 -1
- package/core/computed/metrics/cumulative-layout-shift.js +2 -2
- package/core/computed/metrics/lantern-first-contentful-paint.d.ts +13 -82
- package/core/computed/metrics/lantern-first-contentful-paint.js +16 -178
- package/core/computed/metrics/lantern-first-meaningful-paint.d.ts +13 -12
- package/core/computed/metrics/lantern-first-meaningful-paint.js +11 -49
- package/core/computed/metrics/lantern-interactive.d.ts +13 -21
- package/core/computed/metrics/lantern-interactive.js +12 -84
- package/core/computed/metrics/lantern-largest-contentful-paint.d.ts +13 -25
- package/core/computed/metrics/lantern-largest-contentful-paint.js +13 -80
- package/core/computed/metrics/lantern-max-potential-fid.d.ts +13 -24
- package/core/computed/metrics/lantern-max-potential-fid.js +12 -64
- package/core/computed/metrics/lantern-metric.d.ts +14 -18
- package/core/computed/metrics/lantern-metric.js +34 -30
- package/core/computed/metrics/lantern-speed-index.d.ts +13 -32
- package/core/computed/metrics/lantern-speed-index.js +13 -116
- package/core/computed/metrics/lantern-total-blocking-time.d.ts +13 -25
- package/core/computed/metrics/lantern-total-blocking-time.js +10 -94
- package/core/computed/metrics/metric.js +1 -3
- package/core/computed/module-duplication.d.ts +1 -1
- package/core/computed/navigation-insights.d.ts +36 -0
- package/core/computed/navigation-insights.js +35 -0
- package/core/computed/page-dependency-graph.js +3 -7
- package/core/computed/resource-summary.d.ts +10 -12
- package/core/computed/resource-summary.js +12 -19
- package/core/computed/trace-engine-result.d.ts +16 -3
- package/core/computed/trace-engine-result.js +19 -14
- package/core/computed/unused-css.d.ts +3 -1
- package/core/computed/unused-css.js +6 -5
- package/core/config/config-helpers.js +0 -4
- package/core/config/constants.js +0 -1
- package/core/config/default-config.js +63 -142
- package/core/config/experimental-config.js +11 -0
- package/core/config/filters.js +0 -1
- package/core/gather/driver/navigation.js +4 -1
- package/core/gather/driver/prepare.js +1 -1
- package/core/gather/driver/target-manager.js +4 -3
- package/core/gather/driver/wait-for-condition.js +2 -3
- package/core/gather/driver.d.ts +12 -0
- package/core/gather/driver.js +27 -0
- package/core/gather/gatherers/accessibility.js +4 -6
- package/core/gather/gatherers/css-usage.d.ts +0 -21
- package/core/gather/gatherers/css-usage.js +9 -119
- package/core/gather/gatherers/root-causes.d.ts +2 -2
- package/core/gather/gatherers/root-causes.js +6 -5
- package/core/gather/gatherers/stylesheets.d.ts +26 -0
- package/core/gather/gatherers/stylesheets.js +138 -0
- package/core/gather/gatherers/trace-elements.d.ts +4 -13
- package/core/gather/gatherers/trace-elements.js +42 -31
- package/core/gather/navigation-runner.js +3 -1
- package/core/gather/session.d.ts +8 -0
- package/core/gather/session.js +14 -1
- package/core/lib/emulation.js +2 -2
- package/core/lib/i18n/i18n.d.ts +0 -1
- package/core/lib/i18n/i18n.js +0 -2
- package/core/lib/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/metric.js +2 -6
- package/core/lib/lantern/metrics/first-contentful-paint.d.ts +79 -0
- package/core/lib/lantern/metrics/first-contentful-paint.js +200 -0
- package/core/lib/lantern/metrics/first-meaningful-paint.d.ts +6 -0
- package/core/lib/lantern/metrics/first-meaningful-paint.js +64 -0
- package/core/lib/lantern/metrics/interactive.d.ts +26 -0
- package/core/lib/lantern/metrics/interactive.js +112 -0
- package/core/lib/lantern/metrics/largest-contentful-paint.d.ts +19 -0
- package/core/lib/lantern/metrics/largest-contentful-paint.js +108 -0
- package/core/lib/lantern/metrics/max-potential-fid.d.ts +30 -0
- package/core/lib/lantern/metrics/max-potential-fid.js +92 -0
- package/core/lib/lantern/metrics/speed-index.d.ts +38 -0
- package/core/lib/lantern/metrics/speed-index.js +144 -0
- package/core/lib/lantern/metrics/total-blocking-time.d.ts +31 -0
- package/core/lib/lantern/metrics/total-blocking-time.js +128 -0
- package/core/lib/lantern/network-node.js +28 -4
- package/core/lib/lantern/page-dependency-graph.d.ts +4 -4
- package/core/lib/lantern/page-dependency-graph.js +19 -7
- package/core/lib/lantern/simulator/connection-pool.d.ts +2 -12
- package/core/lib/lantern/simulator/connection-pool.js +3 -22
- package/core/lib/lantern/simulator/network-analyzer.js +1 -12
- package/core/lib/lantern/simulator/simulator.d.ts +2 -4
- package/core/lib/lantern/simulator/simulator.js +7 -14
- package/core/lib/lantern/types/lantern.d.ts +5 -3
- package/core/lib/lantern-trace-saver.js +0 -1
- package/core/lib/lh-error.d.ts +9 -0
- package/core/lib/lh-error.js +13 -3
- package/core/lib/lighthouse-compatibility.js +53 -10
- package/core/lib/navigation-error.js +3 -0
- package/core/lib/network-request.d.ts +1 -0
- package/core/lib/network-request.js +29 -1
- package/core/lib/proto-preprocessor.js +24 -8
- package/core/lib/tracehouse/trace-processor.js +15 -2
- package/core/runner.js +18 -25
- package/dist/report/bundle.esm.js +11 -112
- package/dist/report/flow.js +16 -117
- package/dist/report/standalone.js +12 -113
- 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/flow-report/src/summary/category.tsx +10 -12
- package/package.json +7 -7
- package/readme.md +4 -4
- package/report/assets/styles.css +1 -60
- package/report/assets/templates.html +0 -95
- package/report/renderer/category-renderer.js +1 -1
- package/report/renderer/components.d.ts +2 -2
- package/report/renderer/components.js +2 -103
- package/report/renderer/dom.d.ts +1 -1
- package/report/renderer/dom.js +1 -1
- package/report/renderer/performance-category-renderer.d.ts +0 -7
- package/report/renderer/performance-category-renderer.js +1 -32
- package/report/renderer/report-renderer.js +3 -13
- package/report/renderer/report-ui-features.js +1 -1
- package/report/renderer/report-utils.d.ts +0 -1
- package/report/renderer/report-utils.js +13 -13
- package/shared/localization/locales/ar-XB.json +62 -329
- package/shared/localization/locales/ar.json +62 -329
- package/shared/localization/locales/bg.json +62 -329
- package/shared/localization/locales/ca.json +62 -329
- package/shared/localization/locales/cs.json +62 -329
- package/shared/localization/locales/da.json +62 -329
- package/shared/localization/locales/de.json +62 -329
- package/shared/localization/locales/el.json +62 -329
- package/shared/localization/locales/en-GB.json +62 -329
- package/shared/localization/locales/en-US.json +101 -332
- package/shared/localization/locales/en-XA.json +62 -329
- package/shared/localization/locales/en-XL.json +101 -332
- package/shared/localization/locales/es-419.json +62 -329
- package/shared/localization/locales/es.json +62 -329
- package/shared/localization/locales/fi.json +62 -329
- package/shared/localization/locales/fil.json +61 -328
- package/shared/localization/locales/fr.json +62 -329
- package/shared/localization/locales/he.json +62 -329
- package/shared/localization/locales/hi.json +62 -329
- package/shared/localization/locales/hr.json +63 -330
- package/shared/localization/locales/hu.json +62 -329
- package/shared/localization/locales/id.json +62 -329
- package/shared/localization/locales/it.json +62 -329
- package/shared/localization/locales/ja.json +62 -329
- package/shared/localization/locales/ko.json +62 -329
- package/shared/localization/locales/lt.json +62 -329
- package/shared/localization/locales/lv.json +62 -329
- package/shared/localization/locales/nl.json +62 -329
- package/shared/localization/locales/no.json +62 -329
- package/shared/localization/locales/pl.json +61 -328
- package/shared/localization/locales/pt-PT.json +62 -329
- package/shared/localization/locales/pt.json +64 -331
- package/shared/localization/locales/ro.json +62 -329
- package/shared/localization/locales/ru.json +62 -329
- package/shared/localization/locales/sk.json +62 -329
- package/shared/localization/locales/sl.json +62 -329
- package/shared/localization/locales/sr-Latn.json +62 -329
- package/shared/localization/locales/sr.json +62 -329
- package/shared/localization/locales/sv.json +62 -329
- package/shared/localization/locales/ta.json +61 -328
- package/shared/localization/locales/te.json +62 -329
- package/shared/localization/locales/th.json +62 -329
- package/shared/localization/locales/tr.json +62 -329
- package/shared/localization/locales/uk.json +62 -329
- package/shared/localization/locales/vi.json +61 -328
- package/shared/localization/locales/zh-HK.json +62 -329
- package/shared/localization/locales/zh-TW.json +61 -328
- package/shared/localization/locales/zh.json +62 -329
- package/tsconfig.json +1 -3
- package/types/artifacts.d.ts +21 -110
- package/types/audit.d.ts +0 -10
- package/types/config.d.ts +0 -1
- package/types/externs.d.ts +0 -2
- package/types/gatherer.d.ts +3 -0
- package/types/internal/smokehouse.d.ts +1 -1
- package/types/lh.d.ts +0 -2
- package/types/lhr/audit-details.d.ts +9 -4
- package/types/lhr/lhr.d.ts +0 -4
- package/types/lhr/settings.d.ts +0 -4
- package/core/audits/accessibility/duplicate-id-active.js +0 -42
- 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/layout-shift-elements.d.ts +0 -16
- package/core/audits/layout-shift-elements.js +0 -101
- 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/no-unload-listeners.d.ts +0 -16
- package/core/audits/no-unload-listeners.js +0 -86
- package/core/audits/performance-budget.d.ts +0 -39
- package/core/audits/performance-budget.js +0 -154
- package/core/audits/script-elements-test-audit.d.ts +0 -14
- package/core/audits/script-elements-test-audit.js +0 -29
- package/core/audits/seo/plugins.d.ts +0 -15
- package/core/audits/seo/plugins.js +0 -150
- package/core/audits/seo/tap-targets.d.ts +0 -50
- package/core/audits/seo/tap-targets.js +0 -352
- 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/audits/timing-budget.d.ts +0 -43
- package/core/audits/timing-budget.js +0 -175
- package/core/computed/manifest-values.d.ts +0 -24
- package/core/computed/manifest-values.js +0 -136
- package/core/config/budget.d.ts +0 -74
- package/core/config/budget.js +0 -340
- package/core/config/metrics-to-audits.d.ts +0 -19
- package/core/config/metrics-to-audits.js +0 -62
- package/core/gather/driver/service-workers.d.ts +0 -16
- package/core/gather/driver/service-workers.js +0 -52
- 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/global-listeners.d.ts +0 -27
- package/core/gather/gatherers/global-listeners.js +0 -108
- package/core/gather/gatherers/installability-errors.d.ts +0 -17
- package/core/gather/gatherers/installability-errors.js +0 -56
- package/core/gather/gatherers/script-elements.d.ts +0 -21
- package/core/gather/gatherers/script-elements.js +0 -100
- package/core/gather/gatherers/seo/embedded-content.d.ts +0 -10
- package/core/gather/gatherers/seo/embedded-content.js +0 -63
- package/core/gather/gatherers/seo/tap-targets.d.ts +0 -21
- package/core/gather/gatherers/seo/tap-targets.js +0 -389
- package/core/gather/gatherers/service-worker.d.ts +0 -10
- package/core/gather/gatherers/service-worker.js +0 -32
- 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
- package/types/lhr/budget.d.ts +0 -60
|
@@ -498,9 +498,8 @@ async function waitForFullyLoaded(session, networkMonitor, options) {
|
|
|
498
498
|
if (await isPageHung(session)) {
|
|
499
499
|
log.warn('waitFor', 'Page appears to be hung, killing JavaScript...');
|
|
500
500
|
// We don't await these, as we want to exit with PAGE_HUNG
|
|
501
|
-
void session.
|
|
502
|
-
|
|
503
|
-
void session.sendCommand('Runtime.terminateExecution').catch(_ => {});
|
|
501
|
+
void session.sendCommandAndIgnore('Emulation.setScriptExecutionDisabled', {value: true});
|
|
502
|
+
void session.sendCommandAndIgnore('Runtime.terminateExecution');
|
|
504
503
|
throw new LighthouseError(LighthouseError.errors.PAGE_HUNG);
|
|
505
504
|
}
|
|
506
505
|
|
package/core/gather/driver.d.ts
CHANGED
|
@@ -14,6 +14,10 @@ export class Driver implements LH.Gatherer.Driver {
|
|
|
14
14
|
/** @type {Fetcher|undefined} */
|
|
15
15
|
_fetcher: Fetcher | undefined;
|
|
16
16
|
defaultSession: import("../../types/gatherer.js").default.ProtocolSession;
|
|
17
|
+
fatalRejection: {
|
|
18
|
+
promise: Promise<never>;
|
|
19
|
+
rej: (_: Error) => void;
|
|
20
|
+
};
|
|
17
21
|
/** @return {LH.Gatherer.Driver['executionContext']} */
|
|
18
22
|
get executionContext(): ExecutionContext;
|
|
19
23
|
get fetcher(): any;
|
|
@@ -23,6 +27,14 @@ export class Driver implements LH.Gatherer.Driver {
|
|
|
23
27
|
url(): Promise<string>;
|
|
24
28
|
/** @return {Promise<void>} */
|
|
25
29
|
connect(): Promise<void>;
|
|
30
|
+
/**
|
|
31
|
+
* If the target crashes, we can't continue gathering.
|
|
32
|
+
*
|
|
33
|
+
* FWIW, if the target unexpectedly detaches (eg the user closed the tab), pptr will
|
|
34
|
+
* catch that and reject into our this._cdpSession.send, which we'll alrady handle appropriately
|
|
35
|
+
* @return {void}
|
|
36
|
+
*/
|
|
37
|
+
listenForCrashes(): void;
|
|
26
38
|
/** @return {Promise<void>} */
|
|
27
39
|
disconnect(): Promise<void>;
|
|
28
40
|
}
|
package/core/gather/driver.js
CHANGED
|
@@ -8,6 +8,7 @@ import log from 'lighthouse-logger';
|
|
|
8
8
|
|
|
9
9
|
import {ExecutionContext} from './driver/execution-context.js';
|
|
10
10
|
import {TargetManager} from './driver/target-manager.js';
|
|
11
|
+
import {LighthouseError} from '../lib/lh-error.js';
|
|
11
12
|
import {Fetcher} from './fetcher.js';
|
|
12
13
|
import {NetworkMonitor} from './driver/network-monitor.js';
|
|
13
14
|
|
|
@@ -26,6 +27,7 @@ const throwingSession = {
|
|
|
26
27
|
once: throwNotConnectedFn,
|
|
27
28
|
off: throwNotConnectedFn,
|
|
28
29
|
sendCommand: throwNotConnectedFn,
|
|
30
|
+
sendCommandAndIgnore: throwNotConnectedFn,
|
|
29
31
|
dispose: throwNotConnectedFn,
|
|
30
32
|
};
|
|
31
33
|
|
|
@@ -46,6 +48,12 @@ class Driver {
|
|
|
46
48
|
this._fetcher = undefined;
|
|
47
49
|
|
|
48
50
|
this.defaultSession = throwingSession;
|
|
51
|
+
|
|
52
|
+
// Poor man's Promise.withResolvers()
|
|
53
|
+
/** @param {Error} _ */
|
|
54
|
+
let rej = _ => {};
|
|
55
|
+
const promise = /** @type {Promise<never>} */ (new Promise((_, theRej) => rej = theRej));
|
|
56
|
+
this.fatalRejection = {promise, rej};
|
|
49
57
|
}
|
|
50
58
|
|
|
51
59
|
/** @return {LH.Gatherer.Driver['executionContext']} */
|
|
@@ -85,11 +93,30 @@ class Driver {
|
|
|
85
93
|
this._networkMonitor = new NetworkMonitor(this._targetManager);
|
|
86
94
|
await this._networkMonitor.enable();
|
|
87
95
|
this.defaultSession = this._targetManager.rootSession();
|
|
96
|
+
this.listenForCrashes();
|
|
88
97
|
this._executionContext = new ExecutionContext(this.defaultSession);
|
|
89
98
|
this._fetcher = new Fetcher(this.defaultSession);
|
|
90
99
|
log.timeEnd(status);
|
|
91
100
|
}
|
|
92
101
|
|
|
102
|
+
/**
|
|
103
|
+
* If the target crashes, we can't continue gathering.
|
|
104
|
+
*
|
|
105
|
+
* FWIW, if the target unexpectedly detaches (eg the user closed the tab), pptr will
|
|
106
|
+
* catch that and reject into our this._cdpSession.send, which we'll alrady handle appropriately
|
|
107
|
+
* @return {void}
|
|
108
|
+
*/
|
|
109
|
+
listenForCrashes() {
|
|
110
|
+
this.defaultSession.on('Inspector.targetCrashed', async _ => {
|
|
111
|
+
log.error('Driver', 'Inspector.targetCrashed');
|
|
112
|
+
// Manually detach so no more CDP traffic is attempted.
|
|
113
|
+
// Don't await, else our rejection will be a 'Target closed' protocol error on cross-talk CDP calls.
|
|
114
|
+
void this.defaultSession.dispose();
|
|
115
|
+
this.fatalRejection.rej(new LighthouseError(LighthouseError.errors.TARGET_CRASHED));
|
|
116
|
+
});
|
|
117
|
+
}
|
|
118
|
+
|
|
119
|
+
|
|
93
120
|
/** @return {Promise<void>} */
|
|
94
121
|
async disconnect() {
|
|
95
122
|
if (this.defaultSession === throwingSession) return;
|
|
@@ -43,16 +43,15 @@ async function runA11yChecks() {
|
|
|
43
43
|
'area-alt': {enabled: false},
|
|
44
44
|
'aria-allowed-role': {enabled: true},
|
|
45
45
|
'aria-braille-equivalent': {enabled: false},
|
|
46
|
-
'aria-conditional-attr': {enabled:
|
|
47
|
-
'aria-deprecated-role': {enabled:
|
|
46
|
+
'aria-conditional-attr': {enabled: true},
|
|
47
|
+
'aria-deprecated-role': {enabled: true},
|
|
48
48
|
'aria-dialog-name': {enabled: true},
|
|
49
|
-
'aria-prohibited-attr': {enabled:
|
|
49
|
+
'aria-prohibited-attr': {enabled: true},
|
|
50
50
|
'aria-roledescription': {enabled: false},
|
|
51
51
|
'aria-treeitem-name': {enabled: true},
|
|
52
52
|
'aria-text': {enabled: true},
|
|
53
53
|
'audio-caption': {enabled: false},
|
|
54
54
|
'blink': {enabled: false},
|
|
55
|
-
'duplicate-id-active': {enabled: true},
|
|
56
55
|
'duplicate-id': {enabled: false},
|
|
57
56
|
'empty-heading': {enabled: true},
|
|
58
57
|
'frame-focusable-content': {enabled: false},
|
|
@@ -79,8 +78,7 @@ async function runA11yChecks() {
|
|
|
79
78
|
'tabindex': {enabled: true},
|
|
80
79
|
'table-duplicate-name': {enabled: true},
|
|
81
80
|
'table-fake-caption': {enabled: true},
|
|
82
|
-
|
|
83
|
-
// 'target-size': {enabled: true},
|
|
81
|
+
'target-size': {enabled: true},
|
|
84
82
|
'td-has-header': {enabled: true},
|
|
85
83
|
},
|
|
86
84
|
});
|
|
@@ -1,26 +1,5 @@
|
|
|
1
1
|
export default CSSUsage;
|
|
2
2
|
declare class CSSUsage extends BaseGatherer {
|
|
3
|
-
/** @type {LH.Gatherer.ProtocolSession|undefined} */
|
|
4
|
-
_session: LH.Gatherer.ProtocolSession | undefined;
|
|
5
|
-
/** @type {Map<string, Promise<LH.Artifacts.CSSStyleSheetInfo|Error>>} */
|
|
6
|
-
_sheetPromises: Map<string, Promise<LH.Artifacts.CSSStyleSheetInfo | Error>>;
|
|
7
|
-
/**
|
|
8
|
-
* Initialize as undefined so we can assert results are fetched.
|
|
9
|
-
* @type {LH.Crdp.CSS.RuleUsage[]|undefined}
|
|
10
|
-
*/
|
|
11
|
-
_ruleUsage: LH.Crdp.CSS.RuleUsage[] | undefined;
|
|
12
|
-
/**
|
|
13
|
-
* @param {LH.Crdp.CSS.StyleSheetAddedEvent} event
|
|
14
|
-
*/
|
|
15
|
-
_onStylesheetAdded(event: LH.Crdp.CSS.StyleSheetAddedEvent): void;
|
|
16
|
-
/**
|
|
17
|
-
* @param {LH.Gatherer.Context} context
|
|
18
|
-
*/
|
|
19
|
-
startInstrumentation(context: LH.Gatherer.Context): Promise<void>;
|
|
20
|
-
/**
|
|
21
|
-
* @param {LH.Gatherer.Context} context
|
|
22
|
-
*/
|
|
23
|
-
stopInstrumentation(context: LH.Gatherer.Context): Promise<void>;
|
|
24
3
|
/**
|
|
25
4
|
* @param {LH.Gatherer.Context} context
|
|
26
5
|
* @return {Promise<LH.Artifacts['CSSUsage']>}
|
|
@@ -8,145 +8,35 @@
|
|
|
8
8
|
* @fileoverview Tracks unused CSS rules.
|
|
9
9
|
*/
|
|
10
10
|
|
|
11
|
-
import log from 'lighthouse-logger';
|
|
12
|
-
|
|
13
11
|
import BaseGatherer from '../base-gatherer.js';
|
|
14
|
-
import {Sentry} from '../../lib/sentry.js';
|
|
15
12
|
|
|
16
13
|
class CSSUsage extends BaseGatherer {
|
|
17
|
-
constructor() {
|
|
18
|
-
super();
|
|
19
|
-
/** @type {LH.Gatherer.ProtocolSession|undefined} */
|
|
20
|
-
this._session = undefined;
|
|
21
|
-
/** @type {Map<string, Promise<LH.Artifacts.CSSStyleSheetInfo|Error>>} */
|
|
22
|
-
this._sheetPromises = new Map();
|
|
23
|
-
/**
|
|
24
|
-
* Initialize as undefined so we can assert results are fetched.
|
|
25
|
-
* @type {LH.Crdp.CSS.RuleUsage[]|undefined}
|
|
26
|
-
*/
|
|
27
|
-
this._ruleUsage = undefined;
|
|
28
|
-
this._onStylesheetAdded = this._onStylesheetAdded.bind(this);
|
|
29
|
-
}
|
|
30
|
-
|
|
31
14
|
/** @type {LH.Gatherer.GathererMeta} */
|
|
32
15
|
meta = {
|
|
33
|
-
supportedModes: ['snapshot', '
|
|
16
|
+
supportedModes: ['snapshot', 'navigation'],
|
|
34
17
|
};
|
|
35
18
|
|
|
36
|
-
/**
|
|
37
|
-
* @param {LH.Crdp.CSS.StyleSheetAddedEvent} event
|
|
38
|
-
*/
|
|
39
|
-
_onStylesheetAdded(event) {
|
|
40
|
-
if (!this._session) throw new Error('Session not initialized');
|
|
41
|
-
const styleSheetId = event.header.styleSheetId;
|
|
42
|
-
const sheetPromise = this._session.sendCommand('CSS.getStyleSheetText', {styleSheetId})
|
|
43
|
-
.then(content => ({
|
|
44
|
-
header: event.header,
|
|
45
|
-
content: content.text,
|
|
46
|
-
}))
|
|
47
|
-
.catch(/** @param {Error} err */ (err) => {
|
|
48
|
-
log.warn(
|
|
49
|
-
'CSSUsage',
|
|
50
|
-
`Error fetching content of stylesheet with URL "${event.header.sourceURL}"`
|
|
51
|
-
);
|
|
52
|
-
Sentry.captureException(err, {
|
|
53
|
-
tags: {
|
|
54
|
-
gatherer: 'CSSUsage',
|
|
55
|
-
},
|
|
56
|
-
extra: {
|
|
57
|
-
url: event.header.sourceURL,
|
|
58
|
-
},
|
|
59
|
-
level: 'error',
|
|
60
|
-
});
|
|
61
|
-
return err;
|
|
62
|
-
});
|
|
63
|
-
this._sheetPromises.set(styleSheetId, sheetPromise);
|
|
64
|
-
}
|
|
65
|
-
|
|
66
19
|
/**
|
|
67
20
|
* @param {LH.Gatherer.Context} context
|
|
21
|
+
* @return {Promise<LH.Artifacts['CSSUsage']>}
|
|
68
22
|
*/
|
|
69
|
-
async
|
|
23
|
+
async getArtifact(context) {
|
|
70
24
|
const session = context.driver.defaultSession;
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
// Calling `CSS.enable` will emit events for stylesheets currently on the page.
|
|
74
|
-
// We want to ignore these events in navigation mode because they are not relevant to the
|
|
75
|
-
// navigation that is about to happen. Adding the event listener *after* calling `CSS.enable`
|
|
76
|
-
// ensures that the events for pre-existing stylesheets are ignored.
|
|
77
|
-
const isNavigation = context.gatherMode === 'navigation';
|
|
78
|
-
if (!isNavigation) {
|
|
79
|
-
session.on('CSS.styleSheetAdded', this._onStylesheetAdded);
|
|
80
|
-
}
|
|
25
|
+
const executionContext = context.driver.executionContext;
|
|
81
26
|
|
|
82
27
|
await session.sendCommand('DOM.enable');
|
|
83
28
|
await session.sendCommand('CSS.enable');
|
|
84
29
|
await session.sendCommand('CSS.startRuleUsageTracking');
|
|
85
30
|
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
}
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
/**
|
|
93
|
-
* @param {LH.Gatherer.Context} context
|
|
94
|
-
*/
|
|
95
|
-
async stopInstrumentation(context) {
|
|
96
|
-
const session = context.driver.defaultSession;
|
|
97
|
-
const coverageResponse = await session.sendCommand('CSS.stopRuleUsageTracking');
|
|
98
|
-
this._ruleUsage = coverageResponse.ruleUsage;
|
|
99
|
-
session.off('CSS.styleSheetAdded', this._onStylesheetAdded);
|
|
100
|
-
|
|
101
|
-
// Ensure we finish fetching all stylesheet contents before disabling the CSS domain
|
|
102
|
-
await Promise.all(this._sheetPromises.values());
|
|
31
|
+
// Force style to recompute.
|
|
32
|
+
// Doesn't appear to be necessary in newer versions of Chrome.
|
|
33
|
+
await executionContext.evaluateAsync('getComputedStyle(document.body)');
|
|
103
34
|
|
|
35
|
+
const {ruleUsage} = await session.sendCommand('CSS.stopRuleUsageTracking');
|
|
104
36
|
await session.sendCommand('CSS.disable');
|
|
105
37
|
await session.sendCommand('DOM.disable');
|
|
106
|
-
}
|
|
107
|
-
|
|
108
|
-
/**
|
|
109
|
-
* @param {LH.Gatherer.Context} context
|
|
110
|
-
* @return {Promise<LH.Artifacts['CSSUsage']>}
|
|
111
|
-
*/
|
|
112
|
-
async getArtifact(context) {
|
|
113
|
-
const executionContext = context.driver.executionContext;
|
|
114
|
-
|
|
115
|
-
if (context.gatherMode === 'snapshot') {
|
|
116
|
-
await this.startInstrumentation(context);
|
|
117
|
-
|
|
118
|
-
// Force style to recompute.
|
|
119
|
-
// Doesn't appear to be necessary in newer versions of Chrome.
|
|
120
|
-
await executionContext.evaluateAsync('getComputedStyle(document.body)');
|
|
121
|
-
|
|
122
|
-
await this.stopInstrumentation(context);
|
|
123
|
-
}
|
|
124
|
-
|
|
125
|
-
/** @type {Map<string, LH.Artifacts.CSSStyleSheetInfo>} */
|
|
126
|
-
const dedupedStylesheets = new Map();
|
|
127
|
-
const sheets = await Promise.all(this._sheetPromises.values());
|
|
128
|
-
|
|
129
|
-
for (const sheet of sheets) {
|
|
130
|
-
// Erroneous sheets will be reported via sentry and the log.
|
|
131
|
-
// We can ignore them here without throwing a fatal error.
|
|
132
|
-
if (sheet instanceof Error) {
|
|
133
|
-
continue;
|
|
134
|
-
}
|
|
135
|
-
|
|
136
|
-
// Exclude empty stylesheets.
|
|
137
|
-
if (sheet.header.length === 0) {
|
|
138
|
-
continue;
|
|
139
|
-
}
|
|
140
|
-
|
|
141
|
-
dedupedStylesheets.set(sheet.content, sheet);
|
|
142
|
-
}
|
|
143
|
-
|
|
144
|
-
if (!this._ruleUsage) throw new Error('Issue collecting rule usages');
|
|
145
38
|
|
|
146
|
-
return
|
|
147
|
-
rules: this._ruleUsage,
|
|
148
|
-
stylesheets: Array.from(dedupedStylesheets.values()),
|
|
149
|
-
};
|
|
39
|
+
return ruleUsage;
|
|
150
40
|
}
|
|
151
41
|
}
|
|
152
42
|
|
|
@@ -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
|
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
export default Stylesheets;
|
|
2
|
+
declare class Stylesheets extends BaseGatherer {
|
|
3
|
+
/** @type {LH.Gatherer.ProtocolSession|undefined} */
|
|
4
|
+
_session: LH.Gatherer.ProtocolSession | undefined;
|
|
5
|
+
/** @type {Map<string, Promise<LH.Artifacts.CSSStyleSheetInfo|null>>} */
|
|
6
|
+
_sheetPromises: Map<string, Promise<LH.Artifacts.CSSStyleSheetInfo | null>>;
|
|
7
|
+
/**
|
|
8
|
+
* @param {LH.Crdp.CSS.StyleSheetAddedEvent} event
|
|
9
|
+
*/
|
|
10
|
+
_onStylesheetAdded(event: LH.Crdp.CSS.StyleSheetAddedEvent): void;
|
|
11
|
+
/**
|
|
12
|
+
* @param {LH.Gatherer.Context} context
|
|
13
|
+
*/
|
|
14
|
+
startInstrumentation(context: LH.Gatherer.Context): Promise<void>;
|
|
15
|
+
/**
|
|
16
|
+
* @param {LH.Gatherer.Context} context
|
|
17
|
+
*/
|
|
18
|
+
stopInstrumentation(context: LH.Gatherer.Context): Promise<void>;
|
|
19
|
+
/**
|
|
20
|
+
* @param {LH.Gatherer.Context} context
|
|
21
|
+
* @return {Promise<LH.Artifacts['Stylesheets']>}
|
|
22
|
+
*/
|
|
23
|
+
getArtifact(context: LH.Gatherer.Context): Promise<LH.Artifacts['Stylesheets']>;
|
|
24
|
+
}
|
|
25
|
+
import BaseGatherer from '../base-gatherer.js';
|
|
26
|
+
//# sourceMappingURL=stylesheets.d.ts.map
|
|
@@ -0,0 +1,138 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @license
|
|
3
|
+
* Copyright 2024 Google LLC
|
|
4
|
+
* SPDX-License-Identifier: Apache-2.0
|
|
5
|
+
*/
|
|
6
|
+
|
|
7
|
+
/**
|
|
8
|
+
* @fileoverview Collects all stylesheets and their contents.
|
|
9
|
+
*/
|
|
10
|
+
|
|
11
|
+
import log from 'lighthouse-logger';
|
|
12
|
+
|
|
13
|
+
import BaseGatherer from '../base-gatherer.js';
|
|
14
|
+
import {Sentry} from '../../lib/sentry.js';
|
|
15
|
+
|
|
16
|
+
class Stylesheets extends BaseGatherer {
|
|
17
|
+
constructor() {
|
|
18
|
+
super();
|
|
19
|
+
/** @type {LH.Gatherer.ProtocolSession|undefined} */
|
|
20
|
+
this._session = undefined;
|
|
21
|
+
/** @type {Map<string, Promise<LH.Artifacts.CSSStyleSheetInfo|null>>} */
|
|
22
|
+
this._sheetPromises = new Map();
|
|
23
|
+
this._onStylesheetAdded = this._onStylesheetAdded.bind(this);
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
/** @type {LH.Gatherer.GathererMeta} */
|
|
27
|
+
meta = {
|
|
28
|
+
supportedModes: ['snapshot', 'timespan', 'navigation'],
|
|
29
|
+
};
|
|
30
|
+
|
|
31
|
+
/**
|
|
32
|
+
* @param {LH.Crdp.CSS.StyleSheetAddedEvent} event
|
|
33
|
+
*/
|
|
34
|
+
_onStylesheetAdded(event) {
|
|
35
|
+
if (!this._session) throw new Error('Session not initialized');
|
|
36
|
+
const styleSheetId = event.header.styleSheetId;
|
|
37
|
+
const sheetPromise = this._session.sendCommand('CSS.getStyleSheetText', {styleSheetId})
|
|
38
|
+
.then(content => ({
|
|
39
|
+
header: event.header,
|
|
40
|
+
content: content.text,
|
|
41
|
+
}))
|
|
42
|
+
.catch(err => {
|
|
43
|
+
log.warn(
|
|
44
|
+
'Stylesheets',
|
|
45
|
+
`Error fetching content of stylesheet with URL "${event.header.sourceURL}"`
|
|
46
|
+
);
|
|
47
|
+
Sentry.captureException(err, {
|
|
48
|
+
tags: {
|
|
49
|
+
gatherer: 'Stylesheets',
|
|
50
|
+
},
|
|
51
|
+
extra: {
|
|
52
|
+
url: event.header.sourceURL,
|
|
53
|
+
},
|
|
54
|
+
level: 'error',
|
|
55
|
+
});
|
|
56
|
+
return null;
|
|
57
|
+
});
|
|
58
|
+
this._sheetPromises.set(styleSheetId, sheetPromise);
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
/**
|
|
62
|
+
* @param {LH.Gatherer.Context} context
|
|
63
|
+
*/
|
|
64
|
+
async startInstrumentation(context) {
|
|
65
|
+
const session = context.driver.defaultSession;
|
|
66
|
+
this._session = session;
|
|
67
|
+
|
|
68
|
+
// Calling `CSS.enable` will emit events for stylesheets currently on the page.
|
|
69
|
+
// We want to ignore these events in navigation mode because they are not relevant to the
|
|
70
|
+
// navigation that is about to happen. Adding the event listener *after* calling `CSS.enable`
|
|
71
|
+
// ensures that the events for pre-existing stylesheets are ignored.
|
|
72
|
+
const isNavigation = context.gatherMode === 'navigation';
|
|
73
|
+
if (!isNavigation) {
|
|
74
|
+
session.on('CSS.styleSheetAdded', this._onStylesheetAdded);
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
await session.sendCommand('DOM.enable');
|
|
78
|
+
await session.sendCommand('CSS.enable');
|
|
79
|
+
|
|
80
|
+
if (isNavigation) {
|
|
81
|
+
session.on('CSS.styleSheetAdded', this._onStylesheetAdded);
|
|
82
|
+
}
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
|
|
86
|
+
/**
|
|
87
|
+
* @param {LH.Gatherer.Context} context
|
|
88
|
+
*/
|
|
89
|
+
async stopInstrumentation(context) {
|
|
90
|
+
const session = context.driver.defaultSession;
|
|
91
|
+
session.off('CSS.styleSheetAdded', this._onStylesheetAdded);
|
|
92
|
+
|
|
93
|
+
// Ensure we finish fetching all stylesheet contents before disabling the CSS domain
|
|
94
|
+
await Promise.all(this._sheetPromises.values());
|
|
95
|
+
|
|
96
|
+
await session.sendCommand('CSS.disable');
|
|
97
|
+
await session.sendCommand('DOM.disable');
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
/**
|
|
101
|
+
* @param {LH.Gatherer.Context} context
|
|
102
|
+
* @return {Promise<LH.Artifacts['Stylesheets']>}
|
|
103
|
+
*/
|
|
104
|
+
async getArtifact(context) {
|
|
105
|
+
const executionContext = context.driver.executionContext;
|
|
106
|
+
|
|
107
|
+
if (context.gatherMode === 'snapshot') {
|
|
108
|
+
await this.startInstrumentation(context);
|
|
109
|
+
|
|
110
|
+
// Force style to recompute.
|
|
111
|
+
// Doesn't appear to be necessary in newer versions of Chrome.
|
|
112
|
+
await executionContext.evaluateAsync('getComputedStyle(document.body)');
|
|
113
|
+
|
|
114
|
+
await this.stopInstrumentation(context);
|
|
115
|
+
}
|
|
116
|
+
|
|
117
|
+
/** @type {Map<string, LH.Artifacts.CSSStyleSheetInfo>} */
|
|
118
|
+
const dedupedStylesheets = new Map();
|
|
119
|
+
const sheets = await Promise.all(this._sheetPromises.values());
|
|
120
|
+
|
|
121
|
+
for (const sheet of sheets) {
|
|
122
|
+
// Erroneous sheets will be reported via sentry and the log.
|
|
123
|
+
// We can ignore them here without throwing a fatal error.
|
|
124
|
+
if (!sheet) continue;
|
|
125
|
+
|
|
126
|
+
// Exclude empty stylesheets.
|
|
127
|
+
if (sheet.header.length === 0) {
|
|
128
|
+
continue;
|
|
129
|
+
}
|
|
130
|
+
|
|
131
|
+
dedupedStylesheets.set(sheet.content, sheet);
|
|
132
|
+
}
|
|
133
|
+
|
|
134
|
+
return Array.from(dedupedStylesheets.values());
|
|
135
|
+
}
|
|
136
|
+
}
|
|
137
|
+
|
|
138
|
+
export default Stylesheets;
|
|
@@ -9,37 +9,28 @@ export type TraceElementData = {
|
|
|
9
9
|
type?: string;
|
|
10
10
|
};
|
|
11
11
|
declare class TraceElements extends BaseGatherer {
|
|
12
|
-
/**
|
|
13
|
-
* This function finds the top (up to 15) elements that shift on the page.
|
|
14
|
-
*
|
|
15
|
-
* @param {LH.Trace} trace
|
|
16
|
-
* @param {LH.Gatherer.Context} context
|
|
17
|
-
* @return {Promise<Array<{nodeId: number}>>}
|
|
18
|
-
*/
|
|
19
|
-
static getTopLayoutShiftElements(trace: LH.Trace, context: LH.Gatherer.Context): Promise<Array<{
|
|
20
|
-
nodeId: number;
|
|
21
|
-
}>>;
|
|
22
12
|
/**
|
|
23
13
|
* We want to a single representative node to represent the shift, so let's pick
|
|
24
14
|
* the one with the largest impact (size x distance moved).
|
|
25
15
|
*
|
|
26
16
|
* @param {LH.Artifacts.TraceImpactedNode[]} impactedNodes
|
|
27
17
|
* @param {Map<number, number>} impactByNodeId
|
|
18
|
+
* @param {import('../../lib/trace-engine.js').SaneSyntheticLayoutShift} event Only for debugging
|
|
28
19
|
* @return {number|undefined}
|
|
29
20
|
*/
|
|
30
|
-
static getBiggestImpactNodeForShiftEvent(impactedNodes: LH.Artifacts.TraceImpactedNode[], impactByNodeId: Map<number, number
|
|
21
|
+
static getBiggestImpactNodeForShiftEvent(impactedNodes: LH.Artifacts.TraceImpactedNode[], impactByNodeId: Map<number, number>, event: import('../../lib/trace-engine.js').SaneSyntheticLayoutShift): number | undefined;
|
|
31
22
|
/**
|
|
32
23
|
* This function finds the top (up to 15) layout shifts on the page, and returns
|
|
33
24
|
* the id of the largest impacted node of each shift, along with any related nodes
|
|
34
25
|
* that may have caused the shift.
|
|
35
26
|
*
|
|
36
27
|
* @param {LH.Trace} trace
|
|
37
|
-
* @param {LH.Artifacts.TraceEngineResult} traceEngineResult
|
|
28
|
+
* @param {LH.Artifacts.TraceEngineResult['data']} traceEngineResult
|
|
38
29
|
* @param {LH.Artifacts.TraceEngineRootCauses} rootCauses
|
|
39
30
|
* @param {LH.Gatherer.Context} context
|
|
40
31
|
* @return {Promise<Array<{nodeId: number}>>}
|
|
41
32
|
*/
|
|
42
|
-
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<{
|
|
43
34
|
nodeId: number;
|
|
44
35
|
}>>;
|
|
45
36
|
/**
|