@elastic/synthetics 1.0.0-beta.2 → 1.0.0-beta.22
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 +235 -0
- package/NOTICE.txt +250 -0
- package/README.md +2 -1
- package/dist/cli.js +87 -56
- package/dist/cli.js.map +1 -1
- package/dist/common_types.d.ts +116 -14
- package/dist/common_types.d.ts.map +1 -1
- package/dist/config.d.ts +2 -5
- package/dist/config.d.ts.map +1 -1
- package/dist/config.js +5 -5
- package/dist/config.js.map +1 -1
- package/dist/core/browser-service.js +5 -5
- package/dist/core/browser-service.js.map +1 -1
- package/dist/core/expect.d.ts +177 -0
- package/dist/core/expect.d.ts.map +1 -0
- package/dist/core/expect.js +33 -0
- package/dist/core/expect.js.map +1 -0
- package/dist/core/gatherer.d.ts +4 -7
- package/dist/core/gatherer.d.ts.map +1 -1
- package/dist/core/gatherer.js +39 -12
- package/dist/core/gatherer.js.map +1 -1
- package/dist/core/index.d.ts +5 -5
- package/dist/core/index.d.ts.map +1 -1
- package/dist/core/index.js +2 -2
- package/dist/core/index.js.map +1 -1
- package/dist/core/logger.d.ts +0 -1
- package/dist/core/logger.d.ts.map +1 -1
- package/dist/core/logger.js +3 -16
- package/dist/core/logger.js.map +1 -1
- package/dist/core/runner.d.ts +54 -45
- package/dist/core/runner.d.ts.map +1 -1
- package/dist/core/runner.js +181 -71
- package/dist/core/runner.js.map +1 -1
- package/dist/dsl/journey.d.ts +13 -4
- package/dist/dsl/journey.d.ts.map +1 -1
- package/dist/dsl/journey.js +40 -1
- package/dist/dsl/journey.js.map +1 -1
- package/dist/formatter/javascript.d.ts +73 -0
- package/dist/formatter/javascript.d.ts.map +1 -0
- package/dist/formatter/javascript.js +274 -0
- package/dist/formatter/javascript.js.map +1 -0
- package/dist/helpers.d.ts +33 -12
- package/dist/helpers.d.ts.map +1 -1
- package/dist/helpers.js +108 -54
- package/dist/helpers.js.map +1 -1
- package/dist/index.d.ts +8 -0
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +6 -7
- package/dist/index.js.map +1 -1
- package/dist/parse_args.d.ts +5 -2
- package/dist/parse_args.d.ts.map +1 -1
- package/dist/parse_args.js +59 -16
- package/dist/parse_args.js.map +1 -1
- package/dist/plugins/browser-console.d.ts +5 -8
- package/dist/plugins/browser-console.d.ts.map +1 -1
- package/dist/plugins/browser-console.js +27 -8
- package/dist/plugins/browser-console.js.map +1 -1
- package/dist/plugins/network.d.ts +23 -20
- package/dist/plugins/network.d.ts.map +1 -1
- package/dist/plugins/network.js +149 -124
- package/dist/plugins/network.js.map +1 -1
- package/dist/plugins/performance.d.ts +5 -5
- package/dist/plugins/performance.d.ts.map +1 -1
- package/dist/plugins/performance.js +5 -5
- package/dist/plugins/performance.js.map +1 -1
- package/dist/plugins/plugin-manager.d.ts +11 -11
- package/dist/plugins/plugin-manager.d.ts.map +1 -1
- package/dist/plugins/plugin-manager.js +40 -24
- package/dist/plugins/plugin-manager.js.map +1 -1
- package/dist/plugins/tracing.d.ts +10 -25
- package/dist/plugins/tracing.d.ts.map +1 -1
- package/dist/plugins/tracing.js +40 -26
- package/dist/plugins/tracing.js.map +1 -1
- package/dist/reporters/base.d.ts +0 -1
- package/dist/reporters/base.d.ts.map +1 -1
- package/dist/reporters/base.js +34 -32
- package/dist/reporters/base.js.map +1 -1
- package/dist/reporters/json.d.ts +46 -59
- package/dist/reporters/json.d.ts.map +1 -1
- package/dist/reporters/json.js +188 -70
- package/dist/reporters/json.js.map +1 -1
- package/dist/reporters/junit.d.ts.map +1 -1
- package/dist/reporters/junit.js +7 -7
- package/dist/reporters/junit.js.map +1 -1
- package/dist/sdk/lh-trace-processor.d.ts +304 -0
- package/dist/sdk/lh-trace-processor.d.ts.map +1 -0
- package/dist/sdk/lh-trace-processor.js +832 -0
- package/dist/sdk/lh-trace-processor.js.map +1 -0
- package/dist/sdk/trace-metrics.d.ts +61 -0
- package/dist/sdk/trace-metrics.d.ts.map +1 -0
- package/dist/sdk/trace-metrics.js +252 -0
- package/dist/sdk/trace-metrics.js.map +1 -0
- package/dist/sdk/trace-processor.d.ts +106 -0
- package/dist/sdk/trace-processor.d.ts.map +1 -0
- package/dist/sdk/trace-processor.js +74 -0
- package/dist/sdk/trace-processor.js.map +1 -0
- package/dist/tsconfig.tsbuildinfo +1 -1575
- package/package.json +27 -16
- package/src/cli.ts +68 -45
- package/src/common_types.ts +138 -14
- package/src/config.ts +2 -5
- package/src/core/expect.ts +187 -0
- package/src/core/gatherer.ts +48 -24
- package/src/core/index.ts +6 -6
- package/src/core/logger.ts +1 -12
- package/src/core/runner.ts +259 -112
- package/src/dsl/journey.ts +28 -6
- package/src/formatter/javascript.ts +330 -0
- package/src/helpers.ts +114 -24
- package/src/index.ts +7 -6
- package/src/parse_args.ts +97 -22
- package/src/plugins/browser-console.ts +30 -13
- package/src/plugins/network.ts +175 -159
- package/src/plugins/performance.ts +7 -7
- package/src/plugins/plugin-manager.ts +47 -36
- package/src/plugins/tracing.ts +43 -54
- package/src/reporters/base.ts +29 -23
- package/src/reporters/json.ts +259 -80
- package/src/reporters/junit.ts +1 -1
- package/src/sdk/lh-trace-processor.ts +1033 -0
- package/src/sdk/trace-metrics.ts +287 -0
- package/src/sdk/trace-processor.ts +147 -0
|
@@ -0,0 +1,287 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* MIT License
|
|
3
|
+
*
|
|
4
|
+
* Copyright (c) 2020-present, Elastic NV
|
|
5
|
+
*
|
|
6
|
+
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
7
|
+
* of this software and associated documentation files (the "Software"), to deal
|
|
8
|
+
* in the Software without restriction, including without limitation the rights
|
|
9
|
+
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
10
|
+
* copies of the Software, and to permit persons to whom the Software is
|
|
11
|
+
* furnished to do so, subject to the following conditions:
|
|
12
|
+
*
|
|
13
|
+
* The above copyright notice and this permission notice shall be included in
|
|
14
|
+
* all copies or substantial portions of the Software.
|
|
15
|
+
*
|
|
16
|
+
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
17
|
+
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
18
|
+
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
19
|
+
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
20
|
+
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
21
|
+
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
|
22
|
+
* THE SOFTWARE.
|
|
23
|
+
*
|
|
24
|
+
*/
|
|
25
|
+
|
|
26
|
+
import { Filmstrip, TraceOutput } from '../common_types';
|
|
27
|
+
import type {
|
|
28
|
+
LHProcessedNavigation,
|
|
29
|
+
LHProcessedTrace,
|
|
30
|
+
TraceEvent,
|
|
31
|
+
} from './trace-processor';
|
|
32
|
+
|
|
33
|
+
export class UserTimings {
|
|
34
|
+
static compute(trace: LHProcessedTrace) {
|
|
35
|
+
const { processEvents } = trace;
|
|
36
|
+
const measuresMap = new Map();
|
|
37
|
+
const userTimings: Array<TraceOutput> = [];
|
|
38
|
+
|
|
39
|
+
for (const event of processEvents) {
|
|
40
|
+
const { name, ph, ts, args } = event;
|
|
41
|
+
|
|
42
|
+
if (!event.cat.includes('blink.user_timing')) {
|
|
43
|
+
continue;
|
|
44
|
+
}
|
|
45
|
+
// discard all browser level mark events with frame data
|
|
46
|
+
if (
|
|
47
|
+
name === 'requestStart' ||
|
|
48
|
+
name === 'navigationStart' ||
|
|
49
|
+
name === 'paintNonDefaultBackgroundColor' ||
|
|
50
|
+
args.frame !== undefined
|
|
51
|
+
) {
|
|
52
|
+
continue;
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
/**
|
|
56
|
+
* user timing mark events falls under `R` and i or I
|
|
57
|
+
* measure events starts with `b` and ends with `e`
|
|
58
|
+
* Doc - https://docs.google.com/document/d/1CvAClvFfyA5R-PhYUmn5OOQtYMH4h6I0nSsKchNAySU/edit#heading=h.puwqg050lyuy
|
|
59
|
+
*/
|
|
60
|
+
const phase = ph.toLowerCase();
|
|
61
|
+
if (phase === 'r' || phase === 'i') {
|
|
62
|
+
userTimings.push({
|
|
63
|
+
name,
|
|
64
|
+
type: 'mark',
|
|
65
|
+
start: {
|
|
66
|
+
us: ts,
|
|
67
|
+
},
|
|
68
|
+
});
|
|
69
|
+
} else if (phase === 'b') {
|
|
70
|
+
measuresMap.set(name, ts);
|
|
71
|
+
} else if (phase === 'e') {
|
|
72
|
+
const startTime = measuresMap.get(name);
|
|
73
|
+
userTimings.push({
|
|
74
|
+
name,
|
|
75
|
+
type: 'measure',
|
|
76
|
+
start: {
|
|
77
|
+
us: startTime,
|
|
78
|
+
},
|
|
79
|
+
duration: {
|
|
80
|
+
us: ts - startTime,
|
|
81
|
+
},
|
|
82
|
+
});
|
|
83
|
+
}
|
|
84
|
+
}
|
|
85
|
+
return userTimings;
|
|
86
|
+
}
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
export class ExperienceMetrics {
|
|
90
|
+
static buildMetric(name: string, timestamp?: number) {
|
|
91
|
+
if (!timestamp) {
|
|
92
|
+
return;
|
|
93
|
+
}
|
|
94
|
+
return {
|
|
95
|
+
name,
|
|
96
|
+
type: 'mark',
|
|
97
|
+
start: {
|
|
98
|
+
us: timestamp,
|
|
99
|
+
},
|
|
100
|
+
};
|
|
101
|
+
}
|
|
102
|
+
|
|
103
|
+
static compute(trace: LHProcessedNavigation) {
|
|
104
|
+
const traces: Array<TraceOutput> = [];
|
|
105
|
+
const { timestamps, timings, lcpInvalidated } = trace;
|
|
106
|
+
|
|
107
|
+
traces.push(this.buildMetric('navigationStart', timestamps.timeOrigin));
|
|
108
|
+
traces.push(
|
|
109
|
+
this.buildMetric('firstContentfulPaint', timestamps.firstContentfulPaint)
|
|
110
|
+
);
|
|
111
|
+
/**
|
|
112
|
+
* lcpInvalidated - Denotes when all of the LCP events that comes from the
|
|
113
|
+
* current trace are invalidated. Happens if the previous LCP candidates were
|
|
114
|
+
* suppressed by another event coming later during the page load
|
|
115
|
+
* More info - https://github.com/WICG/largest-contentful-paint/#the-last-candidate
|
|
116
|
+
*/
|
|
117
|
+
!lcpInvalidated &&
|
|
118
|
+
traces.push(
|
|
119
|
+
this.buildMetric(
|
|
120
|
+
'largestContentfulPaint',
|
|
121
|
+
timestamps.largestContentfulPaint
|
|
122
|
+
)
|
|
123
|
+
);
|
|
124
|
+
traces.push(
|
|
125
|
+
this.buildMetric('domContentLoaded', timestamps.domContentLoaded)
|
|
126
|
+
);
|
|
127
|
+
traces.push(this.buildMetric('loadEvent', timestamps.load));
|
|
128
|
+
|
|
129
|
+
/**
|
|
130
|
+
* Lighthouse tracer extracts these metrics in milliseconds resolution,
|
|
131
|
+
* we convert them to microseconds resolution to keep them in sync with
|
|
132
|
+
* other timings
|
|
133
|
+
*/
|
|
134
|
+
const millisToMicros = (value?: number) =>
|
|
135
|
+
value ? value * 1000 : undefined;
|
|
136
|
+
const keys = [
|
|
137
|
+
'firstContentfulPaint',
|
|
138
|
+
'largestContentfulPaint',
|
|
139
|
+
'domContentLoaded',
|
|
140
|
+
'load',
|
|
141
|
+
];
|
|
142
|
+
const values = ['fcp', 'lcp', 'dcl', 'load'];
|
|
143
|
+
const metrics = {};
|
|
144
|
+
|
|
145
|
+
for (let i = 0; i < keys.length; i++) {
|
|
146
|
+
const microSecs = millisToMicros(timings[keys[i]]);
|
|
147
|
+
if (microSecs) {
|
|
148
|
+
metrics[values[i]] = { us: microSecs };
|
|
149
|
+
}
|
|
150
|
+
}
|
|
151
|
+
|
|
152
|
+
return {
|
|
153
|
+
metrics,
|
|
154
|
+
traces: traces.filter(b => Boolean(b)),
|
|
155
|
+
};
|
|
156
|
+
}
|
|
157
|
+
}
|
|
158
|
+
|
|
159
|
+
export class CumulativeLayoutShift {
|
|
160
|
+
static getLayoutShiftEvents(traceEvents: Array<TraceEvent>) {
|
|
161
|
+
const layoutShiftEvents = [];
|
|
162
|
+
// Chromium will set `had_recent_input` if there was recent user input, which
|
|
163
|
+
// skips shift events from contributing to CLS. This results in the first few shift
|
|
164
|
+
// events having `had_recent_input` set to true, so ignore it for those events.
|
|
165
|
+
// See https://crbug.com/1094974
|
|
166
|
+
let ignoreHadRecentInput = true;
|
|
167
|
+
|
|
168
|
+
for (const event of traceEvents) {
|
|
169
|
+
// weighted_score_delta was added in chrome 90 - https://crbug.com/1173139
|
|
170
|
+
if (
|
|
171
|
+
event.name !== 'LayoutShift' ||
|
|
172
|
+
!event.args?.data.is_main_frame ||
|
|
173
|
+
!event.args?.data.weighted_score_delta
|
|
174
|
+
) {
|
|
175
|
+
continue;
|
|
176
|
+
}
|
|
177
|
+
|
|
178
|
+
if (event.args.data.had_recent_input) {
|
|
179
|
+
if (!ignoreHadRecentInput) continue;
|
|
180
|
+
} else {
|
|
181
|
+
ignoreHadRecentInput = false;
|
|
182
|
+
}
|
|
183
|
+
|
|
184
|
+
layoutShiftEvents.push({
|
|
185
|
+
ts: event.ts,
|
|
186
|
+
weightedScore: event.args.data.weighted_score_delta,
|
|
187
|
+
});
|
|
188
|
+
}
|
|
189
|
+
|
|
190
|
+
return layoutShiftEvents;
|
|
191
|
+
}
|
|
192
|
+
|
|
193
|
+
/**
|
|
194
|
+
* Calculate cumulative layout shift per sesion window where each session
|
|
195
|
+
* windows lasts for 5 seconds since the last layoutShift event and has 1 second
|
|
196
|
+
* gap between them. Return the maximum score between all windows.
|
|
197
|
+
* More details - https://web.dev/evolving-cls/
|
|
198
|
+
*/
|
|
199
|
+
static calculateScore(layoutShiftEvents) {
|
|
200
|
+
const gapMicroseconds = 1_000_000; // 1 seconds gap
|
|
201
|
+
const limitMicroseconds = 5_000_000; // 5 seconds window
|
|
202
|
+
let maxScore = 0;
|
|
203
|
+
let currentScore = 0;
|
|
204
|
+
let firstTimestamp = Number.NEGATIVE_INFINITY;
|
|
205
|
+
let prevTimestamp = Number.NEGATIVE_INFINITY;
|
|
206
|
+
|
|
207
|
+
for (const event of layoutShiftEvents) {
|
|
208
|
+
const currTimestamp = event.ts;
|
|
209
|
+
/**
|
|
210
|
+
* Two cases
|
|
211
|
+
* - When the next layout shift event happened after the session window of
|
|
212
|
+
* 5 seconds.
|
|
213
|
+
* - When the next and previous layout shift event has a gap of 1 second
|
|
214
|
+
*
|
|
215
|
+
* Then consider the layout shift event as the start of
|
|
216
|
+
* the current session window and reset the cumulative score.
|
|
217
|
+
*/
|
|
218
|
+
if (
|
|
219
|
+
currTimestamp - firstTimestamp > limitMicroseconds ||
|
|
220
|
+
currTimestamp - prevTimestamp > gapMicroseconds
|
|
221
|
+
) {
|
|
222
|
+
firstTimestamp = currTimestamp;
|
|
223
|
+
currentScore = 0;
|
|
224
|
+
}
|
|
225
|
+
prevTimestamp = currTimestamp;
|
|
226
|
+
currentScore += event.weightedScore;
|
|
227
|
+
maxScore = Math.max(maxScore, currentScore);
|
|
228
|
+
}
|
|
229
|
+
|
|
230
|
+
return maxScore;
|
|
231
|
+
}
|
|
232
|
+
|
|
233
|
+
static compute(trace: LHProcessedTrace) {
|
|
234
|
+
const layoutShiftEvents = this.getLayoutShiftEvents(trace.frameTreeEvents);
|
|
235
|
+
const traces: Array<TraceOutput> = layoutShiftEvents.map(event => {
|
|
236
|
+
return {
|
|
237
|
+
name: 'layoutShift',
|
|
238
|
+
type: 'mark',
|
|
239
|
+
start: {
|
|
240
|
+
us: event.ts,
|
|
241
|
+
},
|
|
242
|
+
score: event.weightedScore,
|
|
243
|
+
};
|
|
244
|
+
});
|
|
245
|
+
const cumulativeLayoutShiftScore = this.calculateScore(layoutShiftEvents);
|
|
246
|
+
|
|
247
|
+
return {
|
|
248
|
+
cls: cumulativeLayoutShiftScore,
|
|
249
|
+
traces,
|
|
250
|
+
};
|
|
251
|
+
}
|
|
252
|
+
}
|
|
253
|
+
|
|
254
|
+
export class Filmstrips {
|
|
255
|
+
static filterExcesssiveScreenshots(events: Array<TraceEvent>) {
|
|
256
|
+
const screenshotEvents = events.filter(
|
|
257
|
+
evt => evt.name === 'Screenshot' && evt.args?.snapshot
|
|
258
|
+
);
|
|
259
|
+
const screenshotTimestamps = screenshotEvents.map(event => event.ts);
|
|
260
|
+
|
|
261
|
+
let lastScreenshotTs = -Infinity;
|
|
262
|
+
return screenshotEvents.filter(evt => {
|
|
263
|
+
const timeSinceLastScreenshot = evt.ts - lastScreenshotTs;
|
|
264
|
+
const nextScreenshotTs = screenshotTimestamps.find(ts => ts > evt.ts);
|
|
265
|
+
const timeUntilNextScreenshot = nextScreenshotTs
|
|
266
|
+
? nextScreenshotTs - evt.ts
|
|
267
|
+
: Infinity;
|
|
268
|
+
const threshold = 500 * 1000; // Throttle to ~2fps
|
|
269
|
+
// Keep the frame if it's been more than 500ms since the last frame we kept or the next frame won't happen for at least 500ms
|
|
270
|
+
const shouldKeep =
|
|
271
|
+
timeUntilNextScreenshot > threshold ||
|
|
272
|
+
timeSinceLastScreenshot > threshold;
|
|
273
|
+
if (shouldKeep) lastScreenshotTs = evt.ts;
|
|
274
|
+
return shouldKeep;
|
|
275
|
+
});
|
|
276
|
+
}
|
|
277
|
+
|
|
278
|
+
static compute(traceEvents: Array<TraceEvent>): Array<Filmstrip> {
|
|
279
|
+
return Filmstrips.filterExcesssiveScreenshots(traceEvents).map(event => ({
|
|
280
|
+
blob: event.args.snapshot,
|
|
281
|
+
mime: 'image/jpeg',
|
|
282
|
+
start: {
|
|
283
|
+
us: event.ts,
|
|
284
|
+
},
|
|
285
|
+
}));
|
|
286
|
+
}
|
|
287
|
+
}
|
|
@@ -0,0 +1,147 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* MIT License
|
|
3
|
+
*
|
|
4
|
+
* Copyright (c) 2020-present, Elastic NV
|
|
5
|
+
*
|
|
6
|
+
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
7
|
+
* of this software and associated documentation files (the "Software"), to deal
|
|
8
|
+
* in the Software without restriction, including without limitation the rights
|
|
9
|
+
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
10
|
+
* copies of the Software, and to permit persons to whom the Software is
|
|
11
|
+
* furnished to do so, subject to the following conditions:
|
|
12
|
+
*
|
|
13
|
+
* The above copyright notice and this permission notice shall be included in
|
|
14
|
+
* all copies or substantial portions of the Software.
|
|
15
|
+
*
|
|
16
|
+
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
17
|
+
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
18
|
+
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
19
|
+
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
20
|
+
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
21
|
+
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
|
22
|
+
* THE SOFTWARE.
|
|
23
|
+
*
|
|
24
|
+
*/
|
|
25
|
+
|
|
26
|
+
import LighthouseTraceProcessor from './lh-trace-processor';
|
|
27
|
+
import {
|
|
28
|
+
ExperienceMetrics,
|
|
29
|
+
CumulativeLayoutShift,
|
|
30
|
+
UserTimings,
|
|
31
|
+
} from './trace-metrics';
|
|
32
|
+
import { PerfMetrics } from '../common_types';
|
|
33
|
+
import { log } from '../core/logger';
|
|
34
|
+
|
|
35
|
+
const ACCEPTABLE_NAVIGATION_URL_REGEX = /^(file|https?):/;
|
|
36
|
+
|
|
37
|
+
/**
|
|
38
|
+
* Trace Event Format
|
|
39
|
+
* https://docs.google.com/document/d/1CvAClvFfyA5R-PhYUmn5OOQtYMH4h6I0nSsKchNAySU
|
|
40
|
+
*/
|
|
41
|
+
export type TraceEvent = {
|
|
42
|
+
name: string;
|
|
43
|
+
// event category
|
|
44
|
+
cat: string;
|
|
45
|
+
// process id
|
|
46
|
+
pid: number;
|
|
47
|
+
// thread id
|
|
48
|
+
tid: number;
|
|
49
|
+
// event phase
|
|
50
|
+
ph?: string;
|
|
51
|
+
args?: {
|
|
52
|
+
snapshot?: string;
|
|
53
|
+
frame: string;
|
|
54
|
+
data: {
|
|
55
|
+
had_recent_input: boolean;
|
|
56
|
+
is_main_frame: boolean;
|
|
57
|
+
cumulative_score: number;
|
|
58
|
+
score: number;
|
|
59
|
+
weighted_score_delta: number;
|
|
60
|
+
} & Record<string, unknown>;
|
|
61
|
+
};
|
|
62
|
+
/**
|
|
63
|
+
* Platform specific monotonic non decreasing clock time
|
|
64
|
+
* https://source.chromium.org/chromium/chromium/src/+/master:base/time/time.h;l=936;bpv=0;bpt=0
|
|
65
|
+
*
|
|
66
|
+
* The tracing clock timestamp of the event. The timestamps are provided at microsecond granularity.
|
|
67
|
+
*/
|
|
68
|
+
ts: number;
|
|
69
|
+
};
|
|
70
|
+
|
|
71
|
+
/**
|
|
72
|
+
* Exported data from Lighthouse trace processor
|
|
73
|
+
*/
|
|
74
|
+
type LHTraceTime = {
|
|
75
|
+
timeOrigin: number;
|
|
76
|
+
firstPaint: number;
|
|
77
|
+
firstContentfulPaint: number;
|
|
78
|
+
largestContentfulPaint: number;
|
|
79
|
+
largestContentfulPaintAllFrames: number;
|
|
80
|
+
domContentLoaded: number;
|
|
81
|
+
load: number;
|
|
82
|
+
traceEnd: number;
|
|
83
|
+
};
|
|
84
|
+
|
|
85
|
+
export type LHProcessedNavigation = {
|
|
86
|
+
domContentLoadedEvt: TraceEvent;
|
|
87
|
+
firstContentfulPaintEvt: TraceEvent;
|
|
88
|
+
largestContentfulPaintEvt: TraceEvent;
|
|
89
|
+
loadEvt: TraceEvent;
|
|
90
|
+
timestamps: LHTraceTime;
|
|
91
|
+
timings: LHTraceTime;
|
|
92
|
+
lcpInvalidated: boolean;
|
|
93
|
+
};
|
|
94
|
+
|
|
95
|
+
export type LHProcessedTrace = {
|
|
96
|
+
processEvents: Array<TraceEvent>;
|
|
97
|
+
frameEvents: Array<TraceEvent>;
|
|
98
|
+
mainThreadEvents: Array<TraceEvent>;
|
|
99
|
+
frameTreeEvents: Array<TraceEvent>;
|
|
100
|
+
timeOriginEvt: TraceEvent;
|
|
101
|
+
timestamps: Partial<LHTraceTime>;
|
|
102
|
+
timings: Partial<LHTraceTime>;
|
|
103
|
+
};
|
|
104
|
+
|
|
105
|
+
/**
|
|
106
|
+
* Extends the lighthouse trace processor which extracts all the meaningful trace
|
|
107
|
+
* events in chronological order from the tab's process
|
|
108
|
+
*
|
|
109
|
+
* We extend Lighthouse Processor instead of calling it directy as we want to control
|
|
110
|
+
* what is the interest event for Navigation start and also in future we want to measure
|
|
111
|
+
* metrics based on multiple navigations instead of a single navigation.
|
|
112
|
+
*/
|
|
113
|
+
export class TraceProcessor extends LighthouseTraceProcessor {
|
|
114
|
+
static override _isNavigationStartOfInterest(event) {
|
|
115
|
+
return (
|
|
116
|
+
event.name === 'navigationStart' &&
|
|
117
|
+
(!event.args.data ||
|
|
118
|
+
!event.args.data.documentLoaderURL ||
|
|
119
|
+
ACCEPTABLE_NAVIGATION_URL_REGEX.test(event.args.data.documentLoaderURL))
|
|
120
|
+
);
|
|
121
|
+
}
|
|
122
|
+
|
|
123
|
+
static computeTrace(traceEvents: Array<TraceEvent>) {
|
|
124
|
+
// Origin of the trace is based on the last navigation event
|
|
125
|
+
const options = {
|
|
126
|
+
timeOriginDeterminationMethod: 'lastNavigationStart',
|
|
127
|
+
};
|
|
128
|
+
try {
|
|
129
|
+
const processedTrace = this.processTrace({ traceEvents }, options);
|
|
130
|
+
const processedNavigation = this.processNavigation(processedTrace);
|
|
131
|
+
const userTiming = UserTimings.compute(processedTrace);
|
|
132
|
+
const { traces: expTraces, metrics } =
|
|
133
|
+
ExperienceMetrics.compute(processedNavigation);
|
|
134
|
+
const { cls, traces: layoutTraces } =
|
|
135
|
+
CumulativeLayoutShift.compute(processedTrace);
|
|
136
|
+
const perfMetrics: Partial<PerfMetrics> = { cls, ...metrics };
|
|
137
|
+
|
|
138
|
+
return {
|
|
139
|
+
traces: userTiming.concat(expTraces, layoutTraces),
|
|
140
|
+
metrics: perfMetrics,
|
|
141
|
+
};
|
|
142
|
+
} catch (e) {
|
|
143
|
+
log(e);
|
|
144
|
+
return {};
|
|
145
|
+
}
|
|
146
|
+
}
|
|
147
|
+
}
|