lighthouse 8.6.0-dev.20211101 → 8.6.0-dev.20211105
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/dist/report/flow.js +14 -14
- package/dist/report/standalone.js +41 -35
- package/flow-report/.eslintrc.cjs +2 -0
- package/flow-report/assets/standalone-flow-template.html +3 -2
- package/flow-report/assets/styles.css +1 -1
- package/flow-report/src/common.tsx +11 -4
- package/flow-report/src/i18n/i18n.tsx +10 -6
- package/flow-report/src/icons.tsx +30 -9
- package/flow-report/src/sidebar/sidebar.tsx +27 -8
- package/flow-report/src/summary/category.tsx +7 -2
- package/flow-report/src/summary/summary.tsx +9 -3
- package/flow-report/src/util.ts +21 -9
- package/flow-report/src/wrappers/report-renderer.tsx +10 -3
- package/flow-report/src/wrappers/report.tsx +9 -5
- package/flow-report/standalone-flow.tsx +4 -3
- package/flow-report/test/setup/env-setup.ts +1 -1
- package/flow-report/test/sidebar/sidebar-test.tsx +43 -1
- package/lighthouse-cli/.eslintrc.cjs +2 -0
- package/lighthouse-cli/cli-flags.js +1 -1
- package/lighthouse-core/audits/audit.js +1 -1
- package/lighthouse-core/computed/resource-summary.js +1 -1
- package/lighthouse-core/config/default-config.js +0 -2
- package/lighthouse-core/gather/connections/cri.js +1 -1
- package/lighthouse-core/lib/proto-preprocessor.js +14 -2
- package/lighthouse-core/lib/url-shim.js +1 -1
- package/lighthouse-core/util-commonjs.js +24 -9
- package/package.json +3 -3
- package/report/.eslintrc.cjs +2 -0
- package/report/assets/standalone-template.html +2 -3
- package/report/assets/styles.css +227 -251
- package/report/assets/templates.html +19 -29
- package/report/clients/bundle.js +1 -0
- package/report/clients/standalone.js +6 -13
- package/report/renderer/api.js +32 -0
- package/report/renderer/category-renderer.js +22 -18
- package/report/renderer/components.js +46 -79
- package/report/renderer/crc-details-renderer.js +15 -12
- package/report/renderer/dom.js +16 -1
- package/report/renderer/drop-down-menu.js +2 -2
- package/report/renderer/element-screenshot-renderer.js +6 -6
- package/report/renderer/features-util.js +1 -1
- package/report/renderer/open-tab.js +9 -3
- package/report/renderer/performance-category-renderer.js +31 -19
- package/report/renderer/report-renderer.js +34 -10
- package/report/renderer/report-ui-features.js +36 -33
- package/report/renderer/swap-locale-feature.js +3 -3
- package/report/renderer/topbar-features.js +52 -48
- package/report/renderer/util.js +25 -9
- package/report/test/clients/bundle-test.js +8 -0
- package/report/test/renderer/category-renderer-test.js +2 -2
- package/report/test/renderer/performance-category-renderer-test.js +1 -1
- package/report/test/renderer/report-renderer-axe-test.js +5 -2
- package/report/test/renderer/report-renderer-test.js +13 -10
- package/report/test/renderer/report-ui-features-test.js +17 -10
- package/report/test-assets/faux-psi-template.html +2 -7
- package/report/test-assets/faux-psi.js +20 -39
- package/report/types/html-renderer.d.ts +2 -0
- package/report/types/report-renderer.d.ts +23 -0
- package/shared/localization/locales/ar-XB.json +0 -15
- package/shared/localization/locales/ar.json +0 -15
- package/shared/localization/locales/bg.json +0 -15
- package/shared/localization/locales/ca.json +0 -15
- package/shared/localization/locales/cs.json +0 -15
- package/shared/localization/locales/da.json +0 -15
- package/shared/localization/locales/de.json +0 -15
- package/shared/localization/locales/el.json +0 -15
- package/shared/localization/locales/en-GB.json +0 -15
- package/shared/localization/locales/en-US.json +18 -15
- package/shared/localization/locales/en-XA.json +0 -15
- package/shared/localization/locales/en-XL.json +18 -15
- package/shared/localization/locales/es-419.json +0 -15
- package/shared/localization/locales/es.json +0 -15
- package/shared/localization/locales/fi.json +0 -15
- package/shared/localization/locales/fil.json +0 -15
- package/shared/localization/locales/fr.json +0 -15
- package/shared/localization/locales/he.json +0 -15
- package/shared/localization/locales/hi.json +0 -15
- package/shared/localization/locales/hr.json +0 -15
- package/shared/localization/locales/hu.json +0 -15
- package/shared/localization/locales/id.json +0 -15
- package/shared/localization/locales/it.json +0 -15
- package/shared/localization/locales/ja.json +0 -15
- package/shared/localization/locales/ko.json +0 -15
- package/shared/localization/locales/lt.json +0 -15
- package/shared/localization/locales/lv.json +0 -15
- package/shared/localization/locales/nl.json +0 -15
- package/shared/localization/locales/no.json +0 -15
- package/shared/localization/locales/pl.json +0 -15
- package/shared/localization/locales/pt-PT.json +0 -15
- package/shared/localization/locales/pt.json +0 -15
- package/shared/localization/locales/ro.json +0 -15
- package/shared/localization/locales/ru.json +0 -15
- package/shared/localization/locales/sk.json +0 -15
- package/shared/localization/locales/sl.json +0 -15
- package/shared/localization/locales/sr-Latn.json +0 -15
- package/shared/localization/locales/sr.json +0 -15
- package/shared/localization/locales/sv.json +0 -15
- package/shared/localization/locales/ta.json +0 -15
- package/shared/localization/locales/te.json +0 -15
- package/shared/localization/locales/th.json +0 -15
- package/shared/localization/locales/tr.json +0 -15
- package/shared/localization/locales/uk.json +0 -15
- package/shared/localization/locales/vi.json +0 -15
- package/shared/localization/locales/zh-HK.json +0 -15
- package/shared/localization/locales/zh-TW.json +0 -15
- package/shared/localization/locales/zh.json +0 -15
- package/lighthouse-core/audits/dobetterweb/external-anchors-use-rel-noopener.js +0 -96
|
@@ -23,11 +23,12 @@ limitations under the License.
|
|
|
23
23
|
<title>Lighthouse Flow Report</title>
|
|
24
24
|
<style>/*%%LIGHTHOUSE_CSS%%*/</style>
|
|
25
25
|
<style>/*%%LIGHTHOUSE_FLOW_CSS%%*/</style>
|
|
26
|
+
<style>body {margin: 0}</style>
|
|
26
27
|
</head>
|
|
27
|
-
<body
|
|
28
|
+
<body>
|
|
28
29
|
<noscript>Lighthouse report requires JavaScript. Please enable.</noscript>
|
|
29
30
|
|
|
30
|
-
<main><!-- report populated here --></main>
|
|
31
|
+
<main class="flow-vars lh-root lh-vars"><!-- report populated here --></main>
|
|
31
32
|
|
|
32
33
|
<script>window.__LIGHTHOUSE_FLOW_JSON__ = %%LIGHTHOUSE_FLOW_JSON%%;</script>
|
|
33
34
|
<script>%%LIGHTHOUSE_FLOW_JAVASCRIPT%%
|
|
@@ -297,7 +297,7 @@
|
|
|
297
297
|
|
|
298
298
|
.SummaryFlow {
|
|
299
299
|
display: grid;
|
|
300
|
-
max-width: var(--report-width);
|
|
300
|
+
max-width: var(--report-content-width);
|
|
301
301
|
grid-auto-rows: min-content;
|
|
302
302
|
grid-template-columns: min-content min-content minmax(var(--min-text-width), max-content) 1fr 1fr 1fr 1fr;
|
|
303
303
|
align-items: center;
|
|
@@ -12,11 +12,11 @@ import {getFilmstripFrames, getScreenDimensions, getFullPageScreenshot} from './
|
|
|
12
12
|
|
|
13
13
|
const ANIMATION_FRAME_DURATION_MS = 500;
|
|
14
14
|
|
|
15
|
-
|
|
15
|
+
const Separator: FunctionComponent = () => {
|
|
16
16
|
return <div className="Separator" role="separator"></div>;
|
|
17
17
|
};
|
|
18
18
|
|
|
19
|
-
|
|
19
|
+
const FlowStepIcon: FunctionComponent<{mode: LH.Result.GatherMode}> = ({mode}) => {
|
|
20
20
|
return <>
|
|
21
21
|
{
|
|
22
22
|
mode === 'navigation' && <NavigationIcon/>
|
|
@@ -30,7 +30,7 @@ export const FlowStepIcon: FunctionComponent<{mode: LH.Result.GatherMode}> = ({m
|
|
|
30
30
|
</>;
|
|
31
31
|
};
|
|
32
32
|
|
|
33
|
-
|
|
33
|
+
const FlowSegment: FunctionComponent<{mode?: LH.Result.GatherMode}> = ({mode}) => {
|
|
34
34
|
return (
|
|
35
35
|
<div className="FlowSegment">
|
|
36
36
|
<div className="FlowSegment__top-line"/>
|
|
@@ -71,7 +71,7 @@ const FlowStepAnimatedThumbnail: FunctionComponent<{
|
|
|
71
71
|
);
|
|
72
72
|
};
|
|
73
73
|
|
|
74
|
-
|
|
74
|
+
const FlowStepThumbnail: FunctionComponent<{
|
|
75
75
|
lhr: LH.Result,
|
|
76
76
|
width?: number,
|
|
77
77
|
height?: number,
|
|
@@ -114,3 +114,10 @@ export const FlowStepThumbnail: FunctionComponent<{
|
|
|
114
114
|
}
|
|
115
115
|
</>;
|
|
116
116
|
};
|
|
117
|
+
|
|
118
|
+
export {
|
|
119
|
+
Separator,
|
|
120
|
+
FlowStepIcon,
|
|
121
|
+
FlowSegment,
|
|
122
|
+
FlowStepThumbnail,
|
|
123
|
+
};
|
|
@@ -31,23 +31,23 @@ function useLhrLocale() {
|
|
|
31
31
|
};
|
|
32
32
|
}
|
|
33
33
|
|
|
34
|
-
|
|
34
|
+
function useI18n() {
|
|
35
35
|
return useContext(I18nContext);
|
|
36
36
|
}
|
|
37
37
|
|
|
38
|
-
|
|
38
|
+
function useLocalizedStrings() {
|
|
39
39
|
const i18n = useI18n();
|
|
40
40
|
return i18n.strings;
|
|
41
41
|
}
|
|
42
42
|
|
|
43
|
-
|
|
43
|
+
function useStringFormatter() {
|
|
44
44
|
const {locale} = useLhrLocale();
|
|
45
45
|
return (str: string, values?: Record<string, string|number>) => {
|
|
46
46
|
return formatMessage(str, values, locale);
|
|
47
47
|
};
|
|
48
48
|
}
|
|
49
49
|
|
|
50
|
-
|
|
50
|
+
const I18nProvider: FunctionComponent = ({children}) => {
|
|
51
51
|
const {locale, lhrStrings} = useLhrLocale();
|
|
52
52
|
|
|
53
53
|
const i18n = useMemo(() => {
|
|
@@ -65,7 +65,6 @@ export const I18nProvider: FunctionComponent = ({children}) => {
|
|
|
65
65
|
|
|
66
66
|
// Initialize renderer util i18n for strings rendered in wrapped components.
|
|
67
67
|
// TODO: Don't attach global i18n to `Util`.
|
|
68
|
-
// @ts-ignore TS reports as read-only.
|
|
69
68
|
Util.i18n = i18n;
|
|
70
69
|
|
|
71
70
|
return i18n;
|
|
@@ -78,4 +77,9 @@ export const I18nProvider: FunctionComponent = ({children}) => {
|
|
|
78
77
|
);
|
|
79
78
|
};
|
|
80
79
|
|
|
81
|
-
|
|
80
|
+
export {
|
|
81
|
+
useI18n,
|
|
82
|
+
useLocalizedStrings,
|
|
83
|
+
useStringFormatter,
|
|
84
|
+
I18nProvider,
|
|
85
|
+
};
|
|
@@ -8,7 +8,7 @@ import {FunctionComponent} from 'preact';
|
|
|
8
8
|
|
|
9
9
|
/* eslint-disable max-len */
|
|
10
10
|
|
|
11
|
-
|
|
11
|
+
const SummaryIcon: FunctionComponent = () => {
|
|
12
12
|
return (
|
|
13
13
|
<svg width="14" viewBox="0 0 18 16" fill="none" role="img">
|
|
14
14
|
<path fill-rule="evenodd" clip-rule="evenodd" d="M0 2C0 1.17 0.67 0.5 1.5 0.5C2.33 0.5 3 1.17 3 2C3 2.83 2.33 3.5 1.5 3.5C0.67 3.5 0 2.83 0 2ZM0 8C0 7.17 0.67 6.5 1.5 6.5C2.33 6.5 3 7.17 3 8C3 8.83 2.33 9.5 1.5 9.5C0.67 9.5 0 8.83 0 8ZM1.5 12.5C0.67 12.5 0 13.18 0 14C0 14.82 0.68 15.5 1.5 15.5C2.32 15.5 3 14.82 3 14C3 13.18 2.33 12.5 1.5 12.5ZM18 15H5V13H18V15ZM5 9H18V7H5V9ZM5 3V1H18V3H5Z" fill="currentColor"/>
|
|
@@ -16,7 +16,7 @@ export const SummaryIcon: FunctionComponent = () => {
|
|
|
16
16
|
);
|
|
17
17
|
};
|
|
18
18
|
|
|
19
|
-
|
|
19
|
+
const NavigationIcon: FunctionComponent = () => {
|
|
20
20
|
return (
|
|
21
21
|
<svg
|
|
22
22
|
width="16"
|
|
@@ -36,7 +36,7 @@ export const NavigationIcon: FunctionComponent = () => {
|
|
|
36
36
|
);
|
|
37
37
|
};
|
|
38
38
|
|
|
39
|
-
|
|
39
|
+
const TimespanIcon: FunctionComponent = () => {
|
|
40
40
|
return (
|
|
41
41
|
<svg
|
|
42
42
|
width="16"
|
|
@@ -60,7 +60,7 @@ export const TimespanIcon: FunctionComponent = () => {
|
|
|
60
60
|
);
|
|
61
61
|
};
|
|
62
62
|
|
|
63
|
-
|
|
63
|
+
const SnapshotIcon: FunctionComponent = () => {
|
|
64
64
|
return (
|
|
65
65
|
<svg
|
|
66
66
|
xmlns="http://www.w3.org/2000/svg"
|
|
@@ -79,7 +79,7 @@ export const SnapshotIcon: FunctionComponent = () => {
|
|
|
79
79
|
);
|
|
80
80
|
};
|
|
81
81
|
|
|
82
|
-
|
|
82
|
+
const CloseIcon: FunctionComponent = () => {
|
|
83
83
|
return (
|
|
84
84
|
<svg
|
|
85
85
|
xmlns="http://www.w3.org/2000/svg"
|
|
@@ -96,7 +96,7 @@ export const CloseIcon: FunctionComponent = () => {
|
|
|
96
96
|
);
|
|
97
97
|
};
|
|
98
98
|
|
|
99
|
-
|
|
99
|
+
const EnvIcon: FunctionComponent = () => {
|
|
100
100
|
return (
|
|
101
101
|
<svg width="15" height="12" viewBox="0 0 15 12" fill="none" role="img">
|
|
102
102
|
<path fill-rule="evenodd" clip-rule="evenodd" d="M3.33317 2.00008H13.9998V0.666748H3.33317C2.59984 0.666748 1.99984 1.26675 1.99984 2.00008V9.33341H0.666504V11.3334H7.99984V9.33341H3.33317V2.00008ZM13.9998 3.33341H9.99984C9.63317 3.33341 9.33317 3.63341 9.33317 4.00008V10.6667C9.33317 11.0334 9.63317 11.3334 9.99984 11.3334H13.9998C14.3665 11.3334 14.6665 11.0334 14.6665 10.6667V4.00008C14.6665 3.63341 14.3665 3.33341 13.9998 3.33341ZM10.6665 9.33341H13.3332V4.66675H10.6665V9.33341Z" fill="currentColor"/>
|
|
@@ -104,7 +104,15 @@ export const EnvIcon: FunctionComponent = () => {
|
|
|
104
104
|
);
|
|
105
105
|
};
|
|
106
106
|
|
|
107
|
-
|
|
107
|
+
const NetworkIcon: FunctionComponent = () => {
|
|
108
|
+
return (
|
|
109
|
+
<svg width="16" height="11" viewBox="0 0 16 11" fill="none" role="img">
|
|
110
|
+
<path fill-rule="evenodd" clip-rule="evenodd" d="M0.666687 3.26663L2.00002 4.59997C3.92002 2.67997 6.52669 1.87997 9.02002 2.18663L9.81335 0.399966C6.59335 -0.173367 3.16002 0.779966 0.666687 3.26663ZM10.6 0.599966C10.4867 0.599966 10.3867 0.659966 10.3267 0.753299L10.28 0.853299L6.82669 8.61996C6.72002 8.8133 6.65335 9.02663 6.65335 9.25996C6.65335 9.99996 7.25335 10.6 7.99335 10.6C8.63335 10.6 9.17335 10.1466 9.30002 9.53996L9.30669 9.51997L10.9334 0.933299C10.9334 0.746633 10.7867 0.599966 10.6 0.599966ZM15.3334 3.26663L14 4.59997C13.1867 3.78663 12.2534 3.17997 11.2534 2.76663L11.6067 0.886633C12.9667 1.38663 14.24 2.1733 15.3334 3.26663ZM11.3334 7.26663L12.6667 5.9333C12.1334 5.39997 11.5334 4.98663 10.8934 4.6733L10.5267 6.61997C10.8067 6.79997 11.08 7.0133 11.3334 7.26663ZM4.66669 7.26663L3.33335 5.9333C4.67335 4.5933 6.45335 3.95997 8.20669 4.0133L7.35335 5.9333C6.37335 6.0733 5.42002 6.5133 4.66669 7.26663Z" fill="currentColor"/>
|
|
111
|
+
</svg>
|
|
112
|
+
);
|
|
113
|
+
};
|
|
114
|
+
|
|
115
|
+
const CpuIcon: FunctionComponent = () => {
|
|
108
116
|
return (
|
|
109
117
|
<svg width="16" height="16" viewBox="0 0 16 16" fill="none" role="img">
|
|
110
118
|
<path fill-rule="evenodd" clip-rule="evenodd" d="M15.5 7.16667V5.5H13.8333V3.83333C13.8333 2.91667 13.0833 2.16667 12.1667 2.16667H10.5V0.5H8.83333V2.16667H7.16667V0.5H5.5V2.16667H3.83333C2.91667 2.16667 2.16667 2.91667 2.16667 3.83333V5.5H0.5V7.16667H2.16667V8.83333H0.5V10.5H2.16667V12.1667C2.16667 13.0833 2.91667 13.8333 3.83333 13.8333H5.5V15.5H7.16667V13.8333H8.83333V15.5H10.5V13.8333H12.1667C13.0833 13.8333 13.8333 13.0833 13.8333 12.1667V10.5H15.5V8.83333H13.8333V7.16667H15.5ZM10.5 5.5H5.5V10.5H10.5V5.5ZM3.83333 12.1667H12.1667V3.83333H3.83333V12.1667Z" fill="currentColor"/>
|
|
@@ -112,7 +120,7 @@ export const CpuIcon: FunctionComponent = () => {
|
|
|
112
120
|
);
|
|
113
121
|
};
|
|
114
122
|
|
|
115
|
-
|
|
123
|
+
const HamburgerIcon: FunctionComponent = () => {
|
|
116
124
|
return (
|
|
117
125
|
<svg viewBox="0 0 18 12" width="18" height="12" role="img">
|
|
118
126
|
<rect width="18" height="2" fill="currentColor"></rect>
|
|
@@ -122,10 +130,23 @@ export const HamburgerIcon: FunctionComponent = () => {
|
|
|
122
130
|
);
|
|
123
131
|
};
|
|
124
132
|
|
|
125
|
-
|
|
133
|
+
const InfoIcon: FunctionComponent = () => {
|
|
126
134
|
return (
|
|
127
135
|
<svg width="14" height="14" viewBox="0 0 14 14" fill="none">
|
|
128
136
|
<path fill-rule="evenodd" clip-rule="evenodd" d="M13 7C13 10.3137 10.3137 13 7 13C3.68629 13 1 10.3137 1 7C1 3.68629 3.68629 1 7 1C10.3137 1 13 3.68629 13 7ZM14 7C14 10.866 10.866 14 7 14C3.13401 14 0 10.866 0 7C0 3.13401 3.13401 0 7 0C10.866 0 14 3.13401 14 7ZM7.66658 11H6.33325V9.66667H7.66658V11ZM4.33325 5.66667C4.33325 4.19333 5.52659 3 6.99992 3C8.47325 3 9.66658 4.19333 9.66658 5.66667C9.66658 6.52194 9.1399 6.98221 8.62709 7.43036C8.1406 7.85551 7.66658 8.26975 7.66658 9H6.33325C6.33325 7.78582 6.96133 7.30439 7.51355 6.88112C7.94674 6.54907 8.33325 6.25281 8.33325 5.66667C8.33325 4.93333 7.73325 4.33333 6.99992 4.33333C6.26658 4.33333 5.66658 4.93333 5.66658 5.66667H4.33325Z" fill="currentColor"/>
|
|
129
137
|
</svg>
|
|
130
138
|
);
|
|
131
139
|
};
|
|
140
|
+
|
|
141
|
+
export {
|
|
142
|
+
SummaryIcon,
|
|
143
|
+
NavigationIcon,
|
|
144
|
+
TimespanIcon,
|
|
145
|
+
SnapshotIcon,
|
|
146
|
+
CloseIcon,
|
|
147
|
+
EnvIcon,
|
|
148
|
+
NetworkIcon,
|
|
149
|
+
CpuIcon,
|
|
150
|
+
HamburgerIcon,
|
|
151
|
+
InfoIcon,
|
|
152
|
+
};
|
|
@@ -6,13 +6,14 @@
|
|
|
6
6
|
|
|
7
7
|
import {FunctionComponent} from 'preact';
|
|
8
8
|
|
|
9
|
+
import {Util} from '../../../report/renderer/util';
|
|
9
10
|
import {Separator} from '../common';
|
|
10
11
|
import {useI18n, useLocalizedStrings} from '../i18n/i18n';
|
|
11
|
-
import {CpuIcon, EnvIcon, SummaryIcon} from '../icons';
|
|
12
|
+
import {CpuIcon, EnvIcon, NetworkIcon, SummaryIcon} from '../icons';
|
|
12
13
|
import {classNames, useHashState, useFlowResult} from '../util';
|
|
13
14
|
import {SidebarFlow} from './flow';
|
|
14
15
|
|
|
15
|
-
|
|
16
|
+
const SidebarSummary: FunctionComponent = () => {
|
|
16
17
|
const hashState = useHashState();
|
|
17
18
|
const strings = useLocalizedStrings();
|
|
18
19
|
|
|
@@ -32,8 +33,10 @@ export const SidebarSummary: FunctionComponent = () => {
|
|
|
32
33
|
);
|
|
33
34
|
};
|
|
34
35
|
|
|
35
|
-
const SidebarRuntimeSettings: FunctionComponent<{settings: LH.ConfigSettings}> =
|
|
36
|
+
const SidebarRuntimeSettings: FunctionComponent<{settings: LH.ConfigSettings}> =
|
|
37
|
+
({settings}) => {
|
|
36
38
|
const strings = useLocalizedStrings();
|
|
39
|
+
const env = Util.getEmulationDescriptions(settings);
|
|
37
40
|
|
|
38
41
|
return (
|
|
39
42
|
<div className="SidebarRuntimeSettings">
|
|
@@ -42,9 +45,18 @@ const SidebarRuntimeSettings: FunctionComponent<{settings: LH.ConfigSettings}> =
|
|
|
42
45
|
<EnvIcon/>
|
|
43
46
|
</div>
|
|
44
47
|
{
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
+
env.deviceEmulation
|
|
49
|
+
}
|
|
50
|
+
</div>
|
|
51
|
+
<div
|
|
52
|
+
className="SidebarRuntimeSettings__item"
|
|
53
|
+
title={strings.runtimeSettingsNetworkThrottling}
|
|
54
|
+
>
|
|
55
|
+
<div className="SidebarRuntimeSettings__item--icon">
|
|
56
|
+
<NetworkIcon/>
|
|
57
|
+
</div>
|
|
58
|
+
{
|
|
59
|
+
env.summary
|
|
48
60
|
}
|
|
49
61
|
</div>
|
|
50
62
|
<div className="SidebarRuntimeSettings__item" title={strings.runtimeSettingsCPUThrottling}>
|
|
@@ -59,7 +71,7 @@ const SidebarRuntimeSettings: FunctionComponent<{settings: LH.ConfigSettings}> =
|
|
|
59
71
|
);
|
|
60
72
|
};
|
|
61
73
|
|
|
62
|
-
|
|
74
|
+
const SidebarHeader: FunctionComponent<{title: string, date: string}> = ({title, date}) => {
|
|
63
75
|
const i18n = useI18n();
|
|
64
76
|
return (
|
|
65
77
|
<div className="SidebarHeader">
|
|
@@ -69,7 +81,7 @@ export const SidebarHeader: FunctionComponent<{title: string, date: string}> = (
|
|
|
69
81
|
);
|
|
70
82
|
};
|
|
71
83
|
|
|
72
|
-
|
|
84
|
+
const Sidebar: FunctionComponent = () => {
|
|
73
85
|
const flowResult = useFlowResult();
|
|
74
86
|
const firstLhr = flowResult.steps[0].lhr;
|
|
75
87
|
return (
|
|
@@ -84,3 +96,10 @@ export const Sidebar: FunctionComponent = () => {
|
|
|
84
96
|
</div>
|
|
85
97
|
);
|
|
86
98
|
};
|
|
99
|
+
|
|
100
|
+
export {
|
|
101
|
+
SidebarSummary,
|
|
102
|
+
SidebarRuntimeSettings,
|
|
103
|
+
SidebarHeader,
|
|
104
|
+
Sidebar,
|
|
105
|
+
};
|
|
@@ -95,7 +95,7 @@ const SummaryTooltipAudits: FunctionComponent<{category: LH.ReportResult.Categor
|
|
|
95
95
|
);
|
|
96
96
|
};
|
|
97
97
|
|
|
98
|
-
|
|
98
|
+
const SummaryTooltip: FunctionComponent<{
|
|
99
99
|
category: LH.ReportResult.Category,
|
|
100
100
|
gatherMode: LH.Result.GatherMode,
|
|
101
101
|
url: string,
|
|
@@ -153,7 +153,7 @@ export const SummaryTooltip: FunctionComponent<{
|
|
|
153
153
|
);
|
|
154
154
|
};
|
|
155
155
|
|
|
156
|
-
|
|
156
|
+
const SummaryCategory: FunctionComponent<{
|
|
157
157
|
category: LH.ReportResult.Category|undefined,
|
|
158
158
|
href: string,
|
|
159
159
|
gatherMode: LH.Result.GatherMode,
|
|
@@ -176,3 +176,8 @@ export const SummaryCategory: FunctionComponent<{
|
|
|
176
176
|
</div>
|
|
177
177
|
);
|
|
178
178
|
};
|
|
179
|
+
|
|
180
|
+
export {
|
|
181
|
+
SummaryTooltip,
|
|
182
|
+
SummaryCategory,
|
|
183
|
+
};
|
|
@@ -44,7 +44,7 @@ const SummaryNavigationHeader: FunctionComponent<{lhr: LH.Result}> = ({lhr}) =>
|
|
|
44
44
|
/**
|
|
45
45
|
* The div should behave like a JSX <>...</>. This still allows us to identify "rows" with CSS selectors.
|
|
46
46
|
*/
|
|
47
|
-
|
|
47
|
+
const SummaryFlowStep: FunctionComponent<{
|
|
48
48
|
lhr: LH.Result,
|
|
49
49
|
label: string,
|
|
50
50
|
hashIndex: number,
|
|
@@ -106,7 +106,7 @@ const SummaryFlow: FunctionComponent = () => {
|
|
|
106
106
|
);
|
|
107
107
|
};
|
|
108
108
|
|
|
109
|
-
|
|
109
|
+
const SummaryHeader: FunctionComponent = () => {
|
|
110
110
|
const flowResult = useFlowResult();
|
|
111
111
|
const strings = useLocalizedStrings();
|
|
112
112
|
const str_ = useStringFormatter();
|
|
@@ -151,7 +151,7 @@ const SummarySectionHeader: FunctionComponent = ({children}) => {
|
|
|
151
151
|
);
|
|
152
152
|
};
|
|
153
153
|
|
|
154
|
-
|
|
154
|
+
const Summary: FunctionComponent = () => {
|
|
155
155
|
const strings = useLocalizedStrings();
|
|
156
156
|
|
|
157
157
|
return (
|
|
@@ -163,3 +163,9 @@ export const Summary: FunctionComponent = () => {
|
|
|
163
163
|
</div>
|
|
164
164
|
);
|
|
165
165
|
};
|
|
166
|
+
|
|
167
|
+
export {
|
|
168
|
+
SummaryFlowStep,
|
|
169
|
+
SummaryHeader,
|
|
170
|
+
Summary,
|
|
171
|
+
};
|
package/flow-report/src/util.ts
CHANGED
|
@@ -9,14 +9,14 @@ import {useContext, useEffect, useMemo, useState} from 'preact/hooks';
|
|
|
9
9
|
|
|
10
10
|
import type {UIStringsType} from './i18n/ui-strings';
|
|
11
11
|
|
|
12
|
-
|
|
12
|
+
const FlowResultContext = createContext<LH.FlowResult|undefined>(undefined);
|
|
13
13
|
|
|
14
14
|
function getHashParam(param: string): string|null {
|
|
15
15
|
const params = new URLSearchParams(location.hash.replace('#', '?'));
|
|
16
16
|
return params.get(param);
|
|
17
17
|
}
|
|
18
18
|
|
|
19
|
-
|
|
19
|
+
function classNames(...args: Array<string|undefined|Record<string, boolean>>): string {
|
|
20
20
|
const classes = [];
|
|
21
21
|
for (const arg of args) {
|
|
22
22
|
if (!arg) continue;
|
|
@@ -35,12 +35,12 @@ export function classNames(...args: Array<string|undefined|Record<string, boolea
|
|
|
35
35
|
return classes.join(' ');
|
|
36
36
|
}
|
|
37
37
|
|
|
38
|
-
|
|
38
|
+
function getScreenDimensions(reportResult: LH.Result) {
|
|
39
39
|
const {width, height} = reportResult.configSettings.screenEmulation;
|
|
40
40
|
return {width, height};
|
|
41
41
|
}
|
|
42
42
|
|
|
43
|
-
|
|
43
|
+
function getFullPageScreenshot(reportResult: LH.Result) {
|
|
44
44
|
const fullPageScreenshotAudit = reportResult.audits['full-page-screenshot'];
|
|
45
45
|
const fullPageScreenshot =
|
|
46
46
|
fullPageScreenshotAudit &&
|
|
@@ -51,7 +51,7 @@ export function getFullPageScreenshot(reportResult: LH.Result) {
|
|
|
51
51
|
return fullPageScreenshot || null;
|
|
52
52
|
}
|
|
53
53
|
|
|
54
|
-
|
|
54
|
+
function getFilmstripFrames(
|
|
55
55
|
reportResult: LH.Result
|
|
56
56
|
): Array<{data: string}> | undefined {
|
|
57
57
|
const filmstripAudit = reportResult.audits['screenshot-thumbnails'];
|
|
@@ -65,7 +65,7 @@ export function getFilmstripFrames(
|
|
|
65
65
|
return frameItems || undefined;
|
|
66
66
|
}
|
|
67
67
|
|
|
68
|
-
|
|
68
|
+
function getModeDescription(mode: LH.Result.GatherMode, strings: UIStringsType) {
|
|
69
69
|
switch (mode) {
|
|
70
70
|
case 'navigation': return strings.navigationDescription;
|
|
71
71
|
case 'timespan': return strings.timespanDescription;
|
|
@@ -73,13 +73,13 @@ export function getModeDescription(mode: LH.Result.GatherMode, strings: UIString
|
|
|
73
73
|
}
|
|
74
74
|
}
|
|
75
75
|
|
|
76
|
-
|
|
76
|
+
function useFlowResult(): LH.FlowResult {
|
|
77
77
|
const flowResult = useContext(FlowResultContext);
|
|
78
78
|
if (!flowResult) throw Error('useFlowResult must be called in the FlowResultContext');
|
|
79
79
|
return flowResult;
|
|
80
80
|
}
|
|
81
81
|
|
|
82
|
-
|
|
82
|
+
function useHashParams(...params: string[]) {
|
|
83
83
|
const [paramValues, setParamValues] = useState(params.map(getHashParam));
|
|
84
84
|
|
|
85
85
|
// Use two-way-binding on the URL hash.
|
|
@@ -97,7 +97,7 @@ export function useHashParams(...params: string[]) {
|
|
|
97
97
|
return paramValues;
|
|
98
98
|
}
|
|
99
99
|
|
|
100
|
-
|
|
100
|
+
function useHashState(): LH.FlowResult.HashState|null {
|
|
101
101
|
const flowResult = useFlowResult();
|
|
102
102
|
const [indexString, anchor] = useHashParams('index', 'anchor');
|
|
103
103
|
|
|
@@ -120,3 +120,15 @@ export function useHashState(): LH.FlowResult.HashState|null {
|
|
|
120
120
|
return {currentLhr: step.lhr, index, anchor};
|
|
121
121
|
}, [indexString, flowResult, anchor]);
|
|
122
122
|
}
|
|
123
|
+
|
|
124
|
+
export {
|
|
125
|
+
FlowResultContext,
|
|
126
|
+
classNames,
|
|
127
|
+
getScreenDimensions,
|
|
128
|
+
getFullPageScreenshot,
|
|
129
|
+
getFilmstripFrames,
|
|
130
|
+
getModeDescription,
|
|
131
|
+
useFlowResult,
|
|
132
|
+
useHashParams,
|
|
133
|
+
useHashState,
|
|
134
|
+
};
|
|
@@ -19,16 +19,17 @@ interface ReportRendererGlobals {
|
|
|
19
19
|
reportRenderer: ReportRenderer,
|
|
20
20
|
}
|
|
21
21
|
|
|
22
|
-
|
|
22
|
+
const ReportRendererContext = createContext<ReportRendererGlobals|undefined>(undefined);
|
|
23
23
|
|
|
24
|
-
|
|
24
|
+
function useReportRenderer() {
|
|
25
25
|
const globals = useContext(ReportRendererContext);
|
|
26
26
|
if (!globals) throw Error('Globals not defined');
|
|
27
27
|
return globals;
|
|
28
28
|
}
|
|
29
29
|
|
|
30
|
-
|
|
30
|
+
const ReportRendererProvider: FunctionComponent = ({children}) => {
|
|
31
31
|
const globals = useMemo(() => {
|
|
32
|
+
// @ts-expect-error Still using legacy
|
|
32
33
|
const dom = new DOM(document);
|
|
33
34
|
const detailsRenderer = new DetailsRenderer(dom);
|
|
34
35
|
const categoryRenderer = new CategoryRenderer(dom, detailsRenderer);
|
|
@@ -44,3 +45,9 @@ export const ReportRendererProvider: FunctionComponent = ({children}) => {
|
|
|
44
45
|
<ReportRendererContext.Provider value={globals}>{children}</ReportRendererContext.Provider>
|
|
45
46
|
);
|
|
46
47
|
};
|
|
48
|
+
|
|
49
|
+
export {
|
|
50
|
+
ReportRendererContext,
|
|
51
|
+
ReportRendererProvider,
|
|
52
|
+
useReportRenderer,
|
|
53
|
+
};
|
|
@@ -16,7 +16,7 @@ import {useReportRenderer} from './report-renderer';
|
|
|
16
16
|
* This function converts any anchor links under the provided element to a flow report link.
|
|
17
17
|
* e.g. <a href="#link"> -> <a href="#index=0&anchor=link">
|
|
18
18
|
*/
|
|
19
|
-
|
|
19
|
+
function convertChildAnchors(element: HTMLElement, index: number) {
|
|
20
20
|
const links = element.querySelectorAll('a[href]') as NodeListOf<HTMLAnchorElement>;
|
|
21
21
|
for (const link of links) {
|
|
22
22
|
// Check if the link destination is in the report.
|
|
@@ -38,7 +38,7 @@ export function convertChildAnchors(element: HTMLElement, index: number) {
|
|
|
38
38
|
}
|
|
39
39
|
}
|
|
40
40
|
|
|
41
|
-
|
|
41
|
+
const Report: FunctionComponent<{hashState: LH.FlowResult.HashState}> =
|
|
42
42
|
({hashState}) => {
|
|
43
43
|
const {dom, reportRenderer} = useReportRenderer();
|
|
44
44
|
const ref = useRef<HTMLDivElement>(null);
|
|
@@ -50,11 +50,10 @@ export const Report: FunctionComponent<{hashState: LH.FlowResult.HashState}> =
|
|
|
50
50
|
convertChildAnchors(ref.current, hashState.index);
|
|
51
51
|
const fullPageScreenshot = getFullPageScreenshot(hashState.currentLhr);
|
|
52
52
|
if (fullPageScreenshot) {
|
|
53
|
-
const container = dom.find('.lh-container', ref.current);
|
|
54
53
|
ElementScreenshotRenderer.installOverlayFeature({
|
|
55
54
|
dom,
|
|
56
|
-
|
|
57
|
-
overlayContainerEl:
|
|
55
|
+
rootEl: ref.current,
|
|
56
|
+
overlayContainerEl: ref.current,
|
|
58
57
|
fullPageScreenshot,
|
|
59
58
|
});
|
|
60
59
|
}
|
|
@@ -71,3 +70,8 @@ export const Report: FunctionComponent<{hashState: LH.FlowResult.HashState}> =
|
|
|
71
70
|
<div ref={ref} className="lh-root" data-testid="Report"/>
|
|
72
71
|
);
|
|
73
72
|
};
|
|
73
|
+
|
|
74
|
+
export {
|
|
75
|
+
convertChildAnchors,
|
|
76
|
+
Report,
|
|
77
|
+
};
|
|
@@ -15,9 +15,10 @@ import {App} from './src/app';
|
|
|
15
15
|
|
|
16
16
|
// Used by standalone-flow.html
|
|
17
17
|
function __initLighthouseFlowReport__() {
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
18
|
+
// TODO(adamraine): add lh-vars, etc classes programmatically instead of in the HTML template
|
|
19
|
+
const container = document.body.querySelector('main');
|
|
20
|
+
if (!container) throw Error('Container element not found');
|
|
21
|
+
render(<App flowResult={window.__LIGHTHOUSE_FLOW_JSON__} />, container);
|
|
21
22
|
}
|
|
22
23
|
|
|
23
24
|
window.__initLighthouseFlowReport__ = __initLighthouseFlowReport__;
|
|
@@ -10,7 +10,7 @@ import {JSDOM} from 'jsdom';
|
|
|
10
10
|
/**
|
|
11
11
|
* The jest environment "jsdom" does not work when preact is combined with the report renderer.
|
|
12
12
|
*/
|
|
13
|
-
|
|
13
|
+
function setupJsDom() {
|
|
14
14
|
const {window} = new JSDOM(undefined, {
|
|
15
15
|
url: 'file:///Users/example/report.html/',
|
|
16
16
|
});
|
|
@@ -8,7 +8,7 @@ import {render} from '@testing-library/preact';
|
|
|
8
8
|
import {FunctionComponent} from 'preact';
|
|
9
9
|
|
|
10
10
|
import {I18nProvider} from '../../src/i18n/i18n';
|
|
11
|
-
import {SidebarHeader, SidebarSummary} from '../../src/sidebar/sidebar';
|
|
11
|
+
import {SidebarHeader, SidebarRuntimeSettings, SidebarSummary} from '../../src/sidebar/sidebar';
|
|
12
12
|
import {FlowResultContext} from '../../src/util';
|
|
13
13
|
import {flowResult} from '../sample-flow';
|
|
14
14
|
|
|
@@ -45,3 +45,45 @@ describe('SidebarSummary', () => {
|
|
|
45
45
|
expect(link.classList).toContain('Sidebar--current');
|
|
46
46
|
});
|
|
47
47
|
});
|
|
48
|
+
|
|
49
|
+
describe('SidebarRuntimeSettings', () => {
|
|
50
|
+
it('displays default runtime settings', async () => {
|
|
51
|
+
const settings = {
|
|
52
|
+
formFactor: 'mobile',
|
|
53
|
+
throttlingMethod: 'simulate',
|
|
54
|
+
throttling: {
|
|
55
|
+
cpuSlowdownMultiplier: 4,
|
|
56
|
+
requestLatencyMs: 150 * 3.75,
|
|
57
|
+
downloadThroughputKbps: 1.6 * 1024 * 0.9,
|
|
58
|
+
uploadThroughputKbps: 750 * 0.9,
|
|
59
|
+
throughputKbps: 1.6 * 1024,
|
|
60
|
+
rttMs: 150,
|
|
61
|
+
},
|
|
62
|
+
} as any;
|
|
63
|
+
const root = render(<SidebarRuntimeSettings settings={settings}/>, {wrapper});
|
|
64
|
+
|
|
65
|
+
expect(root.getByText('Emulated Moto G4')).toBeTruthy();
|
|
66
|
+
expect(root.getByText('Slow 4G throttling')).toBeTruthy();
|
|
67
|
+
expect(root.getByText('4x slowdown'));
|
|
68
|
+
});
|
|
69
|
+
|
|
70
|
+
it('displays custom runtime settings', async () => {
|
|
71
|
+
const settings = {
|
|
72
|
+
formFactor: 'desktop',
|
|
73
|
+
throttlingMethod: 'devtools',
|
|
74
|
+
throttling: {
|
|
75
|
+
cpuSlowdownMultiplier: 1,
|
|
76
|
+
requestLatencyMs: 1,
|
|
77
|
+
downloadThroughputKbps: 1,
|
|
78
|
+
uploadThroughputKbps: 1,
|
|
79
|
+
throughputKbps: 1,
|
|
80
|
+
rttMs: 1,
|
|
81
|
+
},
|
|
82
|
+
} as any;
|
|
83
|
+
const root = render(<SidebarRuntimeSettings settings={settings}/>, {wrapper});
|
|
84
|
+
|
|
85
|
+
expect(root.getByText('Emulated Desktop')).toBeTruthy();
|
|
86
|
+
expect(root.getByText('Custom throttling')).toBeTruthy();
|
|
87
|
+
expect(root.getByText('1x slowdown'));
|
|
88
|
+
});
|
|
89
|
+
});
|
|
@@ -10,7 +10,7 @@ const NetworkRecords = require('./network-records.js');
|
|
|
10
10
|
const URL = require('../lib/url-shim.js');
|
|
11
11
|
const NetworkRequest = require('../lib/network-request.js');
|
|
12
12
|
const Budget = require('../config/budget.js');
|
|
13
|
-
const Util = require('../util-commonjs.js');
|
|
13
|
+
const {Util} = require('../util-commonjs.js');
|
|
14
14
|
|
|
15
15
|
/** @typedef {{count: number, resourceSize: number, transferSize: number}} ResourceEntry */
|
|
16
16
|
|
|
@@ -303,7 +303,6 @@ const defaultConfig = {
|
|
|
303
303
|
'dobetterweb/doctype',
|
|
304
304
|
'dobetterweb/charset',
|
|
305
305
|
'dobetterweb/dom-size',
|
|
306
|
-
'dobetterweb/external-anchors-use-rel-noopener',
|
|
307
306
|
'dobetterweb/geolocation-on-start',
|
|
308
307
|
'dobetterweb/inspector-issues',
|
|
309
308
|
'dobetterweb/no-document-write',
|
|
@@ -554,7 +553,6 @@ const defaultConfig = {
|
|
|
554
553
|
auditRefs: [
|
|
555
554
|
// Trust & Safety
|
|
556
555
|
{id: 'is-on-https', weight: 1, group: 'best-practices-trust-safety'},
|
|
557
|
-
{id: 'external-anchors-use-rel-noopener', weight: 1, group: 'best-practices-trust-safety'},
|
|
558
556
|
{id: 'geolocation-on-start', weight: 1, group: 'best-practices-trust-safety'},
|
|
559
557
|
{id: 'notification-on-start', weight: 1, group: 'best-practices-trust-safety'},
|
|
560
558
|
{id: 'no-vulnerable-libraries', weight: 1, group: 'best-practices-trust-safety'},
|