Skip to content

Commit 0dd6bcd

Browse files
committed
feat: RUM v2
1 parent a70f3df commit 0dd6bcd

6 files changed

Lines changed: 109 additions & 78 deletions

File tree

404.html

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -26,7 +26,7 @@
2626
btnContainer.append(backBtn);
2727
}
2828
}
29-
sampleRUM('404', { source: document.referrer, target: window.location.href });
29+
sampleRUM('404', { source: document.referrer });
3030
});
3131
</script>
3232
<link rel="stylesheet" href="/styles/styles.css">

blocks/article-feed/article-feed.js

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,5 @@
11
import {
22
readBlockConfig,
3-
sampleRUM,
43
} from '../../scripts/lib-franklin.js';
54

65
import {
@@ -259,7 +258,6 @@ function buildFilter(type, tax, ph, block, config) {
259258
applyBtn.classList.add('button', 'small', 'apply');
260259
applyBtn.textContent = ph.apply;
261260
applyBtn.addEventListener('click', () => {
262-
sampleRUM('apply-topic-filter');
263261
delete config.selectedProducts;
264262
delete config.selectedIndustries;
265263
closeCurtain();

blocks/tags/tags.js

Lines changed: 0 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,3 @@
1-
import { sampleRUM } from '../../scripts/lib-franklin.js';
2-
31
export default function decorateTags(blockEl) {
42
const tags = blockEl.querySelectorAll('a');
53
const container = blockEl.querySelector('p');
@@ -11,5 +9,4 @@ export default function decorateTags(blockEl) {
119
targets.push(tag.textContent);
1210
return targets;
1311
}, []).join('; ');
14-
sampleRUM('loadtags', { target, source: `.${blockEl.getAttribute('data-block-name')}` });
1512
}

scripts/delayed.js

Lines changed: 0 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,4 @@
11
// eslint-disable-next-line import/no-cycle
2-
import { sampleRUM } from './lib-franklin.js';
3-
4-
// Core Web Vitals RUM collection
5-
sampleRUM('cwv');
62

73
async function loadScript(src, parent, attrs) {
84
return new Promise((resolve, reject) => {

scripts/lib-franklin.js

Lines changed: 108 additions & 62 deletions
Original file line numberDiff line numberDiff line change
@@ -15,66 +15,118 @@
1515
* @param {string} checkpoint identifies the checkpoint in funnel
1616
* @param {Object} data additional data for RUM sample
1717
*/
18-
export function sampleRUM(checkpoint, data = {}) {
19-
sampleRUM.defer = sampleRUM.defer || [];
20-
const defer = (fnname) => {
21-
sampleRUM[fnname] = sampleRUM[fnname]
22-
|| ((...args) => sampleRUM.defer.push({ fnname, args }));
23-
};
24-
sampleRUM.drain = sampleRUM.drain
25-
|| ((dfnname, fn) => {
26-
sampleRUM[dfnname] = fn;
27-
sampleRUM.defer
28-
.filter(({ fnname }) => dfnname === fnname)
29-
.forEach(({ fnname, args }) => sampleRUM[fnname](...args));
30-
});
31-
sampleRUM.on = (chkpnt, fn) => { sampleRUM.cases[chkpnt] = fn; };
32-
defer('observe');
33-
defer('cwv');
18+
export function sampleRUM(checkpoint, data) {
19+
// eslint-disable-next-line max-len
20+
const timeShift = () => (window.performance ? window.performance.now() : Date.now() - window.hlx.rum.firstReadTime);
3421
try {
3522
window.hlx = window.hlx || {};
23+
sampleRUM.enhance = () => {};
3624
if (!window.hlx.rum) {
37-
const usp = new URLSearchParams(window.location.search);
38-
const weight = (usp.get('rum') === 'on') ? 1 : 100; // with parameter, weight is 1. Defaults to 100.
39-
// eslint-disable-next-line no-bitwise
40-
const hashCode = (s) => s.split('').reduce((a, b) => (((a << 5) - a) + b.charCodeAt(0)) | 0, 0);
41-
const id = `${hashCode(window.location.href)}-${new Date().getTime()}-${Math.random().toString(16).substr(2, 14)}`;
42-
const random = Math.random();
43-
const isSelected = (random * weight < 1);
44-
const urlSanitizers = {
45-
full: () => window.location.href,
46-
origin: () => window.location.origin,
47-
path: () => window.location.pathname,
48-
};
25+
const param = new URLSearchParams(window.location.search).get('rum');
26+
const weight = (window.SAMPLE_PAGEVIEWS_AT_RATE === 'high' && 10)
27+
|| (window.SAMPLE_PAGEVIEWS_AT_RATE === 'low' && 1000)
28+
|| (param === 'on' && 1)
29+
|| 100;
30+
const id = Math.random().toString(36).slice(-4);
31+
const isSelected = param !== 'off' && Math.random() * weight < 1;
4932
// eslint-disable-next-line object-curly-newline, max-len
50-
window.hlx.rum = { weight, id, random, isSelected, sampleRUM, sanitizeURL: urlSanitizers[window.hlx.RUM_MASK_URL || 'path'] };
51-
}
52-
const { weight, id } = window.hlx.rum;
53-
if (window.hlx && window.hlx.rum && window.hlx.rum.isSelected) {
54-
const sendPing = (pdata = data) => {
55-
// eslint-disable-next-line object-curly-newline, max-len, no-use-before-define
56-
const body = JSON.stringify({ weight, id, referer: window.hlx.rum.sanitizeURL(), checkpoint, ...data });
57-
const url = `https://rum.hlx.page/.rum/${weight}`;
58-
// eslint-disable-next-line no-unused-expressions
59-
navigator.sendBeacon(url, body);
60-
// eslint-disable-next-line no-console
61-
console.debug(`ping:${checkpoint}`, pdata);
33+
window.hlx.rum = {
34+
weight,
35+
id,
36+
isSelected,
37+
firstReadTime: window.performance ? window.performance.timeOrigin : Date.now(),
38+
sampleRUM,
39+
queue: [],
40+
collector: (...args) => window.hlx.rum.queue.push(args),
6241
};
63-
sampleRUM.cases = sampleRUM.cases || {
64-
cwv: () => sampleRUM.cwv(data) || true,
65-
lazy: () => {
66-
// use classic script to avoid CORS issues
42+
if (isSelected) {
43+
const dataFromErrorObj = (error) => {
44+
const errData = { source: 'undefined error' };
45+
try {
46+
errData.target = error.toString();
47+
errData.source = error.stack
48+
.split('\n')
49+
.filter((line) => line.match(/https?:\/\//))
50+
.shift()
51+
.replace(/at ([^ ]+) \((.+)\)/, '$1@$2')
52+
.replace(/ at /, '@')
53+
.trim();
54+
} catch (err) {
55+
/* error structure was not as expected */
56+
}
57+
return errData;
58+
};
59+
60+
window.addEventListener('error', ({ error }) => {
61+
const errData = dataFromErrorObj(error);
62+
sampleRUM('error', errData);
63+
});
64+
65+
window.addEventListener('unhandledrejection', ({ reason }) => {
66+
let errData = {
67+
source: 'Unhandled Rejection',
68+
target: reason || 'Unknown',
69+
};
70+
if (reason instanceof Error) {
71+
errData = dataFromErrorObj(reason);
72+
}
73+
sampleRUM('error', errData);
74+
});
75+
76+
sampleRUM.baseURL = sampleRUM.baseURL || new URL(window.RUM_BASE || '/', new URL('https://rum.hlx.page'));
77+
sampleRUM.collectBaseURL = sampleRUM.collectBaseURL || sampleRUM.baseURL;
78+
sampleRUM.sendPing = (ck, time, pingData = {}) => {
79+
// eslint-disable-next-line max-len, object-curly-newline
80+
const rumData = JSON.stringify({
81+
weight,
82+
id,
83+
referer: window.location.href,
84+
checkpoint: ck,
85+
t: time,
86+
...pingData,
87+
});
88+
const urlParams = window.RUM_PARAMS
89+
? `?${new URLSearchParams(window.RUM_PARAMS).toString()}`
90+
: '';
91+
const { href: url, origin } = new URL(
92+
`.rum/${weight}${urlParams}`,
93+
sampleRUM.collectBaseURL,
94+
);
95+
const body = origin === window.location.origin
96+
? new Blob([rumData], { type: 'application/json' })
97+
: rumData;
98+
navigator.sendBeacon(url, body);
99+
// eslint-disable-next-line no-console
100+
console.debug(`ping:${ck}`, pingData);
101+
};
102+
sampleRUM.sendPing('top', timeShift());
103+
104+
sampleRUM.enhance = () => {
105+
// only enhance once
106+
if (document.querySelector('script[src*="rum-enhancer"]')) return;
107+
const { enhancerVersion, enhancerHash } = sampleRUM.enhancerContext || {};
67108
const script = document.createElement('script');
68-
script.src = 'https://rum.hlx.page/.rum/@adobe/helix-rum-enhancer@^1/src/index.js';
109+
if (enhancerHash) {
110+
script.integrity = enhancerHash;
111+
script.setAttribute('crossorigin', 'anonymous');
112+
}
113+
script.src = new URL(
114+
`.rum/@adobe/helix-rum-enhancer@${enhancerVersion || '^2'}/src/index.js`,
115+
sampleRUM.baseURL,
116+
).href;
69117
document.head.appendChild(script);
70-
return true;
71-
},
72-
};
73-
sendPing(data);
74-
if (sampleRUM.cases[checkpoint]) { sampleRUM.cases[checkpoint](); }
118+
};
119+
if (!window.hlx.RUM_MANUAL_ENHANCE) {
120+
sampleRUM.enhance();
121+
}
122+
}
123+
}
124+
if (window.hlx.rum && window.hlx.rum.isSelected && checkpoint) {
125+
window.hlx.rum.collector(checkpoint, data, timeShift());
75126
}
127+
document.dispatchEvent(new CustomEvent('rum', { detail: { checkpoint, data } }));
76128
} catch (error) {
77-
// something went wrong
129+
// something went awry
78130
}
79131
}
80132

@@ -344,6 +396,9 @@ export function updateSectionsStatus(main) {
344396
} else {
345397
section.dataset.sectionStatus = 'loaded';
346398
section.style.display = null;
399+
if (i === 0 && sampleRUM.enhance) {
400+
sampleRUM.enhance();
401+
}
347402
}
348403
}
349404
}
@@ -606,6 +661,7 @@ export function loadFooter(footer) {
606661
export function setup() {
607662
window.hlx = window.hlx || {};
608663
window.hlx.RUM_MASK_URL = 'full';
664+
window.hlx.RUM_MANUAL_ENHANCE = true;
609665
window.hlx.codeBasePath = '';
610666
window.hlx.lighthouse = new URLSearchParams(window.location.search).get('lighthouse') === 'on';
611667

@@ -626,17 +682,7 @@ export function setup() {
626682
function init() {
627683
document.body.style.display = 'none';
628684
setup();
629-
sampleRUM('top');
630-
631-
window.addEventListener('load', () => sampleRUM('load'));
632-
633-
window.addEventListener('unhandledrejection', (event) => {
634-
sampleRUM('error', { source: event.reason.sourceURL, target: event.reason.line });
635-
});
636-
637-
window.addEventListener('error', (event) => {
638-
sampleRUM('error', { source: event.filename, target: event.lineno });
639-
});
685+
sampleRUM();
640686
}
641687

642688
init();

scripts/scripts.js

Lines changed: 0 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,4 @@
11
import {
2-
sampleRUM,
32
buildBlock,
43
createOptimizedPicture,
54
loadFooter,
@@ -913,8 +912,6 @@ async function loadLazy(doc) {
913912
const main = doc.querySelector('main');
914913

915914
// post LCP actions go here
916-
sampleRUM('lcp');
917-
918915
const { hash } = window.location;
919916
const element = hash ? doc.getElementById(hash.substring(1)) : false;
920917
if (hash && element) element.scrollIntoView();
@@ -936,9 +933,6 @@ async function loadLazy(doc) {
936933

937934
loadCSS(`${window.hlx.codeBasePath}/styles/lazy-styles.css`);
938935
addFavIcon(`${window.hlx.codeBasePath}/styles/favicon.svg`);
939-
sampleRUM('lazy');
940-
sampleRUM.observe(main.querySelectorAll('div[data-block-name]'));
941-
sampleRUM.observe(main.querySelectorAll('picture > img'));
942936
}
943937

944938
/**

0 commit comments

Comments
 (0)