browsertime 28.0.0 → 28.1.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 +8 -0
- package/browserscripts/pageinfo/loaf.js +15 -0
- package/browserscripts/pageinfo/loafSummary.js +24 -0
- package/lib/chrome/mediawikiResourceLoader.js +6 -4
- package/lib/chrome/webdriver/chromium.js +14 -0
- package/package.json +1 -1
- package/types/chrome/mediawikiResourceLoader.d.ts.map +1 -1
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,13 @@
|
|
|
1
1
|
# Browsertime changelog (we do [semantic versioning](https://semver.org))
|
|
2
2
|
|
|
3
|
+
## 28.1.0 - 2026-07-17
|
|
4
|
+
|
|
5
|
+
### Added
|
|
6
|
+
* Long Animation Frames (`pageinfo.loaf`) now ship every per-script field the LoAF API exposes (`startTime`, `duration`, `executionStart`, `pauseDuration`) plus `startTime` and `firstUIEventTimestamp` per frame — enough to attribute blocking time to individual scripts, place each frame on the page timeline and spot frames where an input was waiting [#2522](https://github.com/sitespeedio/browsertime/pull/2522) [#2523](https://github.com/sitespeedio/browsertime/pull/2523) [#2526](https://github.com/sitespeedio/browsertime/pull/2526).
|
|
7
|
+
* New `pageinfo.loafSummary` key (`totalFrames`, `totalBlockingDuration`, `totalDuration`): `pageinfo.loaf` only ships the 10 frames with the most blocking, so totals computed from it understate busy pages [#2524](https://github.com/sitespeedio/browsertime/pull/2524).
|
|
8
|
+
* LoAF script URLs get the same ResourceLoader `label`s as `cpu.urls` (`load.php[startup]` and friends) [#2525](https://github.com/sitespeedio/browsertime/pull/2525).
|
|
9
|
+
* Multi-module `load.php` batches are labeled with their first module name — pages lazy-load several general batches, so the bare `load.php[scripts]` label collided as soon as there was more than one [#2527](https://github.com/sitespeedio/browsertime/pull/2527).
|
|
10
|
+
|
|
3
11
|
## 28.0.0 - 2026-07-17
|
|
4
12
|
|
|
5
13
|
### Breaking
|
|
@@ -17,6 +17,11 @@
|
|
|
17
17
|
// re-package
|
|
18
18
|
for (let entry of longestBlockingLoAFs) {
|
|
19
19
|
const info = {};
|
|
20
|
+
// startTime places the frame on the page timeline (before or
|
|
21
|
+
// after FCP/LCP/load); firstUIEventTimestamp > 0 means an input
|
|
22
|
+
// was waiting while this frame blocked — the INP connection.
|
|
23
|
+
info.startTime = entry.startTime;
|
|
24
|
+
info.firstUIEventTimestamp = entry.firstUIEventTimestamp;
|
|
20
25
|
info.blockingDuration = entry.blockingDuration;
|
|
21
26
|
info.duration = entry.duration;
|
|
22
27
|
info.styleAndLayoutStart = entry.styleAndLayoutStart;
|
|
@@ -29,6 +34,16 @@
|
|
|
29
34
|
info.scripts = [];
|
|
30
35
|
for (let script of entry.scripts) {
|
|
31
36
|
const s = {};
|
|
37
|
+
// startTime + duration make per-script attribution possible:
|
|
38
|
+
// without them a frame's blocking can only be credited to
|
|
39
|
+
// every script that ran in it.
|
|
40
|
+
s.startTime = script.startTime;
|
|
41
|
+
s.duration = script.duration;
|
|
42
|
+
// executionStart - startTime is queue/compile delay before the
|
|
43
|
+
// script ran; pauseDuration separates "computed the whole time"
|
|
44
|
+
// from "sat in a sync pause" (alert, sync XHR).
|
|
45
|
+
s.executionStart = script.executionStart;
|
|
46
|
+
s.pauseDuration = script.pauseDuration;
|
|
32
47
|
s.forcedStyleAndLayoutDuration = script.forcedStyleAndLayoutDuration;
|
|
33
48
|
s.invoker = script.invoker;
|
|
34
49
|
s.invokerType = script.invokerType;
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
(function () {
|
|
2
|
+
// The loaf script ships only the 10 frames with the most blocking
|
|
3
|
+
// time, so its numbers understate busy pages. These totals are
|
|
4
|
+
// computed over every long animation frame before the cut.
|
|
5
|
+
if (
|
|
6
|
+
PerformanceObserver.supportedEntryTypes.includes('long-animation-frame')
|
|
7
|
+
) {
|
|
8
|
+
const observer = new PerformanceObserver(list => {});
|
|
9
|
+
observer.observe({type: 'long-animation-frame', buffered: true});
|
|
10
|
+
const entries = observer.takeRecords();
|
|
11
|
+
|
|
12
|
+
let totalBlockingDuration = 0;
|
|
13
|
+
let totalDuration = 0;
|
|
14
|
+
for (let entry of entries) {
|
|
15
|
+
totalBlockingDuration += entry.blockingDuration;
|
|
16
|
+
totalDuration += entry.duration;
|
|
17
|
+
}
|
|
18
|
+
return {
|
|
19
|
+
totalFrames: entries.length,
|
|
20
|
+
totalBlockingDuration,
|
|
21
|
+
totalDuration
|
|
22
|
+
};
|
|
23
|
+
}
|
|
24
|
+
})();
|
|
@@ -96,12 +96,14 @@ export function labelForUrl(url) {
|
|
|
96
96
|
return 'load.php[startup]';
|
|
97
97
|
}
|
|
98
98
|
const kind = only === 'styles' ? 'styles' : 'scripts';
|
|
99
|
-
|
|
99
|
+
// Every multi-module batch carries its (alphabetically) first module
|
|
100
|
+
// name. Real pages lazy-load several general batches (no `only=`)
|
|
101
|
+
// over time, so a bare load.php[scripts] label collides as soon as
|
|
102
|
+
// there is more than one — and the single-module case already names
|
|
103
|
+
// general batches like raw ones.
|
|
104
|
+
if (modules.length > 0) {
|
|
100
105
|
return `load.php[${kind}:${modules[0]}]`;
|
|
101
106
|
}
|
|
102
|
-
if (modules.length > 1 && only === 'scripts') {
|
|
103
|
-
return `load.php[scripts:${modules[0]}]`;
|
|
104
|
-
}
|
|
105
107
|
return `load.php[${kind}]`;
|
|
106
108
|
}
|
|
107
109
|
|
|
@@ -395,6 +395,20 @@ export class Chromium {
|
|
|
395
395
|
// this hack fixes that
|
|
396
396
|
if (result.browserScripts && result.browserScripts.pageinfo) {
|
|
397
397
|
result.browserScripts.pageinfo.longTask = this.longTaskInfo;
|
|
398
|
+
|
|
399
|
+
// Resolve LoAF script URLs to ResourceLoader module labels the
|
|
400
|
+
// same way cpu.urls gets them — several frames all blaming one
|
|
401
|
+
// giant load.php URL say nothing without the module name.
|
|
402
|
+
if (Array.isArray(result.browserScripts.pageinfo.loaf)) {
|
|
403
|
+
for (const frame of result.browserScripts.pageinfo.loaf) {
|
|
404
|
+
for (const script of frame.scripts || []) {
|
|
405
|
+
const label = labelForUrl(script.sourceURL);
|
|
406
|
+
if (label) {
|
|
407
|
+
script.label = label;
|
|
408
|
+
}
|
|
409
|
+
}
|
|
410
|
+
}
|
|
411
|
+
}
|
|
398
412
|
}
|
|
399
413
|
|
|
400
414
|
if (this.chrome.collectNetLog && this.chrome.android) {
|
package/package.json
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"mediawikiResourceLoader.d.ts","sourceRoot":"","sources":["../../lib/chrome/mediawikiResourceLoader.js"],"names":[],"mappings":"AAmBA,mEAEC;AA6DD,
|
|
1
|
+
{"version":3,"file":"mediawikiResourceLoader.d.ts","sourceRoot":"","sources":["../../lib/chrome/mediawikiResourceLoader.js"],"names":[],"mappings":"AAmBA,mEAEC;AA6DD,8CAyBC;AAcD,8DAUC;AAwBD;;;;;EAkCC;AAOD,6EA4BC"}
|