lighthouse 11.7.1 → 12.0.0
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/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-prohibited-attr.d.ts +10 -0
- package/core/audits/accessibility/aria-prohibited-attr.js +44 -0
- package/core/audits/accessibility/target-size.js +0 -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 +1 -1
- 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/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 +2 -12
- package/core/gather/gatherers/trace-elements.js +2 -21
- 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 +28 -0
- 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 +5 -5
- 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 +41 -272
- package/shared/localization/locales/en-XA.json +62 -329
- package/shared/localization/locales/en-XL.json +41 -272
- 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
package/core/config/budget.js
DELETED
|
@@ -1,340 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* @license
|
|
3
|
-
* Copyright 2019 Google LLC
|
|
4
|
-
* SPDX-License-Identifier: Apache-2.0
|
|
5
|
-
*/
|
|
6
|
-
|
|
7
|
-
/**
|
|
8
|
-
* @param {unknown} arr
|
|
9
|
-
* @return {arr is Array<Record<string, unknown>>}
|
|
10
|
-
*/
|
|
11
|
-
function isArrayOfUnknownObjects(arr) {
|
|
12
|
-
return Array.isArray(arr) && arr.every(isObjectOfUnknownProperties);
|
|
13
|
-
}
|
|
14
|
-
|
|
15
|
-
/**
|
|
16
|
-
* @param {unknown} val
|
|
17
|
-
* @return {val is Record<string, unknown>}
|
|
18
|
-
*/
|
|
19
|
-
function isObjectOfUnknownProperties(val) {
|
|
20
|
-
return typeof val === 'object' && val !== null && !Array.isArray(val);
|
|
21
|
-
}
|
|
22
|
-
|
|
23
|
-
/**
|
|
24
|
-
* Returns whether `val` is numeric. Will not coerce to a number. `NaN` will
|
|
25
|
-
* return false, however ±Infinity will return true.
|
|
26
|
-
* @param {unknown} val
|
|
27
|
-
* @return {val is number}
|
|
28
|
-
*/
|
|
29
|
-
function isNumber(val) {
|
|
30
|
-
return typeof val === 'number' && !isNaN(val);
|
|
31
|
-
}
|
|
32
|
-
|
|
33
|
-
class Budget {
|
|
34
|
-
/**
|
|
35
|
-
* Asserts that obj has no own properties, throwing a nice error message if it does.
|
|
36
|
-
* `objectName` is included for nicer logging.
|
|
37
|
-
* @param {Record<string, unknown>} obj
|
|
38
|
-
* @param {string} objectName
|
|
39
|
-
*/
|
|
40
|
-
static assertNoExcessProperties(obj, objectName) {
|
|
41
|
-
const invalidKeys = Object.keys(obj);
|
|
42
|
-
if (invalidKeys.length > 0) {
|
|
43
|
-
const keys = invalidKeys.join(', ');
|
|
44
|
-
throw new Error(`${objectName} has unrecognized properties: [${keys}]`);
|
|
45
|
-
}
|
|
46
|
-
}
|
|
47
|
-
|
|
48
|
-
/**
|
|
49
|
-
* Asserts that `strings` has no duplicate strings in it, throwing an error if
|
|
50
|
-
* it does. `arrayName` is included for nicer logging.
|
|
51
|
-
* @param {Array<string>} strings
|
|
52
|
-
* @param {string} arrayName
|
|
53
|
-
*/
|
|
54
|
-
static assertNoDuplicateStrings(strings, arrayName) {
|
|
55
|
-
const foundStrings = new Set();
|
|
56
|
-
for (const string of strings) {
|
|
57
|
-
if (foundStrings.has(string)) {
|
|
58
|
-
throw new Error(`${arrayName} has duplicate entry of type '${string}'`);
|
|
59
|
-
}
|
|
60
|
-
foundStrings.add(string);
|
|
61
|
-
}
|
|
62
|
-
}
|
|
63
|
-
|
|
64
|
-
/**
|
|
65
|
-
* @param {Record<string, unknown>} resourceBudget
|
|
66
|
-
* @return {LH.Budget.ResourceBudget}
|
|
67
|
-
*/
|
|
68
|
-
static validateResourceBudget(resourceBudget) {
|
|
69
|
-
const {resourceType, budget, ...invalidRest} = resourceBudget;
|
|
70
|
-
Budget.assertNoExcessProperties(invalidRest, 'Resource Budget');
|
|
71
|
-
|
|
72
|
-
/** @type {Array<LH.Budget.ResourceType>} */
|
|
73
|
-
const validResourceTypes = [
|
|
74
|
-
'total',
|
|
75
|
-
'document',
|
|
76
|
-
'script',
|
|
77
|
-
'stylesheet',
|
|
78
|
-
'image',
|
|
79
|
-
'media',
|
|
80
|
-
'font',
|
|
81
|
-
'other',
|
|
82
|
-
'third-party',
|
|
83
|
-
];
|
|
84
|
-
// Assume resourceType is an allowed string, throw if not.
|
|
85
|
-
if (!validResourceTypes.includes(/** @type {LH.Budget.ResourceType} */ (resourceType))) {
|
|
86
|
-
throw new Error(`Invalid resource type: ${resourceType}. \n` +
|
|
87
|
-
`Valid resource types are: ${validResourceTypes.join(', ') }`);
|
|
88
|
-
}
|
|
89
|
-
if (!isNumber(budget)) {
|
|
90
|
-
throw new Error(`Invalid budget: ${budget}`);
|
|
91
|
-
}
|
|
92
|
-
return {
|
|
93
|
-
resourceType: /** @type {LH.Budget.ResourceType} */ (resourceType),
|
|
94
|
-
budget,
|
|
95
|
-
};
|
|
96
|
-
}
|
|
97
|
-
|
|
98
|
-
/**
|
|
99
|
-
* @param {unknown} path
|
|
100
|
-
* @param {string} error
|
|
101
|
-
*/
|
|
102
|
-
static throwInvalidPathError(path, error) {
|
|
103
|
-
throw new Error(`Invalid path ${path}. ${error}\n` +
|
|
104
|
-
`'Path' should be specified using the 'robots.txt' format.\n` +
|
|
105
|
-
`Learn more about the 'robots.txt' format here:\n` +
|
|
106
|
-
`https://developers.google.com/search/reference/robots_txt#url-matching-based-on-path-values`);
|
|
107
|
-
}
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
/**
|
|
111
|
-
* Validates that path is either: a) undefined or ) properly formed.
|
|
112
|
-
* Verifies the quantity and location of the two robot.txt regex characters: $, *
|
|
113
|
-
* @param {unknown} path
|
|
114
|
-
* @return {undefined|string}
|
|
115
|
-
*/
|
|
116
|
-
static validatePath(path) {
|
|
117
|
-
if (path === undefined) {
|
|
118
|
-
return undefined;
|
|
119
|
-
} else if (typeof path !== 'string') {
|
|
120
|
-
this.throwInvalidPathError(path, `Path should be a string.`);
|
|
121
|
-
return;
|
|
122
|
-
} else if (!path.startsWith('/')) {
|
|
123
|
-
this.throwInvalidPathError(path, `Path should start with '/'.`);
|
|
124
|
-
} else if ((path.match(/\*/g) || []).length > 1) {
|
|
125
|
-
this.throwInvalidPathError(path, `Path should only contain one '*'.`);
|
|
126
|
-
} else if ((path.match(/\$/g) || []).length > 1) {
|
|
127
|
-
this.throwInvalidPathError(path, `Path should only contain one '$' character.`);
|
|
128
|
-
} else if (path.includes('$') && !path.endsWith('$')) {
|
|
129
|
-
this.throwInvalidPathError(path, `'$' character should only occur at end of path.`);
|
|
130
|
-
}
|
|
131
|
-
return path;
|
|
132
|
-
}
|
|
133
|
-
|
|
134
|
-
/**
|
|
135
|
-
* Returns the budget that applies to a given URL.
|
|
136
|
-
* If multiple budgets match based on thier 'path' property,
|
|
137
|
-
* then the last-listed of those budgets is returned.
|
|
138
|
-
* @param {LH.Util.Immutable<Array<LH.Budget>>|null} budgets
|
|
139
|
-
* @param {string|undefined} url
|
|
140
|
-
* @return {LH.Util.Immutable<LH.Budget> | undefined} budget
|
|
141
|
-
*/
|
|
142
|
-
static getMatchingBudget(budgets, url) {
|
|
143
|
-
if (budgets === null || url === undefined) return;
|
|
144
|
-
|
|
145
|
-
// Applies the LAST matching budget.
|
|
146
|
-
for (let i = budgets.length - 1; i >= 0; i--) {
|
|
147
|
-
const budget = budgets[i];
|
|
148
|
-
if (this.urlMatchesPattern(url, budget.path)) {
|
|
149
|
-
return budget;
|
|
150
|
-
}
|
|
151
|
-
}
|
|
152
|
-
}
|
|
153
|
-
|
|
154
|
-
/**
|
|
155
|
-
* Determines whether a URL matches against a robots.txt-style "path".
|
|
156
|
-
* Pattern should use the robots.txt format. E.g. "/*-article.html" or "/". Reference:
|
|
157
|
-
* https://developers.google.com/search/reference/robots_txt#url-matching-based-on-path-values
|
|
158
|
-
* @param {string} url
|
|
159
|
-
* @param {string=} pattern
|
|
160
|
-
* @return {boolean}
|
|
161
|
-
*/
|
|
162
|
-
static urlMatchesPattern(url, pattern = '/') {
|
|
163
|
-
const urlObj = new URL(url);
|
|
164
|
-
const urlPath = urlObj.pathname + urlObj.search;
|
|
165
|
-
|
|
166
|
-
const hasWildcard = pattern.includes('*');
|
|
167
|
-
const hasDollarSign = pattern.includes('$');
|
|
168
|
-
|
|
169
|
-
/**
|
|
170
|
-
* There are 4 different cases of path strings.
|
|
171
|
-
* Paths should have already been validated with #validatePath.
|
|
172
|
-
*
|
|
173
|
-
* Case #1: No special characters
|
|
174
|
-
* Example: "/cat"
|
|
175
|
-
* Behavior: URL should start with given pattern.
|
|
176
|
-
*/
|
|
177
|
-
if (!hasWildcard && !hasDollarSign) {
|
|
178
|
-
return urlPath.startsWith(pattern);
|
|
179
|
-
/**
|
|
180
|
-
* Case #2: $ only
|
|
181
|
-
* Example: "/js$"
|
|
182
|
-
* Behavior: URL should be identical to pattern.
|
|
183
|
-
*/
|
|
184
|
-
} else if (!hasWildcard && hasDollarSign) {
|
|
185
|
-
return urlPath === pattern.slice(0, -1);
|
|
186
|
-
/**
|
|
187
|
-
* Case #3: * only
|
|
188
|
-
* Example: "/vendor*chunk"
|
|
189
|
-
* Behavior: URL should start with the string pattern that comes before the wildcard
|
|
190
|
-
* & later in the string contain the string pattern that comes after the wildcard.
|
|
191
|
-
*/
|
|
192
|
-
} else if (hasWildcard && !hasDollarSign) {
|
|
193
|
-
const [beforeWildcard, afterWildcard] = pattern.split('*');
|
|
194
|
-
const remainingUrl = urlPath.slice(beforeWildcard.length);
|
|
195
|
-
return urlPath.startsWith(beforeWildcard) && remainingUrl.includes(afterWildcard);
|
|
196
|
-
/**
|
|
197
|
-
* Case #4: $ and *
|
|
198
|
-
* Example: "/vendor*chunk.js$"
|
|
199
|
-
* Behavior: URL should start with the string pattern that comes before the wildcard
|
|
200
|
-
* & later in the string end with the string pattern that comes after the wildcard.
|
|
201
|
-
*/
|
|
202
|
-
} else if (hasWildcard && hasDollarSign) {
|
|
203
|
-
const [beforeWildcard, afterWildcard] = pattern.split('*');
|
|
204
|
-
const urlEnd = urlPath.slice(beforeWildcard.length);
|
|
205
|
-
return urlPath.startsWith(beforeWildcard) && urlEnd.endsWith(afterWildcard.slice(0, -1));
|
|
206
|
-
}
|
|
207
|
-
return false;
|
|
208
|
-
}
|
|
209
|
-
|
|
210
|
-
/**
|
|
211
|
-
* @param {Record<string, unknown>} timingBudget
|
|
212
|
-
* @return {LH.Budget.TimingBudget}
|
|
213
|
-
*/
|
|
214
|
-
static validateTimingBudget(timingBudget) {
|
|
215
|
-
const {metric, budget, ...invalidRest} = timingBudget;
|
|
216
|
-
Budget.assertNoExcessProperties(invalidRest, 'Timing Budget');
|
|
217
|
-
|
|
218
|
-
/** @type {Array<LH.Budget.TimingMetric>} */
|
|
219
|
-
const validTimingMetrics = [
|
|
220
|
-
'first-contentful-paint',
|
|
221
|
-
'interactive',
|
|
222
|
-
'first-meaningful-paint',
|
|
223
|
-
'max-potential-fid',
|
|
224
|
-
'total-blocking-time',
|
|
225
|
-
'speed-index',
|
|
226
|
-
'largest-contentful-paint',
|
|
227
|
-
'cumulative-layout-shift',
|
|
228
|
-
];
|
|
229
|
-
// Assume metric is an allowed string, throw if not.
|
|
230
|
-
if (!validTimingMetrics.includes(/** @type {LH.Budget.TimingMetric} */ (metric))) {
|
|
231
|
-
throw new Error(`Invalid timing metric: ${metric}. \n` +
|
|
232
|
-
`Valid timing metrics are: ${validTimingMetrics.join(', ')}`);
|
|
233
|
-
}
|
|
234
|
-
if (!isNumber(budget)) {
|
|
235
|
-
throw new Error(`Invalid budget: ${budget}`);
|
|
236
|
-
}
|
|
237
|
-
return {
|
|
238
|
-
metric: /** @type {LH.Budget.TimingMetric} */ (metric),
|
|
239
|
-
budget,
|
|
240
|
-
};
|
|
241
|
-
}
|
|
242
|
-
|
|
243
|
-
/**
|
|
244
|
-
* @param {string} hostname
|
|
245
|
-
* @return {string}
|
|
246
|
-
*/
|
|
247
|
-
static validateHostname(hostname) {
|
|
248
|
-
const errMsg = `${hostname} is not a valid hostname.`;
|
|
249
|
-
if (hostname.length === 0) {
|
|
250
|
-
throw new Error(errMsg);
|
|
251
|
-
}
|
|
252
|
-
if (hostname.includes('/')) {
|
|
253
|
-
throw new Error(errMsg);
|
|
254
|
-
}
|
|
255
|
-
if (hostname.includes(':')) {
|
|
256
|
-
throw new Error(errMsg);
|
|
257
|
-
}
|
|
258
|
-
if (hostname.includes('*')) {
|
|
259
|
-
if (!hostname.startsWith('*.') || hostname.lastIndexOf('*') > 0) {
|
|
260
|
-
throw new Error(errMsg);
|
|
261
|
-
}
|
|
262
|
-
}
|
|
263
|
-
return hostname;
|
|
264
|
-
}
|
|
265
|
-
|
|
266
|
-
/**
|
|
267
|
-
* @param {unknown} hostnames
|
|
268
|
-
* @return {undefined|Array<string>}
|
|
269
|
-
*/
|
|
270
|
-
static validateHostnames(hostnames) {
|
|
271
|
-
if (Array.isArray(hostnames) && hostnames.every(host => typeof host === 'string')) {
|
|
272
|
-
return hostnames.map(Budget.validateHostname);
|
|
273
|
-
} else if (hostnames !== undefined) {
|
|
274
|
-
throw new Error(`firstPartyHostnames should be defined as an array of strings.`);
|
|
275
|
-
}
|
|
276
|
-
}
|
|
277
|
-
|
|
278
|
-
/**
|
|
279
|
-
* More info on the Budget format:
|
|
280
|
-
* https://github.com/GoogleChrome/lighthouse/issues/6053#issuecomment-428385930
|
|
281
|
-
* @param {unknown} budgetJson
|
|
282
|
-
* @return {Array<LH.Budget>}
|
|
283
|
-
*/
|
|
284
|
-
static initializeBudget(budgetJson) {
|
|
285
|
-
// Clone to prevent modifications of original and to deactivate any live properties.
|
|
286
|
-
budgetJson = JSON.parse(JSON.stringify(budgetJson));
|
|
287
|
-
if (!isArrayOfUnknownObjects(budgetJson)) {
|
|
288
|
-
throw new Error('Budget file is not defined as an array of budgets.');
|
|
289
|
-
}
|
|
290
|
-
|
|
291
|
-
const budgets = budgetJson.map((b, index) => {
|
|
292
|
-
/** @type {LH.Budget} */
|
|
293
|
-
const budget = {};
|
|
294
|
-
|
|
295
|
-
const {path, options, resourceSizes, resourceCounts, timings, ...invalidRest} = b;
|
|
296
|
-
Budget.assertNoExcessProperties(invalidRest, 'Budget');
|
|
297
|
-
|
|
298
|
-
budget.path = Budget.validatePath(path);
|
|
299
|
-
|
|
300
|
-
if (isObjectOfUnknownProperties(options)) {
|
|
301
|
-
const {firstPartyHostnames, ...invalidRest} = options;
|
|
302
|
-
Budget.assertNoExcessProperties(invalidRest, 'Options property');
|
|
303
|
-
budget.options = {};
|
|
304
|
-
budget.options.firstPartyHostnames = Budget.validateHostnames(firstPartyHostnames);
|
|
305
|
-
} else if (options !== undefined) {
|
|
306
|
-
throw new Error(`Invalid options property in budget at index ${index}`);
|
|
307
|
-
}
|
|
308
|
-
|
|
309
|
-
if (isArrayOfUnknownObjects(resourceSizes)) {
|
|
310
|
-
budget.resourceSizes = resourceSizes.map(Budget.validateResourceBudget);
|
|
311
|
-
Budget.assertNoDuplicateStrings(budget.resourceSizes.map(r => r.resourceType),
|
|
312
|
-
`budgets[${index}].resourceSizes`);
|
|
313
|
-
} else if (resourceSizes !== undefined) {
|
|
314
|
-
throw new Error(`Invalid resourceSizes entry in budget at index ${index}`);
|
|
315
|
-
}
|
|
316
|
-
|
|
317
|
-
if (isArrayOfUnknownObjects(resourceCounts)) {
|
|
318
|
-
budget.resourceCounts = resourceCounts.map(Budget.validateResourceBudget);
|
|
319
|
-
Budget.assertNoDuplicateStrings(budget.resourceCounts.map(r => r.resourceType),
|
|
320
|
-
`budgets[${index}].resourceCounts`);
|
|
321
|
-
} else if (resourceCounts !== undefined) {
|
|
322
|
-
throw new Error(`Invalid resourceCounts entry in budget at index ${index}`);
|
|
323
|
-
}
|
|
324
|
-
|
|
325
|
-
if (isArrayOfUnknownObjects(timings)) {
|
|
326
|
-
budget.timings = timings.map(Budget.validateTimingBudget);
|
|
327
|
-
Budget.assertNoDuplicateStrings(budget.timings.map(r => r.metric),
|
|
328
|
-
`budgets[${index}].timings`);
|
|
329
|
-
} else if (timings !== undefined) {
|
|
330
|
-
throw new Error(`Invalid timings entry in budget at index ${index}`);
|
|
331
|
-
}
|
|
332
|
-
|
|
333
|
-
return budget;
|
|
334
|
-
});
|
|
335
|
-
|
|
336
|
-
return budgets;
|
|
337
|
-
}
|
|
338
|
-
}
|
|
339
|
-
|
|
340
|
-
export {Budget};
|
|
@@ -1,19 +0,0 @@
|
|
|
1
|
-
export namespace metricsToAudits {
|
|
2
|
-
export { fcpRelevantAudits };
|
|
3
|
-
export { lcpRelevantAudits };
|
|
4
|
-
export { tbtRelevantAudits };
|
|
5
|
-
export { clsRelevantAudits };
|
|
6
|
-
export { inpRelevantAudits };
|
|
7
|
-
}
|
|
8
|
-
/**
|
|
9
|
-
* @license
|
|
10
|
-
* Copyright 2021 Google LLC
|
|
11
|
-
* SPDX-License-Identifier: Apache-2.0
|
|
12
|
-
*/
|
|
13
|
-
declare const fcpRelevantAudits: string[];
|
|
14
|
-
declare const lcpRelevantAudits: string[];
|
|
15
|
-
declare const tbtRelevantAudits: string[];
|
|
16
|
-
declare const clsRelevantAudits: string[];
|
|
17
|
-
declare const inpRelevantAudits: string[];
|
|
18
|
-
export {};
|
|
19
|
-
//# sourceMappingURL=metrics-to-audits.d.ts.map
|
|
@@ -1,62 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* @license
|
|
3
|
-
* Copyright 2021 Google LLC
|
|
4
|
-
* SPDX-License-Identifier: Apache-2.0
|
|
5
|
-
*/
|
|
6
|
-
|
|
7
|
-
// go/lh-audit-metric-mapping
|
|
8
|
-
const fcpRelevantAudits = [
|
|
9
|
-
'server-response-time',
|
|
10
|
-
'render-blocking-resources',
|
|
11
|
-
'redirects',
|
|
12
|
-
'critical-request-chains',
|
|
13
|
-
'uses-text-compression',
|
|
14
|
-
'uses-rel-preconnect',
|
|
15
|
-
'uses-rel-preload',
|
|
16
|
-
'font-display',
|
|
17
|
-
'unminified-javascript',
|
|
18
|
-
'unminified-css',
|
|
19
|
-
'unused-css-rules',
|
|
20
|
-
];
|
|
21
|
-
|
|
22
|
-
const lcpRelevantAudits = [
|
|
23
|
-
...fcpRelevantAudits,
|
|
24
|
-
'largest-contentful-paint-element',
|
|
25
|
-
'prioritize-lcp-image',
|
|
26
|
-
'unused-javascript',
|
|
27
|
-
'efficient-animated-content',
|
|
28
|
-
'total-byte-weight',
|
|
29
|
-
'lcp-lazy-loaded',
|
|
30
|
-
];
|
|
31
|
-
|
|
32
|
-
const tbtRelevantAudits = [
|
|
33
|
-
'long-tasks',
|
|
34
|
-
'third-party-summary',
|
|
35
|
-
'third-party-facades',
|
|
36
|
-
'bootup-time',
|
|
37
|
-
'mainthread-work-breakdown',
|
|
38
|
-
'dom-size',
|
|
39
|
-
'duplicated-javascript',
|
|
40
|
-
'legacy-javascript',
|
|
41
|
-
'viewport',
|
|
42
|
-
];
|
|
43
|
-
|
|
44
|
-
const clsRelevantAudits = [
|
|
45
|
-
'layout-shift-elements',
|
|
46
|
-
'layout-shifts',
|
|
47
|
-
'non-composited-animations',
|
|
48
|
-
'unsized-images',
|
|
49
|
-
// 'preload-fonts', // actually in BP, rather than perf
|
|
50
|
-
];
|
|
51
|
-
|
|
52
|
-
const inpRelevantAudits = [
|
|
53
|
-
'work-during-interaction',
|
|
54
|
-
];
|
|
55
|
-
|
|
56
|
-
export const metricsToAudits = {
|
|
57
|
-
fcpRelevantAudits,
|
|
58
|
-
lcpRelevantAudits,
|
|
59
|
-
tbtRelevantAudits,
|
|
60
|
-
clsRelevantAudits,
|
|
61
|
-
inpRelevantAudits,
|
|
62
|
-
};
|
|
@@ -1,16 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* @license
|
|
3
|
-
* Copyright 2021 Google LLC
|
|
4
|
-
* SPDX-License-Identifier: Apache-2.0
|
|
5
|
-
*/
|
|
6
|
-
/**
|
|
7
|
-
* @param {LH.Gatherer.ProtocolSession} session
|
|
8
|
-
* @return {Promise<LH.Crdp.ServiceWorker.WorkerVersionUpdatedEvent>}
|
|
9
|
-
*/
|
|
10
|
-
export function getServiceWorkerVersions(session: LH.Gatherer.ProtocolSession): Promise<LH.Crdp.ServiceWorker.WorkerVersionUpdatedEvent>;
|
|
11
|
-
/**
|
|
12
|
-
* @param {LH.Gatherer.ProtocolSession} session
|
|
13
|
-
* @return {Promise<LH.Crdp.ServiceWorker.WorkerRegistrationUpdatedEvent>}
|
|
14
|
-
*/
|
|
15
|
-
export function getServiceWorkerRegistrations(session: LH.Gatherer.ProtocolSession): Promise<LH.Crdp.ServiceWorker.WorkerRegistrationUpdatedEvent>;
|
|
16
|
-
//# sourceMappingURL=service-workers.d.ts.map
|
|
@@ -1,52 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* @license
|
|
3
|
-
* Copyright 2021 Google LLC
|
|
4
|
-
* SPDX-License-Identifier: Apache-2.0
|
|
5
|
-
*/
|
|
6
|
-
|
|
7
|
-
/**
|
|
8
|
-
* @param {LH.Gatherer.ProtocolSession} session
|
|
9
|
-
* @return {Promise<LH.Crdp.ServiceWorker.WorkerVersionUpdatedEvent>}
|
|
10
|
-
*/
|
|
11
|
-
function getServiceWorkerVersions(session) {
|
|
12
|
-
return new Promise((resolve, reject) => {
|
|
13
|
-
/**
|
|
14
|
-
* @param {LH.Crdp.ServiceWorker.WorkerVersionUpdatedEvent} data
|
|
15
|
-
*/
|
|
16
|
-
const versionUpdatedListener = data => {
|
|
17
|
-
// find a service worker with runningStatus that looks like active
|
|
18
|
-
// on slow connections the serviceworker might still be installing
|
|
19
|
-
const activateCandidates = data.versions.filter(sw => {
|
|
20
|
-
return sw.status !== 'redundant';
|
|
21
|
-
});
|
|
22
|
-
|
|
23
|
-
const hasActiveServiceWorker = activateCandidates.find(sw => {
|
|
24
|
-
return sw.status === 'activated';
|
|
25
|
-
});
|
|
26
|
-
|
|
27
|
-
if (!activateCandidates.length || hasActiveServiceWorker) {
|
|
28
|
-
session.off('ServiceWorker.workerVersionUpdated', versionUpdatedListener);
|
|
29
|
-
session.sendCommand('ServiceWorker.disable').then(_ => resolve(data), reject);
|
|
30
|
-
}
|
|
31
|
-
};
|
|
32
|
-
|
|
33
|
-
session.on('ServiceWorker.workerVersionUpdated', versionUpdatedListener);
|
|
34
|
-
|
|
35
|
-
session.sendCommand('ServiceWorker.enable').catch(reject);
|
|
36
|
-
});
|
|
37
|
-
}
|
|
38
|
-
|
|
39
|
-
/**
|
|
40
|
-
* @param {LH.Gatherer.ProtocolSession} session
|
|
41
|
-
* @return {Promise<LH.Crdp.ServiceWorker.WorkerRegistrationUpdatedEvent>}
|
|
42
|
-
*/
|
|
43
|
-
function getServiceWorkerRegistrations(session) {
|
|
44
|
-
return new Promise((resolve, reject) => {
|
|
45
|
-
session.once('ServiceWorker.workerRegistrationUpdated', data => {
|
|
46
|
-
session.sendCommand('ServiceWorker.disable').then(_ => resolve(data), reject);
|
|
47
|
-
});
|
|
48
|
-
session.sendCommand('ServiceWorker.enable').catch(reject);
|
|
49
|
-
});
|
|
50
|
-
}
|
|
51
|
-
|
|
52
|
-
export {getServiceWorkerVersions, getServiceWorkerRegistrations};
|
|
@@ -1,47 +0,0 @@
|
|
|
1
|
-
export default TagsBlockingFirstPaint;
|
|
2
|
-
export type MediaChange = {
|
|
3
|
-
href: string;
|
|
4
|
-
media: string;
|
|
5
|
-
msSinceHTMLEnd: number;
|
|
6
|
-
matches: boolean;
|
|
7
|
-
};
|
|
8
|
-
export type LinkTag = {
|
|
9
|
-
tagName: 'LINK';
|
|
10
|
-
url: string;
|
|
11
|
-
href: string;
|
|
12
|
-
rel: string;
|
|
13
|
-
media: string;
|
|
14
|
-
disabled: boolean;
|
|
15
|
-
mediaChanges: Array<MediaChange>;
|
|
16
|
-
};
|
|
17
|
-
export type ScriptTag = {
|
|
18
|
-
tagName: 'SCRIPT';
|
|
19
|
-
url: string;
|
|
20
|
-
src: string;
|
|
21
|
-
};
|
|
22
|
-
declare class TagsBlockingFirstPaint extends BaseGatherer {
|
|
23
|
-
/**
|
|
24
|
-
* @param {Array<LH.Artifacts.NetworkRequest>} networkRecords
|
|
25
|
-
* @return {Map<string, LH.Artifacts.NetworkRequest>}
|
|
26
|
-
*/
|
|
27
|
-
static _filteredAndIndexedByUrl(networkRecords: Array<LH.Artifacts.NetworkRequest>): Map<string, LH.Artifacts.NetworkRequest>;
|
|
28
|
-
/**
|
|
29
|
-
* @param {LH.Gatherer.Driver} driver
|
|
30
|
-
* @param {Array<LH.Artifacts.NetworkRequest>} networkRecords
|
|
31
|
-
* @return {Promise<Array<LH.Artifacts.TagBlockingFirstPaint>>}
|
|
32
|
-
*/
|
|
33
|
-
static findBlockingTags(driver: LH.Gatherer.Driver, networkRecords: Array<LH.Artifacts.NetworkRequest>): Promise<Array<LH.Artifacts.TagBlockingFirstPaint>>;
|
|
34
|
-
/** @type {LH.Gatherer.GathererMeta<'DevtoolsLog'>} */
|
|
35
|
-
meta: LH.Gatherer.GathererMeta<'DevtoolsLog'>;
|
|
36
|
-
/**
|
|
37
|
-
* @param {LH.Gatherer.Context} context
|
|
38
|
-
*/
|
|
39
|
-
startSensitiveInstrumentation(context: LH.Gatherer.Context): Promise<void>;
|
|
40
|
-
/**
|
|
41
|
-
* @param {LH.Gatherer.Context<'DevtoolsLog'>} context
|
|
42
|
-
* @return {Promise<LH.Artifacts['TagsBlockingFirstPaint']>}
|
|
43
|
-
*/
|
|
44
|
-
getArtifact(context: LH.Gatherer.Context<'DevtoolsLog'>): Promise<LH.Artifacts['TagsBlockingFirstPaint']>;
|
|
45
|
-
}
|
|
46
|
-
import BaseGatherer from '../../base-gatherer.js';
|
|
47
|
-
//# sourceMappingURL=tags-blocking-first-paint.d.ts.map
|