|
14 | 14 | * limitations under the License.
|
15 | 15 | */
|
16 | 16 |
|
| 17 | +import { WINDOW } from '../../types'; |
17 | 18 | import { bindReporter } from './lib/bindReporter';
|
18 | 19 | import { initMetric } from './lib/initMetric';
|
| 20 | +import { initUnique } from './lib/initUnique'; |
| 21 | +import { LayoutShiftManager } from './lib/LayoutShiftManager'; |
19 | 22 | import { observe } from './lib/observe';
|
20 |
| -import { onHidden } from './lib/onHidden'; |
21 | 23 | import { runOnce } from './lib/runOnce';
|
22 | 24 | import { onFCP } from './onFCP';
|
23 | 25 | import type { CLSMetric, MetricRatingThresholds, ReportOpts } from './types';
|
@@ -54,58 +56,37 @@ export const onCLS = (onReport: (metric: CLSMetric) => void, opts: ReportOpts =
|
54 | 56 | const metric = initMetric('CLS', 0);
|
55 | 57 | let report: ReturnType<typeof bindReporter>;
|
56 | 58 |
|
57 |
| - let sessionValue = 0; |
58 |
| - let sessionEntries: LayoutShift[] = []; |
| 59 | + const layoutShiftManager = initUnique(opts, LayoutShiftManager); |
59 | 60 |
|
60 | 61 | const handleEntries = (entries: LayoutShift[]) => {
|
61 |
| - entries.forEach(entry => { |
62 |
| - // Only count layout shifts without recent user input. |
63 |
| - if (!entry.hadRecentInput) { |
64 |
| - const firstSessionEntry = sessionEntries[0]; |
65 |
| - const lastSessionEntry = sessionEntries[sessionEntries.length - 1]; |
66 |
| - |
67 |
| - // If the entry occurred less than 1 second after the previous entry |
68 |
| - // and less than 5 seconds after the first entry in the session, |
69 |
| - // include the entry in the current session. Otherwise, start a new |
70 |
| - // session. |
71 |
| - if ( |
72 |
| - sessionValue && |
73 |
| - firstSessionEntry && |
74 |
| - lastSessionEntry && |
75 |
| - entry.startTime - lastSessionEntry.startTime < 1000 && |
76 |
| - entry.startTime - firstSessionEntry.startTime < 5000 |
77 |
| - ) { |
78 |
| - sessionValue += entry.value; |
79 |
| - sessionEntries.push(entry); |
80 |
| - } else { |
81 |
| - sessionValue = entry.value; |
82 |
| - sessionEntries = [entry]; |
83 |
| - } |
84 |
| - } |
85 |
| - }); |
| 62 | + for (const entry of entries) { |
| 63 | + layoutShiftManager._processEntry(entry); |
| 64 | + } |
86 | 65 |
|
87 | 66 | // If the current session value is larger than the current CLS value,
|
88 | 67 | // update CLS and the entries contributing to it.
|
89 |
| - if (sessionValue > metric.value) { |
90 |
| - metric.value = sessionValue; |
91 |
| - metric.entries = sessionEntries; |
| 68 | + if (layoutShiftManager._sessionValue > metric.value) { |
| 69 | + metric.value = layoutShiftManager._sessionValue; |
| 70 | + metric.entries = layoutShiftManager._sessionEntries; |
92 | 71 | report();
|
93 | 72 | }
|
94 | 73 | };
|
95 | 74 |
|
96 | 75 | const po = observe('layout-shift', handleEntries);
|
97 | 76 | if (po) {
|
98 |
| - report = bindReporter(onReport, metric, CLSThresholds, opts.reportAllChanges); |
| 77 | + report = bindReporter(onReport, metric, CLSThresholds, opts!.reportAllChanges); |
99 | 78 |
|
100 |
| - onHidden(() => { |
101 |
| - handleEntries(po.takeRecords() as CLSMetric['entries']); |
102 |
| - report(true); |
| 79 | + WINDOW.document?.addEventListener('visibilitychange', () => { |
| 80 | + if (WINDOW.document?.visibilityState === 'hidden') { |
| 81 | + handleEntries(po.takeRecords() as CLSMetric['entries']); |
| 82 | + report(true); |
| 83 | + } |
103 | 84 | });
|
104 | 85 |
|
105 | 86 | // Queue a task to report (if nothing else triggers a report first).
|
106 | 87 | // This allows CLS to be reported as soon as FCP fires when
|
107 | 88 | // `reportAllChanges` is true.
|
108 |
| - setTimeout(report, 0); |
| 89 | + WINDOW?.setTimeout?.(report); |
109 | 90 | }
|
110 | 91 | }),
|
111 | 92 | );
|
|
0 commit comments