@adobe/helix-rum-enhancer 2.7.3 → 2.7.5
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 +14 -0
- package/package.json +3 -3
- package/src/index.js +122 -91
package/CHANGELOG.md
CHANGED
|
@@ -1,3 +1,17 @@
|
|
|
1
|
+
## [2.7.5](https://github.com/adobe/helix-rum-enhancer/compare/v2.7.4...v2.7.5) (2024-05-14)
|
|
2
|
+
|
|
3
|
+
|
|
4
|
+
### Bug Fixes
|
|
5
|
+
|
|
6
|
+
* in case window.hlx exists but window.hlx.rum is undefined ([581653b](https://github.com/adobe/helix-rum-enhancer/commit/581653b8e4e3e28c0c8de314454025cd8dbf4618))
|
|
7
|
+
|
|
8
|
+
## [2.7.4](https://github.com/adobe/helix-rum-enhancer/compare/v2.7.3...v2.7.4) (2024-05-02)
|
|
9
|
+
|
|
10
|
+
|
|
11
|
+
### Bug Fixes
|
|
12
|
+
|
|
13
|
+
* catch potential exceptions and errors ([99ab83e](https://github.com/adobe/helix-rum-enhancer/commit/99ab83eae7ebc3a2c27df7887a57f58307e6ca61))
|
|
14
|
+
|
|
1
15
|
## [2.7.3](https://github.com/adobe/helix-rum-enhancer/compare/v2.7.2...v2.7.3) (2024-04-22)
|
|
2
16
|
|
|
3
17
|
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@adobe/helix-rum-enhancer",
|
|
3
|
-
"version": "2.7.
|
|
3
|
+
"version": "2.7.5",
|
|
4
4
|
"description": "Helix RUM Enhancer",
|
|
5
5
|
"main": "src/index.js",
|
|
6
6
|
"type": "module",
|
|
@@ -32,7 +32,7 @@
|
|
|
32
32
|
"@adobe/eslint-config-helix": "2.0.6",
|
|
33
33
|
"@semantic-release/changelog": "6.0.3",
|
|
34
34
|
"@semantic-release/git": "10.0.1",
|
|
35
|
-
"@semantic-release/npm": "12.0.
|
|
35
|
+
"@semantic-release/npm": "12.0.1",
|
|
36
36
|
"c8": "9.1.0",
|
|
37
37
|
"codecov": "3.8.3",
|
|
38
38
|
"eslint": "8.57.0",
|
|
@@ -44,7 +44,7 @@
|
|
|
44
44
|
"lint-staged": "15.2.2",
|
|
45
45
|
"mocha": "10.4.0",
|
|
46
46
|
"mocha-multi-reporters": "1.5.1",
|
|
47
|
-
"semantic-release": "23.
|
|
47
|
+
"semantic-release": "23.1.1"
|
|
48
48
|
},
|
|
49
49
|
"lint-staged": {
|
|
50
50
|
"*.js": "eslint",
|
package/src/index.js
CHANGED
|
@@ -12,7 +12,7 @@
|
|
|
12
12
|
/* eslint-env browser */
|
|
13
13
|
const KNOWN_PROPERTIES = ['weight', 'id', 'referer', 'checkpoint', 't', 'source', 'target', 'cwv', 'CLS', 'FID', 'LCP', 'INP', 'TTFB'];
|
|
14
14
|
const DEFAULT_TRACKING_EVENTS = ['click', 'cwv', 'form', 'enterleave', 'viewblock', 'viewmedia', 'loadresource', 'utm'];
|
|
15
|
-
const { sampleRUM, queue, isSelected } = window.hlx.rum;
|
|
15
|
+
const { sampleRUM, queue, isSelected } = (window.hlx && window.hlx.rum) ? window.hlx.rum : {};
|
|
16
16
|
|
|
17
17
|
const urlSanitizers = {
|
|
18
18
|
full: () => window.location.href,
|
|
@@ -24,46 +24,55 @@ const getTargetValue = (element) => element.getAttribute('data-rum-target') || e
|
|
|
24
24
|
|| element.currentSrc || element.getAttribute('src') || element.dataset.action || element.action;
|
|
25
25
|
|
|
26
26
|
const targetselector = (element) => {
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
value
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
27
|
+
try {
|
|
28
|
+
if (!element) return undefined;
|
|
29
|
+
let value = getTargetValue(element);
|
|
30
|
+
if (!value && element.tagName !== 'A' && element.closest('a')) {
|
|
31
|
+
value = getTargetValue(element.closest('a'));
|
|
32
|
+
}
|
|
33
|
+
if (value && !value.startsWith('https://')) {
|
|
34
|
+
// resolve relative links
|
|
35
|
+
value = new URL(value, window.location).href;
|
|
36
|
+
}
|
|
37
|
+
return value;
|
|
38
|
+
} catch (error) {
|
|
39
|
+
// something went wrong
|
|
40
|
+
return null;
|
|
35
41
|
}
|
|
36
|
-
return value;
|
|
37
42
|
};
|
|
38
43
|
|
|
39
44
|
const sourceselector = (element) => {
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
45
|
+
try {
|
|
46
|
+
if (element === document.body || element === document.documentElement || !element) {
|
|
47
|
+
return undefined;
|
|
48
|
+
}
|
|
49
|
+
if (element.getAttribute('data-rum-source')) {
|
|
50
|
+
return element.getAttribute('data-rum-source');
|
|
51
|
+
}
|
|
52
|
+
const form = element.closest('form');
|
|
53
|
+
let formElementSelector = '';
|
|
54
|
+
if (form && Array.from(form.elements).includes(element)) {
|
|
55
|
+
formElementSelector = element.tagName === 'INPUT' ? `form input[type='${element.getAttribute('type')}']` : `form ${element.tagName.toLowerCase()}`;
|
|
56
|
+
}
|
|
51
57
|
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
58
|
+
const blockName = element.closest('.block') ? element.closest('.block').getAttribute('data-block-name') : '';
|
|
59
|
+
if (element.id || formElementSelector) {
|
|
60
|
+
const id = element.id ? `#${element.id}` : '';
|
|
61
|
+
return blockName ? `.${blockName} ${formElementSelector}${id}` : `${formElementSelector}${id}`;
|
|
62
|
+
}
|
|
57
63
|
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
64
|
+
if (element.getAttribute('data-block-name')) {
|
|
65
|
+
return `.${element.getAttribute('data-block-name')}`;
|
|
66
|
+
}
|
|
61
67
|
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
68
|
+
if (Array.from(element.classList).some((className) => className.match(/button|cta/))) {
|
|
69
|
+
return blockName ? `.${blockName} .button` : '.button';
|
|
70
|
+
}
|
|
65
71
|
|
|
66
|
-
|
|
72
|
+
return sourceselector(element.parentElement);
|
|
73
|
+
} catch (error) {
|
|
74
|
+
return null;
|
|
75
|
+
}
|
|
67
76
|
};
|
|
68
77
|
|
|
69
78
|
const formSubmitListener = (e) => sampleRUM('formsubmit', { target: targetselector(e.target), source: sourceselector(e.target) });
|
|
@@ -105,39 +114,43 @@ function processQueue() {
|
|
|
105
114
|
|
|
106
115
|
function addCWVTracking() {
|
|
107
116
|
setTimeout(() => {
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
const
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
117
|
+
try {
|
|
118
|
+
const cwvScript = new URL('.rum/web-vitals/dist/web-vitals.iife.js', sampleRUM.baseURL).href;
|
|
119
|
+
if (document.querySelector(`script[src="${cwvScript}"]`)) {
|
|
120
|
+
// web vitals script has been loaded already
|
|
121
|
+
return;
|
|
122
|
+
}
|
|
123
|
+
const script = document.createElement('script');
|
|
124
|
+
script.src = cwvScript;
|
|
125
|
+
script.onload = () => {
|
|
126
|
+
const storeCWV = (measurement) => {
|
|
127
|
+
const data = { cwv: {} };
|
|
128
|
+
data.cwv[measurement.name] = measurement.value;
|
|
129
|
+
if (measurement.name === 'LCP' && measurement.entries.length > 0) {
|
|
130
|
+
const { element } = measurement.entries.pop();
|
|
131
|
+
data.target = targetselector(element);
|
|
132
|
+
data.source = sourceselector(element) || (element && element.outerHTML.slice(0, 30));
|
|
133
|
+
}
|
|
134
|
+
sampleRUM('cwv', data);
|
|
135
|
+
};
|
|
126
136
|
|
|
127
|
-
|
|
128
|
-
|
|
137
|
+
const featureToggle = () => window.location.hostname === 'blog.adobe.com';
|
|
138
|
+
const isEager = (metric) => ['CLS', 'LCP'].includes(metric);
|
|
129
139
|
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
140
|
+
// When loading `web-vitals` using a classic script, all the public
|
|
141
|
+
// methods can be found on the `webVitals` global namespace.
|
|
142
|
+
['FID', 'INP', 'TTFB', 'CLS', 'LCP'].forEach((metric) => {
|
|
143
|
+
const metricFn = window.webVitals[`on${metric}`];
|
|
144
|
+
if (typeof metricFn === 'function') {
|
|
145
|
+
const opts = isEager(metric) ? { reportAllChanges: featureToggle() } : undefined;
|
|
146
|
+
metricFn(storeCWV, opts);
|
|
147
|
+
}
|
|
148
|
+
});
|
|
149
|
+
};
|
|
150
|
+
document.head.appendChild(script);
|
|
151
|
+
} catch (error) {
|
|
152
|
+
// something went wrong
|
|
153
|
+
}
|
|
141
154
|
}, 2000); // wait for delayed
|
|
142
155
|
}
|
|
143
156
|
|
|
@@ -163,11 +176,15 @@ function addEnterLeaveTracking() {
|
|
|
163
176
|
.observe({ type: 'navigation', buffered: true });
|
|
164
177
|
|
|
165
178
|
const leave = ((event) => {
|
|
166
|
-
|
|
167
|
-
|
|
179
|
+
try {
|
|
180
|
+
if (leave.left || (event.type === 'visibilitychange' && document.visibilityState !== 'hidden')) {
|
|
181
|
+
return;
|
|
182
|
+
}
|
|
183
|
+
leave.left = true;
|
|
184
|
+
sampleRUM('leave');
|
|
185
|
+
} catch (error) {
|
|
186
|
+
// something went wrong
|
|
168
187
|
}
|
|
169
|
-
leave.left = true;
|
|
170
|
-
sampleRUM('leave');
|
|
171
188
|
});
|
|
172
189
|
window.addEventListener('visibilitychange', ((event) => leave(event)));
|
|
173
190
|
window.addEventListener('pagehide', ((event) => leave(event)));
|
|
@@ -175,21 +192,25 @@ function addEnterLeaveTracking() {
|
|
|
175
192
|
|
|
176
193
|
function addLoadResourceTracking() {
|
|
177
194
|
const observer = new PerformanceObserver((list) => {
|
|
178
|
-
|
|
179
|
-
.filter((entry) => !entry.responseStatus || entry.responseStatus < 400)
|
|
180
|
-
.filter((entry) => window.location.hostname === new URL(entry.name).hostname)
|
|
181
|
-
.filter((entry) => new URL(entry.name).pathname.match('.*(\\.plain\\.html|\\.json)$'))
|
|
182
|
-
.forEach((entry) => {
|
|
183
|
-
sampleRUM('loadresource', { source: entry.name, target: Math.round(entry.duration) });
|
|
184
|
-
});
|
|
185
|
-
|
|
186
|
-
if (window.origin === 'business.adobe.com') {
|
|
187
|
-
// feature flagged for now
|
|
195
|
+
try {
|
|
188
196
|
list.getEntries()
|
|
189
|
-
.filter((entry) => entry.responseStatus
|
|
197
|
+
.filter((entry) => !entry.responseStatus || entry.responseStatus < 400)
|
|
198
|
+
.filter((entry) => window.location.hostname === new URL(entry.name).hostname)
|
|
199
|
+
.filter((entry) => new URL(entry.name).pathname.match('.*(\\.plain\\.html|\\.json)$'))
|
|
190
200
|
.forEach((entry) => {
|
|
191
|
-
sampleRUM('
|
|
201
|
+
sampleRUM('loadresource', { source: entry.name, target: Math.round(entry.duration) });
|
|
192
202
|
});
|
|
203
|
+
|
|
204
|
+
if (window.origin === 'business.adobe.com') {
|
|
205
|
+
// feature flagged for now
|
|
206
|
+
list.getEntries()
|
|
207
|
+
.filter((entry) => entry.responseStatus === 404)
|
|
208
|
+
.forEach((entry) => {
|
|
209
|
+
sampleRUM('missingresource', { source: entry.name, target: entry.hostname });
|
|
210
|
+
});
|
|
211
|
+
}
|
|
212
|
+
} catch (error) {
|
|
213
|
+
// something went wrong
|
|
193
214
|
}
|
|
194
215
|
});
|
|
195
216
|
observer.observe({ type: 'resource', buffered: true });
|
|
@@ -213,14 +234,18 @@ function getIntersectionObsever(checkpoint) {
|
|
|
213
234
|
}
|
|
214
235
|
activateBlocksMutationObserver();
|
|
215
236
|
const observer = new IntersectionObserver((entries) => {
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
|
|
237
|
+
try {
|
|
238
|
+
entries
|
|
239
|
+
.filter((entry) => entry.isIntersecting)
|
|
240
|
+
.forEach((entry) => {
|
|
241
|
+
observer.unobserve(entry.target); // observe only once
|
|
242
|
+
const target = targetselector(entry.target);
|
|
243
|
+
const source = sourceselector(entry.target);
|
|
244
|
+
sampleRUM(checkpoint, { target, source });
|
|
245
|
+
});
|
|
246
|
+
} catch (error) {
|
|
247
|
+
// something went wrong
|
|
248
|
+
}
|
|
224
249
|
}, { threshold: 0.25 });
|
|
225
250
|
return observer;
|
|
226
251
|
}
|
|
@@ -293,9 +318,15 @@ function addTrackingFromConfig() {
|
|
|
293
318
|
}
|
|
294
319
|
|
|
295
320
|
function initEnhancer() {
|
|
296
|
-
|
|
297
|
-
|
|
298
|
-
|
|
321
|
+
try {
|
|
322
|
+
if (sampleRUM) {
|
|
323
|
+
addTrackingFromConfig();
|
|
324
|
+
window.hlx.rum.collector = trackCheckpoint;
|
|
325
|
+
processQueue();
|
|
326
|
+
}
|
|
327
|
+
} catch (error) {
|
|
328
|
+
// something went wrong
|
|
329
|
+
}
|
|
299
330
|
}
|
|
300
331
|
|
|
301
332
|
initEnhancer();
|