sitespeed.io 21.2.2 → 21.6.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/CHANGELOG.md +31 -1
- package/Dockerfile +1 -1
- package/lib/cli/cli.js +33 -2
- package/lib/plugins/browsertime/analyzer.js +3 -2
- package/lib/plugins/crux/cli.js +6 -0
- package/lib/plugins/crux/index.js +148 -130
- package/lib/plugins/crux/pug/index.pug +57 -25
- package/lib/plugins/html/assets/css/index.min.css +1 -1
- package/lib/plugins/html/assets/js/chartist-plugin-legend.min.js +1 -0
- package/lib/plugins/html/renderer.js +1 -1
- package/lib/plugins/html/src/sass/components/chartistExtras.scss +70 -3
- package/lib/plugins/html/templates/layout.pug +1 -0
- package/lib/plugins/html/templates/url/iteration/index.pug +29 -16
- package/lib/plugins/html/templates/url/summary/index.pug +47 -12
- package/npm-shrinkwrap.json +31 -31
- package/package.json +2 -2
- package/release/feed.js +2 -1
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,35 @@
|
|
|
1
1
|
# CHANGELOG - sitespeed.io (we use [semantic versioning](https://semver.org))
|
|
2
2
|
|
|
3
|
+
## 21.6.0 - 2022-01-24
|
|
4
|
+
### Added
|
|
5
|
+
* Updated to Edge stable release in the Docker container.
|
|
6
|
+
* Remove Crux distribution table and use pie charts instead [#3537](https://github.com/sitespeedio/sitespeed.io/pull/3537)
|
|
7
|
+
* Add extra sleep time between Crux calls to make sure to not overload the API limit [#3536](https://github.com/sitespeedio/sitespeed.io/pull/3536).
|
|
8
|
+
* Added extra Crux enable command line `--crux.enable` to enable Crux [#3538](https://github.com/sitespeedio/sitespeed.io/pull/3538). Its default value is `true` and you also need to supply the Crux key to run Crux. The reason for the new parameter is that you can now configure the key in your configuration JSON and set the enable to false and then you enable it with the CLI parameter when you actually need to run Crux.
|
|
9
|
+
* Show Crux-metrics on the Summary page [#3540](https://github.com/sitespeedio/sitespeed.io/pull/3540).
|
|
10
|
+
* Updated summary metrics tables with headings to make it easier to read [#3541](https://github.com/sitespeedio/sitespeed.io/pull/3541).
|
|
11
|
+
* Added [Browsertime 14.17.0](https://github.com/sitespeedio/browsertime/blob/main/CHANGELOG.md#14170---2022-01-23) with new Select and click.byName commands. With that Browsertime version you also need to have ffprobe installed when you run Visual Metrics but that should already be installed.
|
|
12
|
+
* Added [Browsertime 14.18.0](https://github.com/sitespeedio/browsertime/blob/main/CHANGELOG.md#14180---2022-01-24) with a fix for Firefox [#1698](https://github.com/sitespeedio/browsertime/issues/1698)
|
|
13
|
+
|
|
14
|
+
## 21.5.0 - 2022-01-14
|
|
15
|
+
### Added
|
|
16
|
+
* Upgraded to [Browsertime 14.15.0](https://github.com/sitespeedio/browsertime/blob/main/CHANGELOG.md#14150---2022-01-12) that adds support for `--appendToUserAgent` for Chrome/Edge/Firefox. And then Browsertime 14.16.0 that supports Geckodriver for Raspberry Pi.
|
|
17
|
+
## 21.4.0 - 2022-01-12
|
|
18
|
+
### Added
|
|
19
|
+
* Updated to a new build of WebPageReplay in the Docker container
|
|
20
|
+
* Updated the Ubuntu base image to latest version and latest NodeJS in the Docketr container.
|
|
21
|
+
* Upgraded Browsertime [#3528](https://github.com/sitespeedio/sitespeed.io/pull/3528):
|
|
22
|
+
* Add support for Humble as connectivity engine for mobile phone testing. Make sure to setup Humble on a Raspberry Pi 4 and the choose engine with --connectivity.engine humble and set the URL to your instance --connectivity.humble.url http://raspberrypi.local:3000. Added in #1691.
|
|
23
|
+
* Upgraded to Chrome 97 and Edge 97 in the Docker container.
|
|
24
|
+
* Upgraded to Chromedriver 97.
|
|
25
|
+
### Fixed
|
|
26
|
+
* Updated Chromedriver library that automatically picks up the Chromedriver if it's installed on Raspberry Pi.
|
|
27
|
+
## 21.3.0 - 2022-01-01
|
|
28
|
+
### Added
|
|
29
|
+
* Updated to [Browsertime 14.13.0](https://github.com/sitespeedio/browsertime/blob/main/CHANGELOG.md#14130---2021-12-30) with the following fixes for the user agent:
|
|
30
|
+
* Append text to Chrome/Edge user agent using `--chrome.appendToUserAgent`
|
|
31
|
+
* When you use Chrome/Edge and use a "emulated device" that will use the user agent that you provide using `--userAgent`. Else it will use the user agent from your emulated device setting.
|
|
32
|
+
* You can also use Edge to run emulated mobile with the same settings as Chrome.
|
|
3
33
|
## 21.2.2 - 2021-12-23
|
|
4
34
|
### Fixed
|
|
5
35
|
* Fix the error introduced in 21.2.0 for "Include page summary URL in the result JSON"
|
|
@@ -10,7 +40,7 @@
|
|
|
10
40
|
* It turns out that Firefox 95 doesn't work with the HAR export trigger and the workaround that worked in Firefox 94 seems to not work in 95 see https://github.com/sitespeedio/browsertime/issues/1671#issuecomment-999412035. That's why we are reverting to Firefox 94 in the Docker containers.
|
|
11
41
|
## 21.2.0 - 2021-12-22
|
|
12
42
|
### Fixed
|
|
13
|
-
* The catching of errors in the queue was broken and reported the error x times (x=
|
|
43
|
+
* The catching of errors in the queue was broken and reported the error x times (x=number of plugins). Also when we had an error the result JSON was not stored. [#3522](https://github.com/sitespeedio/sitespeed.io/pull/3522).
|
|
14
44
|
|
|
15
45
|
### Added
|
|
16
46
|
* Updated to Firefox 95 and Edge 96 in the Docker container.
|
package/Dockerfile
CHANGED
package/lib/cli/cli.js
CHANGED
|
@@ -113,6 +113,18 @@ function validateInput(argv) {
|
|
|
113
113
|
return 'Error: You have a miss match between number of alias for groups and URLs.';
|
|
114
114
|
}
|
|
115
115
|
|
|
116
|
+
if (
|
|
117
|
+
argv.browsertime.connectivity &&
|
|
118
|
+
argv.browsertime.connectivity.engine === 'humble'
|
|
119
|
+
) {
|
|
120
|
+
if (
|
|
121
|
+
!argv.browsertime.connectivity.humble ||
|
|
122
|
+
!argv.browsertime.connectivity.humble.url
|
|
123
|
+
) {
|
|
124
|
+
return 'You need to specify the URL to Humble by using the --browsertime.connectivity.humble.url option.';
|
|
125
|
+
}
|
|
126
|
+
}
|
|
127
|
+
|
|
116
128
|
if (
|
|
117
129
|
argv.browsertime.safari &&
|
|
118
130
|
argv.browsertime.safari.useSimulator &&
|
|
@@ -291,12 +303,19 @@ module.exports.parseCommandLine = function parseCommandLine() {
|
|
|
291
303
|
.option('browsertime.connectivity.engine', {
|
|
292
304
|
alias: 'connectivity.engine',
|
|
293
305
|
default: 'external',
|
|
294
|
-
choices: ['external', 'throttle', 'tsproxy'],
|
|
306
|
+
choices: ['external', 'throttle', 'tsproxy', 'humble'],
|
|
295
307
|
describe:
|
|
296
|
-
'The engine for connectivity. Throttle works on Mac and tc based Linux. Use external if you set the connectivity outside of Browsertime. Use tsproxy if you are using Kubernetes. More documentation at https://www.sitespeed.io/documentation/sitespeed.io/connectivity/.',
|
|
308
|
+
'The engine for connectivity. Throttle works on Mac and tc based Linux. For mobile you can use Humble if you have a Humble setup. Use external if you set the connectivity outside of Browsertime. Use tsproxy if you are using Kubernetes. More documentation at https://www.sitespeed.io/documentation/sitespeed.io/connectivity/.',
|
|
297
309
|
type: 'string',
|
|
298
310
|
group: 'Browser'
|
|
299
311
|
})
|
|
312
|
+
.option('browsertime.connectivity.humble.url', {
|
|
313
|
+
alias: 'connectivity.humble.url',
|
|
314
|
+
type: 'string',
|
|
315
|
+
describe:
|
|
316
|
+
'The path to your Humble instance. For example http://raspberrypi:3000',
|
|
317
|
+
group: 'Browser'
|
|
318
|
+
})
|
|
300
319
|
.option('browsertime.pageCompleteCheck', {
|
|
301
320
|
alias: 'pageCompleteCheck',
|
|
302
321
|
describe:
|
|
@@ -372,6 +391,12 @@ module.exports.parseCommandLine = function parseCommandLine() {
|
|
|
372
391
|
'The full User Agent string, defaults to the User Agent used by the browsertime.browser option.',
|
|
373
392
|
group: 'Browser'
|
|
374
393
|
})
|
|
394
|
+
.option('browsertime.appendToUserAgent', {
|
|
395
|
+
alias: 'appendToUserAgent',
|
|
396
|
+
describe:
|
|
397
|
+
'Append a String to the user agent. Works in Chrome/Edge and Firefox.',
|
|
398
|
+
group: 'Browser'
|
|
399
|
+
})
|
|
375
400
|
.option('browsertime.preURL', {
|
|
376
401
|
alias: 'preURL',
|
|
377
402
|
describe:
|
|
@@ -715,6 +740,12 @@ module.exports.parseCommandLine = function parseCommandLine() {
|
|
|
715
740
|
default: true,
|
|
716
741
|
group: 'Chrome'
|
|
717
742
|
})
|
|
743
|
+
.option('browsertime.chrome.appendToUserAgent', {
|
|
744
|
+
alias: 'chrome.appendToUserAgent',
|
|
745
|
+
type: 'string',
|
|
746
|
+
describe: 'Append to the user agent.',
|
|
747
|
+
group: 'Chrome'
|
|
748
|
+
})
|
|
718
749
|
.option('browsertime.chrome.android.package', {
|
|
719
750
|
alias: 'chrome.android.package',
|
|
720
751
|
describe:
|
|
@@ -100,7 +100,7 @@ module.exports = {
|
|
|
100
100
|
// set mobile options
|
|
101
101
|
if (options.mobile) {
|
|
102
102
|
btOptions.viewPort = '360x640';
|
|
103
|
-
if (btOptions.browser === 'chrome') {
|
|
103
|
+
if (btOptions.browser === 'chrome' || btOptions.browser === 'edge') {
|
|
104
104
|
const emulation = get(
|
|
105
105
|
btOptions,
|
|
106
106
|
'chrome.mobileEmulation.deviceName',
|
|
@@ -109,8 +109,9 @@ module.exports = {
|
|
|
109
109
|
btOptions.chrome.mobileEmulation = {
|
|
110
110
|
deviceName: emulation
|
|
111
111
|
};
|
|
112
|
+
} else {
|
|
113
|
+
btOptions.userAgent = iphone6UserAgent;
|
|
112
114
|
}
|
|
113
|
-
btOptions.userAgent = iphone6UserAgent;
|
|
114
115
|
}
|
|
115
116
|
const scriptCategories = await browserScripts.allScriptCategories;
|
|
116
117
|
let scriptsByCategory = await browserScripts.getScriptsForCategories(
|
package/lib/plugins/crux/cli.js
CHANGED
|
@@ -4,6 +4,12 @@ module.exports = {
|
|
|
4
4
|
'You need to use a key to get data from CrUx. Get the key from https://developers.google.com/web/tools/chrome-user-experience-report/api/guides/getting-started#APIKey',
|
|
5
5
|
group: 'CrUx'
|
|
6
6
|
},
|
|
7
|
+
enable: {
|
|
8
|
+
default: true,
|
|
9
|
+
describe:
|
|
10
|
+
'Enable the CrUx plugin. This is on by defauly but you also need the Crux key. If you chose to disable it with this key, set this to false and you can still use the CrUx key in your configuration.',
|
|
11
|
+
group: 'CrUx'
|
|
12
|
+
},
|
|
7
13
|
formFactor: {
|
|
8
14
|
default: 'ALL',
|
|
9
15
|
type: 'string',
|
|
@@ -23,6 +23,12 @@ const DEFAULT_METRICS_SUMMARY = [
|
|
|
23
23
|
'originLoadingExperience.*.CUMULATIVE_LAYOUT_SHIFT_SCORE.*'
|
|
24
24
|
];
|
|
25
25
|
|
|
26
|
+
function wait(ms) {
|
|
27
|
+
return new Promise(resolve => setTimeout(resolve, ms));
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
const CRUX_WAIT_TIME = 300;
|
|
31
|
+
|
|
26
32
|
module.exports = {
|
|
27
33
|
name() {
|
|
28
34
|
return path.basename(__dirname);
|
|
@@ -30,159 +36,171 @@ module.exports = {
|
|
|
30
36
|
open(context, options) {
|
|
31
37
|
this.make = context.messageMaker('crux').make;
|
|
32
38
|
this.options = merge({}, defaultConfig, options.crux);
|
|
33
|
-
this.
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
39
|
+
if (this.options.enable === true) {
|
|
40
|
+
this.testedOrigins = {};
|
|
41
|
+
throwIfMissing(options.crux, ['key'], 'crux');
|
|
42
|
+
this.formFactors = Array.isArray(this.options.formFactor)
|
|
43
|
+
? this.options.formFactor
|
|
44
|
+
: [this.options.formFactor];
|
|
45
|
+
this.pug = fs.readFileSync(
|
|
46
|
+
path.resolve(__dirname, 'pug', 'index.pug'),
|
|
47
|
+
'utf8'
|
|
48
|
+
);
|
|
49
|
+
|
|
50
|
+
if (this.options.collect === 'ALL' || this.options.collect === 'URL') {
|
|
51
|
+
context.filterRegistry.registerFilterForType(
|
|
52
|
+
DEFAULT_METRICS_PAGESUMMARY,
|
|
53
|
+
'crux.pageSummary'
|
|
54
|
+
);
|
|
55
|
+
}
|
|
42
56
|
|
|
43
|
-
if (this.options.collect === 'ALL' || this.options.collect === 'URL') {
|
|
44
57
|
context.filterRegistry.registerFilterForType(
|
|
45
|
-
|
|
46
|
-
'crux.
|
|
58
|
+
DEFAULT_METRICS_SUMMARY,
|
|
59
|
+
'crux.summary'
|
|
47
60
|
);
|
|
48
61
|
}
|
|
49
|
-
|
|
50
|
-
context.filterRegistry.registerFilterForType(
|
|
51
|
-
DEFAULT_METRICS_SUMMARY,
|
|
52
|
-
'crux.summary'
|
|
53
|
-
);
|
|
54
62
|
},
|
|
55
63
|
async processMessage(message, queue) {
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
if (originResult.originLoadingExperience[formFactor].error) {
|
|
98
|
-
log.info(
|
|
99
|
-
`${originResult.originLoadingExperience[formFactor].error.message} for domain ${url} using ${formFactor}`
|
|
64
|
+
if (this.options.enable === true) {
|
|
65
|
+
const make = this.make;
|
|
66
|
+
switch (message.type) {
|
|
67
|
+
case 'sitespeedio.setup': {
|
|
68
|
+
queue.postMessage(make('crux.setup'));
|
|
69
|
+
// Add the HTML pugs
|
|
70
|
+
queue.postMessage(
|
|
71
|
+
make('html.pug', {
|
|
72
|
+
id: 'crux',
|
|
73
|
+
name: 'CrUx',
|
|
74
|
+
pug: this.pug,
|
|
75
|
+
type: 'pageSummary'
|
|
76
|
+
})
|
|
77
|
+
);
|
|
78
|
+
queue.postMessage(
|
|
79
|
+
make('html.pug', {
|
|
80
|
+
id: 'crux',
|
|
81
|
+
name: 'CrUx',
|
|
82
|
+
pug: this.pug,
|
|
83
|
+
type: 'run'
|
|
84
|
+
})
|
|
85
|
+
);
|
|
86
|
+
break;
|
|
87
|
+
}
|
|
88
|
+
case 'url': {
|
|
89
|
+
let url = message.url;
|
|
90
|
+
let group = message.group;
|
|
91
|
+
const originResult = { originLoadingExperience: {} };
|
|
92
|
+
if (
|
|
93
|
+
!this.testedOrigins[group] &&
|
|
94
|
+
(this.options.collect === 'ALL' ||
|
|
95
|
+
this.options.collect === 'ORIGIN')
|
|
96
|
+
) {
|
|
97
|
+
this.testedOrigins[group] = true;
|
|
98
|
+
log.info(`Get CrUx data for domain ${group}`);
|
|
99
|
+
for (let formFactor of this.formFactors) {
|
|
100
|
+
originResult.originLoadingExperience[formFactor] = await send.get(
|
|
101
|
+
url,
|
|
102
|
+
this.options.key,
|
|
103
|
+
formFactor,
|
|
104
|
+
false
|
|
100
105
|
);
|
|
101
106
|
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
`${originResult.originLoadingExperience[formFactor].error.message} for domain ${url} using ${formFactor}`,
|
|
106
|
-
{
|
|
107
|
-
url
|
|
108
|
-
}
|
|
109
|
-
)
|
|
110
|
-
);
|
|
111
|
-
} else {
|
|
112
|
-
try {
|
|
113
|
-
originResult.originLoadingExperience[formFactor] = repackage(
|
|
114
|
-
originResult.originLoadingExperience[formFactor]
|
|
107
|
+
if (originResult.originLoadingExperience[formFactor].error) {
|
|
108
|
+
log.info(
|
|
109
|
+
`${originResult.originLoadingExperience[formFactor].error.message} for domain ${url} using ${formFactor}`
|
|
115
110
|
);
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
111
|
+
|
|
112
|
+
queue.postMessage(
|
|
113
|
+
make(
|
|
114
|
+
'error',
|
|
115
|
+
`${originResult.originLoadingExperience[formFactor].error.message} for domain ${url} using ${formFactor}`,
|
|
116
|
+
{
|
|
117
|
+
url
|
|
118
|
+
}
|
|
119
|
+
)
|
|
120
120
|
);
|
|
121
|
+
} else {
|
|
122
|
+
try {
|
|
123
|
+
originResult.originLoadingExperience[formFactor] = repackage(
|
|
124
|
+
originResult.originLoadingExperience[formFactor]
|
|
125
|
+
);
|
|
126
|
+
} catch (e) {
|
|
127
|
+
log.error(
|
|
128
|
+
'Could not repackage the JSON for origin from CrUx, is it broken? %j',
|
|
129
|
+
originResult.originLoadingExperience[formFactor]
|
|
130
|
+
);
|
|
131
|
+
}
|
|
121
132
|
}
|
|
133
|
+
await wait(CRUX_WAIT_TIME);
|
|
122
134
|
}
|
|
135
|
+
queue.postMessage(make('crux.summary', originResult, { group }));
|
|
123
136
|
}
|
|
124
|
-
queue.postMessage(make('crux.summary', originResult, { group }));
|
|
125
|
-
}
|
|
126
|
-
|
|
127
|
-
if (this.options.collect === 'ALL' || this.options.collect === 'URL') {
|
|
128
|
-
log.info(`Get CrUx data for url ${url}`);
|
|
129
|
-
const urlResult = { loadingExperience: {} };
|
|
130
|
-
for (let formFactor of this.formFactors) {
|
|
131
|
-
urlResult.loadingExperience[formFactor] = await send.get(
|
|
132
|
-
url,
|
|
133
|
-
this.options.key,
|
|
134
|
-
formFactor,
|
|
135
|
-
true
|
|
136
|
-
);
|
|
137
137
|
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
138
|
+
if (
|
|
139
|
+
this.options.collect === 'ALL' ||
|
|
140
|
+
this.options.collect === 'URL'
|
|
141
|
+
) {
|
|
142
|
+
log.info(`Get CrUx data for url ${url}`);
|
|
143
|
+
const urlResult = { loadingExperience: {} };
|
|
144
|
+
for (let formFactor of this.formFactors) {
|
|
145
|
+
urlResult.loadingExperience[formFactor] = await send.get(
|
|
146
|
+
url,
|
|
147
|
+
this.options.key,
|
|
148
|
+
formFactor,
|
|
149
|
+
true
|
|
141
150
|
);
|
|
142
151
|
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
`${urlResult.loadingExperience[formFactor].error.message} for ${url} using ${formFactor}`,
|
|
147
|
-
{
|
|
148
|
-
url
|
|
149
|
-
}
|
|
150
|
-
)
|
|
151
|
-
);
|
|
152
|
-
} else {
|
|
153
|
-
try {
|
|
154
|
-
urlResult.loadingExperience[formFactor] = repackage(
|
|
155
|
-
urlResult.loadingExperience[formFactor]
|
|
152
|
+
if (urlResult.loadingExperience[formFactor].error) {
|
|
153
|
+
log.info(
|
|
154
|
+
`${urlResult.loadingExperience[formFactor].error.message} for ${url} using ${formFactor}`
|
|
156
155
|
);
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
156
|
+
|
|
157
|
+
queue.postMessage(
|
|
158
|
+
make(
|
|
159
|
+
'error',
|
|
160
|
+
`${urlResult.loadingExperience[formFactor].error.message} for ${url} using ${formFactor}`,
|
|
161
|
+
{
|
|
162
|
+
url
|
|
163
|
+
}
|
|
164
|
+
)
|
|
161
165
|
);
|
|
166
|
+
} else {
|
|
167
|
+
try {
|
|
168
|
+
urlResult.loadingExperience[formFactor] = repackage(
|
|
169
|
+
urlResult.loadingExperience[formFactor]
|
|
170
|
+
);
|
|
171
|
+
} catch (e) {
|
|
172
|
+
log.error(
|
|
173
|
+
'Could not repackage the JSON from CrUx, is it broken? %j',
|
|
174
|
+
urlResult.loadingExperience[formFactor]
|
|
175
|
+
);
|
|
176
|
+
}
|
|
162
177
|
}
|
|
178
|
+
await wait(CRUX_WAIT_TIME);
|
|
163
179
|
}
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
originResult.originLoadingExperience;
|
|
180
|
+
// Attach origin result so we can show it in the HTML
|
|
181
|
+
urlResult.originLoadingExperience =
|
|
182
|
+
originResult.originLoadingExperience;
|
|
168
183
|
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
url,
|
|
172
|
-
group
|
|
173
|
-
})
|
|
174
|
-
);
|
|
175
|
-
} else {
|
|
176
|
-
queue.postMessage(
|
|
177
|
-
make(
|
|
178
|
-
'crux.pageSummary',
|
|
179
|
-
{ originLoadingExperience: originResult.originLoadingExperience },
|
|
180
|
-
{
|
|
184
|
+
queue.postMessage(
|
|
185
|
+
make('crux.pageSummary', urlResult, {
|
|
181
186
|
url,
|
|
182
187
|
group
|
|
183
|
-
}
|
|
184
|
-
)
|
|
185
|
-
|
|
188
|
+
})
|
|
189
|
+
);
|
|
190
|
+
} else {
|
|
191
|
+
queue.postMessage(
|
|
192
|
+
make(
|
|
193
|
+
'crux.pageSummary',
|
|
194
|
+
{
|
|
195
|
+
originLoadingExperience: originResult.originLoadingExperience
|
|
196
|
+
},
|
|
197
|
+
{
|
|
198
|
+
url,
|
|
199
|
+
group
|
|
200
|
+
}
|
|
201
|
+
)
|
|
202
|
+
);
|
|
203
|
+
}
|
|
186
204
|
}
|
|
187
205
|
}
|
|
188
206
|
}
|
|
@@ -11,7 +11,7 @@ mixin sizeCell(title, size)
|
|
|
11
11
|
td.number(data-title=title, data-value= size)= h.size.format(size)
|
|
12
12
|
|
|
13
13
|
- const crux = pageInfo.data.crux.pageSummary;
|
|
14
|
-
- const metrics = {first_contentful_paint:'First Contentful Paint (FCP)', largest_contentful_paint: 'Largest Contentful Paint (LCP)', first_input_delay:'First Input Delay (FID)', cumulative_layout_shift: 'Cumulative Layout Shift'};
|
|
14
|
+
- const metrics = {first_contentful_paint:'First Contentful Paint (FCP)', largest_contentful_paint: 'Largest Contentful Paint (LCP)', first_input_delay:'First Input Delay (FID)', cumulative_layout_shift: 'Cumulative Layout Shift (CLS)'};
|
|
15
15
|
- const experiences = ['loadingExperience','originLoadingExperience'];
|
|
16
16
|
|
|
17
17
|
small
|
|
@@ -25,6 +25,10 @@ a#crux
|
|
|
25
25
|
h2 CrUx
|
|
26
26
|
p.small Chrome User Experience Report (CrUx) is powered by real user measurement across the public web, aggregated from users who have opted-in to syncing their browsing history, have not set up a Sync passphrase, and have usage statistic reporting enabled and is using Chrome.
|
|
27
27
|
|
|
28
|
+
p.small The CrUx data has four different buckets (form factor) depending on device: DESKTOP, PHONE, TABLET and ALL. You can choose which data to get with
|
|
29
|
+
code --crux.formFactor
|
|
30
|
+
| .
|
|
31
|
+
|
|
28
32
|
each experience in experiences
|
|
29
33
|
if experience === 'loadingExperience' && crux[experience]
|
|
30
34
|
p Over the last 30 days, this is the field data for this page for Chrome users.
|
|
@@ -47,29 +51,57 @@ each experience in experiences
|
|
|
47
51
|
if crux[experience][formFactor].data.record.metrics[key]
|
|
48
52
|
tr
|
|
49
53
|
td #{name} 75 percentile
|
|
50
|
-
td #{crux[experience][formFactor].data.record.metrics[key].percentiles.p75
|
|
54
|
+
td #{key.indexOf('cumulative') > -1 ? crux[experience][formFactor].data.record.metrics[key].percentiles.p75 : h.time.ms(crux[experience][formFactor].data.record.metrics[key].percentiles.p75)}
|
|
51
55
|
|
|
52
56
|
h4 Distribution
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
57
|
+
- let cruxus = `${experience}.${formFactor}.data.record.metrics`;
|
|
58
|
+
- let FCPs = [Number(get(crux, `${cruxus}.first_contentful_paint.histogram[0].density`, 0) * 100).toFixed(2), Number(get(crux, `${cruxus}.first_contentful_paint.histogram[1].density`, 0) * 100).toFixed(2), Number(get(crux, `${cruxus}.first_contentful_paint.histogram[2].density`, 0)*100).toFixed(2)];
|
|
59
|
+
|
|
60
|
+
- let LCPs = [Number(get(crux, `${cruxus}.largest_contentful_paint.histogram[0].density`, 0) * 100).toFixed(2), Number(get(crux, `${cruxus}.largest_contentful_paint.histogram[1].density`, 0) * 100).toFixed(2), Number(get(crux, `${cruxus}.largest_contentful_paint.histogram[2].density`, 0)*100).toFixed(2)];
|
|
61
|
+
|
|
62
|
+
- let FIDs = [Number(get(crux, `${cruxus}.first_input_delay.histogram[0].density`, 0) * 100).toFixed(2), Number(get(crux, `${cruxus}.first_input_delay.histogram[1].density`, 0) * 100).toFixed(2), Number(get(crux, `${cruxus}.first_input_delay.histogram[2].density`, 0)*100).toFixed(2)];
|
|
63
|
+
|
|
64
|
+
- let CLSs = [Number(get(crux, `${cruxus}.cumulative_layout_shift.histogram[0].density`, 0) * 100).toFixed(2), Number(get(crux, `${cruxus}.cumulative_layout_shift.histogram[1].density`, 0) * 100).toFixed(2), Number(get(crux, `${cruxus}.cumulative_layout_shift.histogram[2].density`, 0)*100).toFixed(2)];
|
|
65
|
+
|
|
66
|
+
script(type='text/javascript').
|
|
67
|
+
document.addEventListener("DOMContentLoaded", function() {
|
|
68
|
+
|
|
69
|
+
function drawPie(id, series, labels) {
|
|
70
|
+
new Chartist.Pie(id, {
|
|
71
|
+
series,
|
|
72
|
+
labels,
|
|
73
|
+
}, {
|
|
74
|
+
showLabel: false,
|
|
75
|
+
plugins: [
|
|
76
|
+
Chartist.plugins.legend(
|
|
77
|
+
{ clickable: false,
|
|
78
|
+
position: 'bottom'
|
|
79
|
+
}
|
|
80
|
+
)
|
|
81
|
+
]
|
|
82
|
+
});
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
drawPie('#chartFCP#{experience + formFactor}', [#{FCPs}], ['Fast: #{FCPs[0]}%', 'Moderate #{FCPs[1]}%', 'Slow: #{FCPs[2]}%']);
|
|
86
|
+
drawPie('#chartLCP#{experience + formFactor}', [#{LCPs}], ['Fast: #{LCPs[0]}%', 'Moderate #{LCPs[1]}%', 'Slow: #{LCPs[2]}%']);
|
|
87
|
+
drawPie('#chartFID#{experience + formFactor}', [#{FIDs}], ['Fast: #{FIDs[0]}%', 'Moderate #{FIDs[1]}%', 'Slow: #{FIDs[2]}%']);
|
|
88
|
+
drawPie('#chartCLS#{experience + formFactor}', [#{CLSs}], ['Good: #{CLSs[0]}%', 'Need improvement: #{CLSs[1]}%', 'Poor: #{CLSs[2]}%']);
|
|
89
|
+
|
|
90
|
+
|
|
91
|
+
});
|
|
92
|
+
.responsive
|
|
93
|
+
table
|
|
94
|
+
tr
|
|
95
|
+
th #{metrics['first_contentful_paint']}
|
|
96
|
+
th #{metrics['largest_contentful_paint']}
|
|
97
|
+
th #{metrics['first_input_delay']}
|
|
98
|
+
th #{metrics['cumulative_layout_shift']}
|
|
99
|
+
tr
|
|
100
|
+
td(data-title=metrics['first_contentful_paint'])
|
|
101
|
+
.ct-chart(id='chartFCP' + experience + formFactor)
|
|
102
|
+
td(data-title=metrics['largest_contentful_paint'])
|
|
103
|
+
.ct-chart(id='chartLCP' + experience + formFactor)
|
|
104
|
+
td(data-title=metrics['first_input_delay'])
|
|
105
|
+
.ct-chart(id='chartFID' + experience + formFactor)
|
|
106
|
+
td(data-title=metrics['cumulative_layout_shift'])
|
|
107
|
+
.ct-chart(id='chartCLS' + experience + formFactor)
|