From 6066f0bd56393a10391e190b9a338f9a65b772b0 Mon Sep 17 00:00:00 2001 From: Julien Ramboz Date: Mon, 13 Jan 2025 16:20:38 -0800 Subject: [PATCH 01/42] feat: introduce minimal plugin system to offset non-essenial logic --- modules/index.js | 187 +++++++--------------- plugins/ads.js | 27 ++++ plugins/cwv.js | 57 +++++++ plugins/email.js | 21 +++ plugins/form.js | 32 ++++ plugins/navigation.js | 58 +++++++ modules/martech.js => plugins/onetrust.js | 40 +---- plugins/utm.js | 21 +++ plugins/video.js | 15 ++ rollup.config.js | 6 + 10 files changed, 295 insertions(+), 169 deletions(-) create mode 100644 plugins/ads.js create mode 100644 plugins/cwv.js create mode 100644 plugins/email.js create mode 100644 plugins/form.js create mode 100644 plugins/navigation.js rename modules/martech.js => plugins/onetrust.js (54%) create mode 100644 plugins/utm.js create mode 100644 plugins/video.js diff --git a/modules/index.js b/modules/index.js index 4c4419c..c2ee72c 100644 --- a/modules/index.js +++ b/modules/index.js @@ -14,12 +14,6 @@ import { KNOWN_PROPERTIES, DEFAULT_TRACKING_EVENTS } from './defaults.js'; import { urlSanitizers } from './utils.js'; import { targetSelector, sourceSelector } from './dom.js'; -import { - addAdsParametersTracking, - addCookieConsentTracking, - addEmailParameterTracking, - addUTMParametersTracking, -} from './martech.js'; import { fflags } from './fflags.js'; const { sampleRUM, queue, isSelected } = (window.hlx && window.hlx.rum) ? window.hlx.rum @@ -35,6 +29,52 @@ const blocksMO = window.MutationObserver ? new MutationObserver(blocksMCB) const mediaMO = window.MutationObserver ? new MutationObserver(mediaMCB) /* c8 ignore next */ : {}; +const PLUGINS = { + cwv: 'cwv.js', + navigation: 'navigation.js', + // Interactive elements + form: { + condition: () => document.body.querySelector('form'), + file: 'form.js', + }, + video: { + condition: () => document.body.querySelector('video'), + file: 'video.js', + }, + // Martech + ads: { + condition: ({ urlParameters }) => urlParameters.keys().length, + file: 'ads.js', + }, + email: { + condition: ({ urlParameters }) => urlParameters.keys().length, + file: 'email.js', + }, + onetrust: { + condition: () => document.cookie.split(';').map((c) => c.trim()).some((cookie) => cookie.startsWith('OptanonAlertBoxClosed=')), + file: 'onetrust.js', + }, + utm: { + condition: ({ urlParameters }) => urlParameters.keys().length, + file: 'utm.js', + }, +}; + +const PLUGIN_PARAMETERS = { + sampleRUM, + sourceSelector, + targetSelector, + fflags, + context: window.document.body, +}; + +async function loadPlugin(key, params) { + const urlParameters = new URLSearchParams(window.location.search); + return PLUGINS[key] && (!PLUGINS[key].condition || PLUGINS[key].condition({ urlParameters })) + ? import(`../plugins/${PLUGINS[key].path || PLUGINS[key]}`).then((p) => p.default && p.default(params)) + : Promise.reject(new Error(`Plugin ${key} not found`)); +} + function trackCheckpoint(checkpoint, data, t) { const { weight, id } = window.hlx.rum; if (isSelected) { @@ -64,99 +104,6 @@ function processQueue() { } } -function addCWVTracking() { - setTimeout(() => { - try { - const cwvScript = new URL('.rum/web-vitals/dist/web-vitals.iife.js', sampleRUM.baseURL).href; - if (document.querySelector(`script[src="${cwvScript}"]`)) { - // web vitals script has been loaded already - return; - } - const script = document.createElement('script'); - script.src = cwvScript; - script.onload = () => { - const storeCWV = (measurement) => { - const data = { cwv: {} }; - data.cwv[measurement.name] = measurement.value; - if (measurement.name === 'LCP' && measurement.entries.length > 0) { - const { element } = measurement.entries.pop(); - data.target = targetSelector(element); - data.source = sourceSelector(element) || (element && element.outerHTML.slice(0, 30)); - } - sampleRUM('cwv', data); - }; - - const isEager = (metric) => ['CLS', 'LCP'].includes(metric); - - // When loading `web-vitals` using a classic script, all the public - // methods can be found on the `webVitals` global namespace. - ['INP', 'TTFB', 'CLS', 'LCP'].forEach((metric) => { - const metricFn = window.webVitals[`on${metric}`]; - if (typeof metricFn === 'function') { - let opts = {}; - fflags.enabled('eagercwv', () => { - opts = { reportAllChanges: isEager(metric) }; - }); - metricFn(storeCWV, opts); - } - }); - }; - document.head.appendChild(script); - /* c8 ignore next 3 */ - } catch (error) { - // something went wrong - } - }, 2000); // wait for delayed -} - -function addNavigationTracking() { - // enter checkpoint when referrer is not the current page url - const navigate = (source, type, redirectCount) => { - // target can be 'visible', 'hidden' (background tab) or 'prerendered' (speculation rules) - const payload = { source, target: document.visibilityState }; - /* c8 ignore next 13 */ - // prerendering cannot be tested yet with headless browsers - if (document.prerendering) { - // listen for "activation" of the current pre-rendered page - document.addEventListener('prerenderingchange', () => { - // pre-rendered page is now "activated" - payload.target = 'prerendered'; - sampleRUM('navigate', payload); // prerendered navigation - }, { - once: true, - }); - if (type === 'navigate') { - sampleRUM('prerender', payload); // prerendering page - } - } else if (type === 'reload' || source === window.location.href) { - sampleRUM('reload', payload); - } else if (type && type !== 'navigate') { - sampleRUM(type, payload); // back, forward, prerender, etc. - } else if (source && window.location.origin === new URL(source).origin) { - sampleRUM('navigate', payload); // internal navigation - } else { - sampleRUM('enter', payload); // enter site - } - fflags.enabled('redirect', () => { - const from = new URLSearchParams(window.location.search).get('redirect_from'); - if (redirectCount || from) { - sampleRUM('redirect', { source: from, target: redirectCount || 1 }); - } - }); - }; - - const processed = new Set(); // avoid processing duplicate types - new PerformanceObserver((list) => list - .getEntries() - .filter(({ type }) => !processed.has(type)) - .map((e) => [e, processed.add(e.type)]) - .map(([e]) => navigate( - window.hlx.referrer || document.referrer, - e.type, - e.redirectCount, - ))).observe({ type: 'navigation', buffered: true }); -} - function addLoadResourceTracking() { const observer = new PerformanceObserver((list) => { try { @@ -211,8 +158,6 @@ function getIntersectionObsever(checkpoint) { if (!window.IntersectionObserver) { return null; } - activateBlocksMO(); - activateMediaMO(); const observer = new IntersectionObserver((entries) => { try { entries @@ -251,28 +196,6 @@ function addViewMediaTracking(parent) { } } -function addFormTracking(parent) { - activateBlocksMO(); - activateMediaMO(); - parent.querySelectorAll('form').forEach((form) => { - form.addEventListener('submit', (e) => sampleRUM('formsubmit', { target: targetSelector(e.target), source: sourceSelector(e.target) }), { once: true }); - let lastSource; - form.addEventListener('change', (e) => { - const source = sourceSelector(e.target); - if (source !== lastSource) { - sampleRUM('fill', { source }); - lastSource = source; - } - }); - form.addEventListener('focusin', (e) => { - if (['INPUT', 'TEXTAREA', 'SELECT', 'BUTTON'].includes(e.target.tagName) - || e.target.getAttribute('contenteditable') === 'true') { - sampleRUM('click', { source: sourceSelector(e.target) }); - } - }); - }); -} - function addObserver(ck, fn, block) { return DEFAULT_TRACKING_EVENTS.includes(ck) && fn(block); } @@ -284,7 +207,7 @@ function blocksMCB(mutations) { .filter((m) => m.type === 'attributes' && m.attributeName === 'data-block-status') .filter((m) => m.target.dataset.blockStatus === 'loaded') .forEach((m) => { - addObserver('form', addFormTracking, m.target); + addObserver('form', (el) => loadPlugin('form', { ...PLUGIN_PARAMETERS, context: el }), m.target); addObserver('viewblock', addViewBlockTracking, m.target); }); } @@ -299,6 +222,9 @@ function mediaMCB(mutations) { } function addTrackingFromConfig() { + activateBlocksMO(); + activateMediaMO(); + let lastSource; let lastTarget; document.addEventListener('click', (event) => { @@ -310,16 +236,15 @@ function addTrackingFromConfig() { lastTarget = target; } }); - addCWVTracking(); - addFormTracking(window.document.body); - addNavigationTracking(); + + // Core tracking addLoadResourceTracking(); - addUTMParametersTracking(sampleRUM); addViewBlockTracking(window.document.body); addViewMediaTracking(window.document.body); - addCookieConsentTracking(sampleRUM); - addAdsParametersTracking(sampleRUM); - addEmailParameterTracking(sampleRUM); + + // Tracking extensions + Object.keys(PLUGINS).filter((key) => loadPlugin(key, PLUGIN_PARAMETERS)); + fflags.enabled('language', () => { const target = navigator.language; const source = document.documentElement.lang; diff --git a/plugins/ads.js b/plugins/ads.js new file mode 100644 index 0000000..ba3ece6 --- /dev/null +++ b/plugins/ads.js @@ -0,0 +1,27 @@ +/* + * Copyright 2025 Adobe. All rights reserved. + * This file is licensed to you under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. You may obtain a copy + * of the License at http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software distributed under + * the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR REPRESENTATIONS + * OF ANY KIND, either express or implied. See the License for the specific language + * governing permissions and limitations under the License. + */ +export function addAdsParametersTracking({ sampleRUM }) { + const networks = { + google: /gclid|gclsrc|wbraid|gbraid/, + doubleclick: /dclid/, + microsoft: /msclkid/, + facebook: /fb(cl|ad_|pxl_)id/, + twitter: /tw(clid|src|term)/, + linkedin: /li_fat_id/, + pinterest: /epik/, + tiktok: /ttclid/, + }; + const params = Array.from(new URLSearchParams(window.location.search).keys()); + Object.entries(networks).forEach(([network, regex]) => { + params.filter((param) => regex.test(param)).forEach((param) => sampleRUM('paid', { source: network, target: param })); + }); +} diff --git a/plugins/cwv.js b/plugins/cwv.js new file mode 100644 index 0000000..0cfa775 --- /dev/null +++ b/plugins/cwv.js @@ -0,0 +1,57 @@ +/* + * Copyright 2025 Adobe. All rights reserved. + * This file is licensed to you under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. You may obtain a copy + * of the License at http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software distributed under + * the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR REPRESENTATIONS + * OF ANY KIND, either express or implied. See the License for the specific language + * governing permissions and limitations under the License. + */ +export default function addCWVTracking({ + sampleRUM, sourceSelector, targetSelector, fflags, +}) { + setTimeout(() => { + try { + const cwvScript = new URL('.rum/web-vitals/dist/web-vitals.iife.js', sampleRUM.baseURL).href; + if (document.querySelector(`script[src="${cwvScript}"]`)) { + // web vitals script has been loaded already + return; + } + const script = document.createElement('script'); + script.src = cwvScript; + script.onload = () => { + const storeCWV = (measurement) => { + const data = { cwv: {} }; + data.cwv[measurement.name] = measurement.value; + if (measurement.name === 'LCP' && measurement.entries.length > 0) { + const { element } = measurement.entries.pop(); + data.target = targetSelector(element); + data.source = sourceSelector(element) || (element && element.outerHTML.slice(0, 30)); + } + sampleRUM('cwv', data); + }; + + const isEager = (metric) => ['CLS', 'LCP'].includes(metric); + + // When loading `web-vitals` using a classic script, all the public + // methods can be found on the `webVitals` global namespace. + ['INP', 'TTFB', 'CLS', 'LCP'].forEach((metric) => { + const metricFn = window.webVitals[`on${metric}`]; + if (typeof metricFn === 'function') { + let opts = {}; + fflags.enabled('eagercwv', () => { + opts = { reportAllChanges: isEager(metric) }; + }); + metricFn(storeCWV, opts); + } + }); + }; + document.head.appendChild(script); + /* c8 ignore next 3 */ + } catch (error) { + // something went wrong + } + }, 2000); // wait for delayed +} diff --git a/plugins/email.js b/plugins/email.js new file mode 100644 index 0000000..2328af0 --- /dev/null +++ b/plugins/email.js @@ -0,0 +1,21 @@ +/* + * Copyright 2025 Adobe. All rights reserved. + * This file is licensed to you under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. You may obtain a copy + * of the License at http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software distributed under + * the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR REPRESENTATIONS + * OF ANY KIND, either express or implied. See the License for the specific language + * governing permissions and limitations under the License. + */ +export function addEmailParameterTracking({ sampleRUM }) { + const networks = { + mailchimp: /mc_(c|e)id/, + marketo: /mkt_tok/, + }; + const params = Array.from(new URLSearchParams(window.location.search).keys()); + Object.entries(networks).forEach(([network, regex]) => { + params.filter((param) => regex.test(param)).forEach((param) => sampleRUM('email', { source: network, target: param })); + }); +} diff --git a/plugins/form.js b/plugins/form.js new file mode 100644 index 0000000..0ff398d --- /dev/null +++ b/plugins/form.js @@ -0,0 +1,32 @@ +/* + * Copyright 2025 Adobe. All rights reserved. + * This file is licensed to you under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. You may obtain a copy + * of the License at http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software distributed under + * the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR REPRESENTATIONS + * OF ANY KIND, either express or implied. See the License for the specific language + * governing permissions and limitations under the License. + */ +export default function addFormTracking({ + sampleRUM, sourceSelector, targetSelector, context, +}) { + context.querySelectorAll('form').forEach((form) => { + form.addEventListener('submit', (e) => sampleRUM('formsubmit', { target: targetSelector(e.target), source: sourceSelector(e.target) }), { once: true }); + let lastSource; + form.addEventListener('change', (e) => { + const source = sourceSelector(e.target); + if (source !== lastSource) { + sampleRUM('fill', { source }); + lastSource = source; + } + }); + form.addEventListener('focusin', (e) => { + if (['INPUT', 'TEXTAREA', 'SELECT', 'BUTTON'].includes(e.target.tagName) + || e.target.getAttribute('contenteditable') === 'true') { + sampleRUM('click', { source: sourceSelector(e.target) }); + } + }); + }); +} diff --git a/plugins/navigation.js b/plugins/navigation.js new file mode 100644 index 0000000..ebad8b1 --- /dev/null +++ b/plugins/navigation.js @@ -0,0 +1,58 @@ +/* + * Copyright 2025 Adobe. All rights reserved. + * This file is licensed to you under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. You may obtain a copy + * of the License at http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software distributed under + * the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR REPRESENTATIONS + * OF ANY KIND, either express or implied. See the License for the specific language + * governing permissions and limitations under the License. + */ +export default function addNavigationTracking({ sampleRUM, fflags }) { + // enter checkpoint when referrer is not the current page url + const navigate = (source, type, redirectCount) => { + // target can be 'visible', 'hidden' (background tab) or 'prerendered' (speculation rules) + const payload = { source, target: document.visibilityState }; + /* c8 ignore next 13 */ + // prerendering cannot be tested yet with headless browsers + if (document.prerendering) { + // listen for "activation" of the current pre-rendered page + document.addEventListener('prerenderingchange', () => { + // pre-rendered page is now "activated" + payload.target = 'prerendered'; + sampleRUM('navigate', payload); // prerendered navigation + }, { + once: true, + }); + if (type === 'navigate') { + sampleRUM('prerender', payload); // prerendering page + } + } else if (type === 'reload' || source === window.location.href) { + sampleRUM('reload', payload); + } else if (type && type !== 'navigate') { + sampleRUM(type, payload); // back, forward, prerender, etc. + } else if (source && window.location.origin === new URL(source).origin) { + sampleRUM('navigate', payload); // internal navigation + } else { + sampleRUM('enter', payload); // enter site + } + fflags.enabled('redirect', () => { + const from = new URLSearchParams(window.location.search).get('redirect_from'); + if (redirectCount || from) { + sampleRUM('redirect', { source: from, target: redirectCount || 1 }); + } + }); + }; + + const processed = new Set(); // avoid processing duplicate types + new PerformanceObserver((list) => list + .getEntries() + .filter(({ type }) => !processed.has(type)) + .map((e) => [e, processed.add(e.type)]) + .map(([e]) => navigate( + window.hlx.referrer || document.referrer, + e.type, + e.redirectCount, + ))).observe({ type: 'navigation', buffered: true }); +} diff --git a/modules/martech.js b/plugins/onetrust.js similarity index 54% rename from modules/martech.js rename to plugins/onetrust.js index 6fb623d..a482454 100644 --- a/modules/martech.js +++ b/plugins/onetrust.js @@ -1,5 +1,5 @@ /* - * Copyright 2024 Adobe. All rights reserved. + * Copyright 2025 Adobe. All rights reserved. * This file is licensed to you under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. You may obtain a copy * of the License at http://www.apache.org/licenses/LICENSE-2.0 @@ -9,7 +9,7 @@ * OF ANY KIND, either express or implied. See the License for the specific language * governing permissions and limitations under the License. */ -export function addCookieConsentTracking(sampleRUM) { +export function addCookieConsentTracking({ sampleRUM }) { const cmpCookie = document.cookie.split(';') .map((c) => c.trim()) .find((cookie) => cookie.startsWith('OptanonAlertBoxClosed=')); @@ -50,39 +50,3 @@ export function addCookieConsentTracking(sampleRUM) { } } } - -export function addUTMParametersTracking(sampleRUM) { - const usp = new URLSearchParams(window.location.search); - [...usp.entries()] - .filter(([key]) => key.startsWith('utm_')) - // exclude keys that may leak PII - .filter(([key]) => key !== 'utm_id') - .filter(([key]) => key !== 'utm_term') - .forEach(([source, target]) => sampleRUM('utm', { source, target })); -} -export function addAdsParametersTracking(sampleRUM) { - const networks = { - google: /gclid|gclsrc|wbraid|gbraid/, - doubleclick: /dclid/, - microsoft: /msclkid/, - facebook: /fb(cl|ad_|pxl_)id/, - twitter: /tw(clid|src|term)/, - linkedin: /li_fat_id/, - pinterest: /epik/, - tiktok: /ttclid/, - }; - const params = Array.from(new URLSearchParams(window.location.search).keys()); - Object.entries(networks).forEach(([network, regex]) => { - params.filter((param) => regex.test(param)).forEach((param) => sampleRUM('paid', { source: network, target: param })); - }); -} -export function addEmailParameterTracking(sampleRUM) { - const networks = { - mailchimp: /mc_(c|e)id/, - marketo: /mkt_tok/, - }; - const params = Array.from(new URLSearchParams(window.location.search).keys()); - Object.entries(networks).forEach(([network, regex]) => { - params.filter((param) => regex.test(param)).forEach((param) => sampleRUM('email', { source: network, target: param })); - }); -} diff --git a/plugins/utm.js b/plugins/utm.js new file mode 100644 index 0000000..10cbd69 --- /dev/null +++ b/plugins/utm.js @@ -0,0 +1,21 @@ +/* + * Copyright 2025 Adobe. All rights reserved. + * This file is licensed to you under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. You may obtain a copy + * of the License at http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software distributed under + * the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR REPRESENTATIONS + * OF ANY KIND, either express or implied. See the License for the specific language + * governing permissions and limitations under the License. + */ + +export function addUTMParametersTracking({ sampleRUM }) { + const usp = new URLSearchParams(window.location.search); + [...usp.entries()] + .filter(([key]) => key.startsWith('utm_')) + // exclude keys that may leak PII + .filter(([key]) => key !== 'utm_id') + .filter(([key]) => key !== 'utm_term') + .forEach(([source, target]) => sampleRUM('utm', { source, target })); +} diff --git a/plugins/video.js b/plugins/video.js new file mode 100644 index 0000000..67d96a0 --- /dev/null +++ b/plugins/video.js @@ -0,0 +1,15 @@ +/* + * Copyright 2025 Adobe. All rights reserved. + * This file is licensed to you under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. You may obtain a copy + * of the License at http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software distributed under + * the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR REPRESENTATIONS + * OF ANY KIND, either express or implied. See the License for the specific language + * governing permissions and limitations under the License. + */ + +export function addVideoTracking() { + // TODO: Add video tracking +} diff --git a/rollup.config.js b/rollup.config.js index 1c4803f..e5fec44 100644 --- a/rollup.config.js +++ b/rollup.config.js @@ -28,10 +28,16 @@ const banner = `/* */`; const bundles = [ + // Core library { source: 'modules/index.js', outputFile: 'src/index', }, + // Library plugins + ...['ads', 'cwv', 'email', 'form', 'navigation', 'onetrust', 'utm', 'video'].map((plugin) => ({ + source: `plugins/${plugin}.js`, + outputFile: `src/plugins/${plugin}`, + })), ]; export default [...bundles.map(({ outputFile, source }) => ({ From 8642557beaef5161d1d4d51d2b04ce06bf7dbeb7 Mon Sep 17 00:00:00 2001 From: Julien Ramboz Date: Mon, 13 Jan 2025 16:33:58 -0800 Subject: [PATCH 02/42] feat: introduce minimal plugin system to offset non-essenial logic --- modules/index.js | 27 +++++++++++++++++---------- 1 file changed, 17 insertions(+), 10 deletions(-) diff --git a/modules/index.js b/modules/index.js index c2ee72c..ecf4b28 100644 --- a/modules/index.js +++ b/modules/index.js @@ -19,15 +19,19 @@ import { fflags } from './fflags.js'; const { sampleRUM, queue, isSelected } = (window.hlx && window.hlx.rum) ? window.hlx.rum /* c8 ignore next */ : {}; +const createMO = (cb) => (window.MutationObserver ? new MutationObserver(cb) +/* c8 ignore next */ : {}); + // blocks mutation observer // eslint-disable-next-line no-use-before-define, max-len -const blocksMO = window.MutationObserver ? new MutationObserver(blocksMCB) - /* c8 ignore next */ : {}; +const blocksMO = createMO(blocksMCB); // media mutation observer // eslint-disable-next-line no-use-before-define, max-len -const mediaMO = window.MutationObserver ? new MutationObserver(mediaMCB) - /* c8 ignore next */ : {}; +const mediaMO = createMO(mediaMCB); + +// Check for the presence of URL parameters +const hasUrlParameters = ({ urlParameters }) => urlParameters.keys().length > 0; const PLUGINS = { cwv: 'cwv.js', @@ -43,11 +47,11 @@ const PLUGINS = { }, // Martech ads: { - condition: ({ urlParameters }) => urlParameters.keys().length, + condition: hasUrlParameters, file: 'ads.js', }, email: { - condition: ({ urlParameters }) => urlParameters.keys().length, + condition: hasUrlParameters, file: 'email.js', }, onetrust: { @@ -55,7 +59,7 @@ const PLUGINS = { file: 'onetrust.js', }, utm: { - condition: ({ urlParameters }) => urlParameters.keys().length, + condition: hasUrlParameters, file: 'utm.js', }, }; @@ -70,9 +74,12 @@ const PLUGIN_PARAMETERS = { async function loadPlugin(key, params) { const urlParameters = new URLSearchParams(window.location.search); - return PLUGINS[key] && (!PLUGINS[key].condition || PLUGINS[key].condition({ urlParameters })) - ? import(`../plugins/${PLUGINS[key].path || PLUGINS[key]}`).then((p) => p.default && p.default(params)) - : Promise.reject(new Error(`Plugin ${key} not found`)); + const plugin = PLUGINS[key]; + if (!plugin) return Promise.reject(new Error(`Plugin ${key} not found`)); + if (!plugin.condition || plugin.condition({ urlParameters })) { + return import(`../plugins/${plugin.file || plugin}`).then((p) => p.default && p.default(params)); + } + return Promise.resolve(); } function trackCheckpoint(checkpoint, data, t) { From d5aa373168d865b7da584ba18d4e9c9b03fc43ce Mon Sep 17 00:00:00 2001 From: Julien Ramboz Date: Mon, 13 Jan 2025 16:56:11 -0800 Subject: [PATCH 03/42] refactor: rreduce code duplication and add error handling --- modules/index.js | 62 ++++++++++++++++++++++-------------------------- 1 file changed, 28 insertions(+), 34 deletions(-) diff --git a/modules/index.js b/modules/index.js index ecf4b28..e3d7570 100644 --- a/modules/index.js +++ b/modules/index.js @@ -23,63 +23,57 @@ const createMO = (cb) => (window.MutationObserver ? new MutationObserver(cb) /* c8 ignore next */ : {}); // blocks mutation observer -// eslint-disable-next-line no-use-before-define, max-len +// eslint-disable-next-line no-use-before-define const blocksMO = createMO(blocksMCB); // media mutation observer -// eslint-disable-next-line no-use-before-define, max-len +// eslint-disable-next-line no-use-before-define const mediaMO = createMO(mediaMCB); // Check for the presence of URL parameters const hasUrlParameters = ({ urlParameters }) => urlParameters.keys().length > 0; +// Check for the presence of a given cookie +const hasCookieKey = (key) => () => document.cookie.split(';').map((c) => c.trim()).some((cookie) => cookie.startsWith(`${key}=`)); const PLUGINS = { cwv: 'cwv.js', navigation: 'navigation.js', // Interactive elements - form: { - condition: () => document.body.querySelector('form'), - file: 'form.js', - }, - video: { - condition: () => document.body.querySelector('video'), - file: 'video.js', - }, + form: { file: 'form.js', condition: () => document.body.querySelector('form') }, + video: { file: 'video.js', condition: () => document.body.querySelector('video') }, // Martech - ads: { - condition: hasUrlParameters, - file: 'ads.js', - }, - email: { - condition: hasUrlParameters, - file: 'email.js', - }, - onetrust: { - condition: () => document.cookie.split(';').map((c) => c.trim()).some((cookie) => cookie.startsWith('OptanonAlertBoxClosed=')), - file: 'onetrust.js', - }, - utm: { - condition: hasUrlParameters, - file: 'utm.js', - }, + ads: { file: 'ads.js', condition: hasUrlParameters }, + email: { file: 'email.js', condition: hasUrlParameters }, + onetrust: { file: 'onetrust.js', condition: () => hasCookieKey('OptanonAlertBoxClosed') }, + utm: { file: 'utm.js', condition: hasUrlParameters }, }; const PLUGIN_PARAMETERS = { + context: document.body, + fflags, sampleRUM, sourceSelector, targetSelector, - fflags, - context: window.document.body, }; +const pluginCache = new Map(); + async function loadPlugin(key, params) { - const urlParameters = new URLSearchParams(window.location.search); const plugin = PLUGINS[key]; if (!plugin) return Promise.reject(new Error(`Plugin ${key} not found`)); - if (!plugin.condition || plugin.condition({ urlParameters })) { - return import(`../plugins/${plugin.file || plugin}`).then((p) => p.default && p.default(params)); + const usp = new URLSearchParams(window.location.search); + if (!pluginCache.has(key) && plugin.condition && !plugin.condition({ urlParameters: usp })) { + return Promise.reject(new Error(`Condition for plugin ${key} not met`)); + } + const basePath = '../plugins/'; + if (!pluginCache.has(key)) { + try { + pluginCache.set(key, import(`${basePath}${plugin.file || plugin}`)); + } catch (e) { + return Promise.reject(new Error(`Error loading plugin ${key}: ${e.message}`)); + } } - return Promise.resolve(); + return pluginCache.get(key).then((p) => p.default && p.default(params)); } function trackCheckpoint(checkpoint, data, t) { @@ -246,8 +240,8 @@ function addTrackingFromConfig() { // Core tracking addLoadResourceTracking(); - addViewBlockTracking(window.document.body); - addViewMediaTracking(window.document.body); + addViewBlockTracking(document.body); + addViewMediaTracking(document.body); // Tracking extensions Object.keys(PLUGINS).filter((key) => loadPlugin(key, PLUGIN_PARAMETERS)); From 4613b004c617f4d503355b5c43008149df9101ef Mon Sep 17 00:00:00 2001 From: Julien Ramboz Date: Mon, 13 Jan 2025 17:02:42 -0800 Subject: [PATCH 04/42] feat: allow external extension via window.RUM_PLUGINS --- modules/index.js | 31 +++++++++++++++++++------------ 1 file changed, 19 insertions(+), 12 deletions(-) diff --git a/modules/index.js b/modules/index.js index e3d7570..e14a193 100644 --- a/modules/index.js +++ b/modules/index.js @@ -35,17 +35,24 @@ const hasUrlParameters = ({ urlParameters }) => urlParameters.keys().length > 0; // Check for the presence of a given cookie const hasCookieKey = (key) => () => document.cookie.split(';').map((c) => c.trim()).some((cookie) => cookie.startsWith(`${key}=`)); +const pluginBasePath = '../plugins'; + const PLUGINS = { - cwv: 'cwv.js', - navigation: 'navigation.js', + cwv: `${pluginBasePath}/cwv.js`, + navigation: `${pluginBasePath}/navigation.js`, // Interactive elements - form: { file: 'form.js', condition: () => document.body.querySelector('form') }, - video: { file: 'video.js', condition: () => document.body.querySelector('video') }, + form: { url: `${pluginBasePath}/form.js`, condition: () => document.body.querySelector('form') }, + video: { url: `${pluginBasePath}/video.js`, condition: () => document.body.querySelector('video') }, // Martech - ads: { file: 'ads.js', condition: hasUrlParameters }, - email: { file: 'email.js', condition: hasUrlParameters }, - onetrust: { file: 'onetrust.js', condition: () => hasCookieKey('OptanonAlertBoxClosed') }, - utm: { file: 'utm.js', condition: hasUrlParameters }, + ads: { url: `${pluginBasePath}/ads.js`, condition: hasUrlParameters }, + email: { url: `${pluginBasePath}/email.js`, condition: hasUrlParameters }, + onetrust: { url: `${pluginBasePath}/onetrust.js`, condition: () => hasCookieKey('OptanonAlertBoxClosed') }, + utm: { url: `${pluginBasePath}/utm.js`, condition: hasUrlParameters }, +}; + +const allPlugins = { + ...(window.RUM_PLUGINS || {}), + PLUGINS, }; const PLUGIN_PARAMETERS = { @@ -59,16 +66,15 @@ const PLUGIN_PARAMETERS = { const pluginCache = new Map(); async function loadPlugin(key, params) { - const plugin = PLUGINS[key]; + const plugin = allPlugins[key]; if (!plugin) return Promise.reject(new Error(`Plugin ${key} not found`)); const usp = new URLSearchParams(window.location.search); if (!pluginCache.has(key) && plugin.condition && !plugin.condition({ urlParameters: usp })) { return Promise.reject(new Error(`Condition for plugin ${key} not met`)); } - const basePath = '../plugins/'; if (!pluginCache.has(key)) { try { - pluginCache.set(key, import(`${basePath}${plugin.file || plugin}`)); + pluginCache.set(key, import(`${plugin.url || plugin}`)); } catch (e) { return Promise.reject(new Error(`Error loading plugin ${key}: ${e.message}`)); } @@ -244,7 +250,8 @@ function addTrackingFromConfig() { addViewMediaTracking(document.body); // Tracking extensions - Object.keys(PLUGINS).filter((key) => loadPlugin(key, PLUGIN_PARAMETERS)); + Object.keys(allPlugins) + .forEach((key) => loadPlugin(key, PLUGIN_PARAMETERS)); fflags.enabled('language', () => { const target = navigator.language; From 9726dc8f98bd71936c8a8f430cae73b6a8f5d63f Mon Sep 17 00:00:00 2001 From: Julien Ramboz Date: Mon, 13 Jan 2025 17:14:50 -0800 Subject: [PATCH 05/42] fix: set proper url base for plugins --- modules/index.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/modules/index.js b/modules/index.js index e14a193..a5d4da3 100644 --- a/modules/index.js +++ b/modules/index.js @@ -35,7 +35,7 @@ const hasUrlParameters = ({ urlParameters }) => urlParameters.keys().length > 0; // Check for the presence of a given cookie const hasCookieKey = (key) => () => document.cookie.split(';').map((c) => c.trim()).some((cookie) => cookie.startsWith(`${key}=`)); -const pluginBasePath = '../plugins'; +const pluginBasePath = new URL('.rum/@adobe/helix-rum-enhancer@^2/src/plugins', sampleRUM.baseURL).href; const PLUGINS = { cwv: `${pluginBasePath}/cwv.js`, From 068c5c5cd425be5f1206ab73936cd6e398b8071f Mon Sep 17 00:00:00 2001 From: Julien Ramboz Date: Wed, 15 Jan 2025 16:04:31 -0800 Subject: [PATCH 06/42] refactor: address PR feedback --- modules/index.js | 85 ++++++++++++++++++++++++++++++++++--------- plugins/ads.js | 27 -------------- plugins/cwv.js | 2 +- plugins/email.js | 21 ----------- plugins/form.js | 2 +- plugins/martech.js | 54 +++++++++++++++++++++++++++ plugins/navigation.js | 58 ----------------------------- plugins/onetrust.js | 2 +- plugins/utm.js | 21 ----------- plugins/video.js | 6 ++- 10 files changed, 128 insertions(+), 150 deletions(-) delete mode 100644 plugins/ads.js delete mode 100644 plugins/email.js create mode 100644 plugins/martech.js delete mode 100644 plugins/navigation.js delete mode 100644 plugins/utm.js diff --git a/modules/index.js b/modules/index.js index a5d4da3..38b759f 100644 --- a/modules/index.js +++ b/modules/index.js @@ -30,8 +30,6 @@ const blocksMO = createMO(blocksMCB); // eslint-disable-next-line no-use-before-define const mediaMO = createMO(mediaMCB); -// Check for the presence of URL parameters -const hasUrlParameters = ({ urlParameters }) => urlParameters.keys().length > 0; // Check for the presence of a given cookie const hasCookieKey = (key) => () => document.cookie.split(';').map((c) => c.trim()).some((cookie) => cookie.startsWith(`${key}=`)); @@ -39,20 +37,12 @@ const pluginBasePath = new URL('.rum/@adobe/helix-rum-enhancer@^2/src/plugins', const PLUGINS = { cwv: `${pluginBasePath}/cwv.js`, - navigation: `${pluginBasePath}/navigation.js`, // Interactive elements - form: { url: `${pluginBasePath}/form.js`, condition: () => document.body.querySelector('form') }, - video: { url: `${pluginBasePath}/video.js`, condition: () => document.body.querySelector('video') }, + form: { url: `${pluginBasePath}/form.js`, condition: () => document.body.querySelector('form'), isBlockDependent: true }, + video: { url: `${pluginBasePath}/video.js`, condition: () => document.body.querySelector('video'), isBlockDependent: true }, // Martech - ads: { url: `${pluginBasePath}/ads.js`, condition: hasUrlParameters }, - email: { url: `${pluginBasePath}/email.js`, condition: hasUrlParameters }, - onetrust: { url: `${pluginBasePath}/onetrust.js`, condition: () => hasCookieKey('OptanonAlertBoxClosed') }, - utm: { url: `${pluginBasePath}/utm.js`, condition: hasUrlParameters }, -}; - -const allPlugins = { - ...(window.RUM_PLUGINS || {}), - PLUGINS, + martech: { url: `${pluginBasePath}/martech.js`, condition: ({ urlParameters }) => urlParameters.keys().length > 0 }, + onetrust: { url: `${pluginBasePath}/onetrust.js`, condition: () => hasCookieKey('OptanonAlertBoxClosed') || document.querySelector('body > div#onetrust-consent-sdk'), isBlockDependent: true }, }; const PLUGIN_PARAMETERS = { @@ -66,7 +56,7 @@ const PLUGIN_PARAMETERS = { const pluginCache = new Map(); async function loadPlugin(key, params) { - const plugin = allPlugins[key]; + const plugin = PLUGINS[key]; if (!plugin) return Promise.reject(new Error(`Plugin ${key} not found`)); const usp = new URLSearchParams(window.location.search); if (!pluginCache.has(key) && plugin.condition && !plugin.condition({ urlParameters: usp })) { @@ -82,6 +72,17 @@ async function loadPlugin(key, params) { return pluginCache.get(key).then((p) => p.default && p.default(params)); } +async function loadPlugins(filter = () => true, params = PLUGIN_PARAMETERS) { + return Promise.all( + Object.values(PLUGINS) + .filter(([, plugin]) => filter(plugin)) + .map(([key]) => loadPlugin(key, params)), + ).catch((err) => { + // eslint-disable-next-line no-console + console.error('Failed to load plugins', err); + }); +} + function trackCheckpoint(checkpoint, data, t) { const { weight, id } = window.hlx.rum; if (isSelected) { @@ -111,6 +112,54 @@ function processQueue() { } } +function addNavigationTracking() { + // enter checkpoint when referrer is not the current page url + const navigate = (source, type, redirectCount) => { + // target can be 'visible', 'hidden' (background tab) or 'prerendered' (speculation rules) + const payload = { source, target: document.visibilityState }; + /* c8 ignore next 13 */ + // prerendering cannot be tested yet with headless browsers + if (document.prerendering) { + // listen for "activation" of the current pre-rendered page + document.addEventListener('prerenderingchange', () => { + // pre-rendered page is now "activated" + payload.target = 'prerendered'; + sampleRUM('navigate', payload); // prerendered navigation + }, { + once: true, + }); + if (type === 'navigate') { + sampleRUM('prerender', payload); // prerendering page + } + } else if (type === 'reload' || source === window.location.href) { + sampleRUM('reload', payload); + } else if (type && type !== 'navigate') { + sampleRUM(type, payload); // back, forward, prerender, etc. + } else if (source && window.location.origin === new URL(source).origin) { + sampleRUM('navigate', payload); // internal navigation + } else { + sampleRUM('enter', payload); // enter site + } + fflags.enabled('redirect', () => { + const from = new URLSearchParams(window.location.search).get('redirect_from'); + if (redirectCount || from) { + sampleRUM('redirect', { source: from, target: redirectCount || 1 }); + } + }); + }; + + const processed = new Set(); // avoid processing duplicate types + new PerformanceObserver((list) => list + .getEntries() + .filter(({ type }) => !processed.has(type)) + .map((e) => [e, processed.add(e.type)]) + .map(([e]) => navigate( + window.hlx.referrer || document.referrer, + e.type, + e.redirectCount, + ))).observe({ type: 'navigation', buffered: true }); +} + function addLoadResourceTracking() { const observer = new PerformanceObserver((list) => { try { @@ -214,7 +263,7 @@ function blocksMCB(mutations) { .filter((m) => m.type === 'attributes' && m.attributeName === 'data-block-status') .filter((m) => m.target.dataset.blockStatus === 'loaded') .forEach((m) => { - addObserver('form', (el) => loadPlugin('form', { ...PLUGIN_PARAMETERS, context: el }), m.target); + addObserver('form', (el) => loadPlugins((p) => p.isBlockDependent, { ...PLUGIN_PARAMETERS, context: el }), m.target); addObserver('viewblock', addViewBlockTracking, m.target); }); } @@ -245,13 +294,13 @@ function addTrackingFromConfig() { }); // Core tracking + addNavigationTracking(); addLoadResourceTracking(); addViewBlockTracking(document.body); addViewMediaTracking(document.body); // Tracking extensions - Object.keys(allPlugins) - .forEach((key) => loadPlugin(key, PLUGIN_PARAMETERS)); + loadPlugins(); fflags.enabled('language', () => { const target = navigator.language; diff --git a/plugins/ads.js b/plugins/ads.js deleted file mode 100644 index ba3ece6..0000000 --- a/plugins/ads.js +++ /dev/null @@ -1,27 +0,0 @@ -/* - * Copyright 2025 Adobe. All rights reserved. - * This file is licensed to you under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. You may obtain a copy - * of the License at http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software distributed under - * the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR REPRESENTATIONS - * OF ANY KIND, either express or implied. See the License for the specific language - * governing permissions and limitations under the License. - */ -export function addAdsParametersTracking({ sampleRUM }) { - const networks = { - google: /gclid|gclsrc|wbraid|gbraid/, - doubleclick: /dclid/, - microsoft: /msclkid/, - facebook: /fb(cl|ad_|pxl_)id/, - twitter: /tw(clid|src|term)/, - linkedin: /li_fat_id/, - pinterest: /epik/, - tiktok: /ttclid/, - }; - const params = Array.from(new URLSearchParams(window.location.search).keys()); - Object.entries(networks).forEach(([network, regex]) => { - params.filter((param) => regex.test(param)).forEach((param) => sampleRUM('paid', { source: network, target: param })); - }); -} diff --git a/plugins/cwv.js b/plugins/cwv.js index 0cfa775..d4442c0 100644 --- a/plugins/cwv.js +++ b/plugins/cwv.js @@ -1,5 +1,5 @@ /* - * Copyright 2025 Adobe. All rights reserved. + * Copyright 2024 Adobe. All rights reserved. * This file is licensed to you under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. You may obtain a copy * of the License at http://www.apache.org/licenses/LICENSE-2.0 diff --git a/plugins/email.js b/plugins/email.js deleted file mode 100644 index 2328af0..0000000 --- a/plugins/email.js +++ /dev/null @@ -1,21 +0,0 @@ -/* - * Copyright 2025 Adobe. All rights reserved. - * This file is licensed to you under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. You may obtain a copy - * of the License at http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software distributed under - * the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR REPRESENTATIONS - * OF ANY KIND, either express or implied. See the License for the specific language - * governing permissions and limitations under the License. - */ -export function addEmailParameterTracking({ sampleRUM }) { - const networks = { - mailchimp: /mc_(c|e)id/, - marketo: /mkt_tok/, - }; - const params = Array.from(new URLSearchParams(window.location.search).keys()); - Object.entries(networks).forEach(([network, regex]) => { - params.filter((param) => regex.test(param)).forEach((param) => sampleRUM('email', { source: network, target: param })); - }); -} diff --git a/plugins/form.js b/plugins/form.js index 0ff398d..904a22d 100644 --- a/plugins/form.js +++ b/plugins/form.js @@ -1,5 +1,5 @@ /* - * Copyright 2025 Adobe. All rights reserved. + * Copyright 2024 Adobe. All rights reserved. * This file is licensed to you under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. You may obtain a copy * of the License at http://www.apache.org/licenses/LICENSE-2.0 diff --git a/plugins/martech.js b/plugins/martech.js new file mode 100644 index 0000000..dec8ec0 --- /dev/null +++ b/plugins/martech.js @@ -0,0 +1,54 @@ +/* + * Copyright 2024 Adobe. All rights reserved. + * This file is licensed to you under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. You may obtain a copy + * of the License at http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software distributed under + * the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR REPRESENTATIONS + * OF ANY KIND, either express or implied. See the License for the specific language + * governing permissions and limitations under the License. + */ +function addAdsParametersTracking(usp, { sampleRUM }) { + const networks = { + google: /gclid|gclsrc|wbraid|gbraid/, + doubleclick: /dclid/, + microsoft: /msclkid/, + facebook: /fb(cl|ad_|pxl_)id/, + twitter: /tw(clid|src|term)/, + linkedin: /li_fat_id/, + pinterest: /epik/, + tiktok: /ttclid/, + }; + const params = Array.from(usp.keys()); + Object.entries(networks).forEach(([network, regex]) => { + params.filter((param) => regex.test(param)).forEach((param) => sampleRUM('paid', { source: network, target: param })); + }); +} + +function addEmailParameterTracking(usp, { sampleRUM }) { + const networks = { + mailchimp: /mc_(c|e)id/, + marketo: /mkt_tok/, + }; + const params = Array.from(usp.keys()); + Object.entries(networks).forEach(([network, regex]) => { + params.filter((param) => regex.test(param)).forEach((param) => sampleRUM('email', { source: network, target: param })); + }); +} + +function addUTMParametersTracking(usp, { sampleRUM }) { + Array.from(usp.entries()) + .filter(([key]) => key.startsWith('utm_')) + // exclude keys that may leak PII + .filter(([key]) => key !== 'utm_id') + .filter(([key]) => key !== 'utm_term') + .forEach(([source, target]) => sampleRUM('utm', { source, target })); +} + +export function addMartechTraking({ sampleRUM }) { + const usp = new URLSearchParams(window.location.search); + addAdsParametersTracking(usp, { sampleRUM }); + addEmailParameterTracking(usp, { sampleRUM }); + addUTMParametersTracking(usp, { sampleRUM }); +} diff --git a/plugins/navigation.js b/plugins/navigation.js deleted file mode 100644 index ebad8b1..0000000 --- a/plugins/navigation.js +++ /dev/null @@ -1,58 +0,0 @@ -/* - * Copyright 2025 Adobe. All rights reserved. - * This file is licensed to you under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. You may obtain a copy - * of the License at http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software distributed under - * the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR REPRESENTATIONS - * OF ANY KIND, either express or implied. See the License for the specific language - * governing permissions and limitations under the License. - */ -export default function addNavigationTracking({ sampleRUM, fflags }) { - // enter checkpoint when referrer is not the current page url - const navigate = (source, type, redirectCount) => { - // target can be 'visible', 'hidden' (background tab) or 'prerendered' (speculation rules) - const payload = { source, target: document.visibilityState }; - /* c8 ignore next 13 */ - // prerendering cannot be tested yet with headless browsers - if (document.prerendering) { - // listen for "activation" of the current pre-rendered page - document.addEventListener('prerenderingchange', () => { - // pre-rendered page is now "activated" - payload.target = 'prerendered'; - sampleRUM('navigate', payload); // prerendered navigation - }, { - once: true, - }); - if (type === 'navigate') { - sampleRUM('prerender', payload); // prerendering page - } - } else if (type === 'reload' || source === window.location.href) { - sampleRUM('reload', payload); - } else if (type && type !== 'navigate') { - sampleRUM(type, payload); // back, forward, prerender, etc. - } else if (source && window.location.origin === new URL(source).origin) { - sampleRUM('navigate', payload); // internal navigation - } else { - sampleRUM('enter', payload); // enter site - } - fflags.enabled('redirect', () => { - const from = new URLSearchParams(window.location.search).get('redirect_from'); - if (redirectCount || from) { - sampleRUM('redirect', { source: from, target: redirectCount || 1 }); - } - }); - }; - - const processed = new Set(); // avoid processing duplicate types - new PerformanceObserver((list) => list - .getEntries() - .filter(({ type }) => !processed.has(type)) - .map((e) => [e, processed.add(e.type)]) - .map(([e]) => navigate( - window.hlx.referrer || document.referrer, - e.type, - e.redirectCount, - ))).observe({ type: 'navigation', buffered: true }); -} diff --git a/plugins/onetrust.js b/plugins/onetrust.js index a482454..0f34994 100644 --- a/plugins/onetrust.js +++ b/plugins/onetrust.js @@ -1,5 +1,5 @@ /* - * Copyright 2025 Adobe. All rights reserved. + * Copyright 2024 Adobe. All rights reserved. * This file is licensed to you under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. You may obtain a copy * of the License at http://www.apache.org/licenses/LICENSE-2.0 diff --git a/plugins/utm.js b/plugins/utm.js deleted file mode 100644 index 10cbd69..0000000 --- a/plugins/utm.js +++ /dev/null @@ -1,21 +0,0 @@ -/* - * Copyright 2025 Adobe. All rights reserved. - * This file is licensed to you under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. You may obtain a copy - * of the License at http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software distributed under - * the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR REPRESENTATIONS - * OF ANY KIND, either express or implied. See the License for the specific language - * governing permissions and limitations under the License. - */ - -export function addUTMParametersTracking({ sampleRUM }) { - const usp = new URLSearchParams(window.location.search); - [...usp.entries()] - .filter(([key]) => key.startsWith('utm_')) - // exclude keys that may leak PII - .filter(([key]) => key !== 'utm_id') - .filter(([key]) => key !== 'utm_term') - .forEach(([source, target]) => sampleRUM('utm', { source, target })); -} diff --git a/plugins/video.js b/plugins/video.js index 67d96a0..046680a 100644 --- a/plugins/video.js +++ b/plugins/video.js @@ -10,6 +10,8 @@ * governing permissions and limitations under the License. */ -export function addVideoTracking() { - // TODO: Add video tracking +export function addVideoTracking({ context }) { + context.querySelectorAll('video').forEach(() => { + // TODO: Add video tracking + }); } From 95a653e73b98d12db47945b8344698afc59ce3d1 Mon Sep 17 00:00:00 2001 From: Julien Ramboz Date: Wed, 15 Jan 2025 17:53:24 -0800 Subject: [PATCH 07/42] refactor: address PR feedback --- rollup.config.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/rollup.config.js b/rollup.config.js index e5fec44..fcd998e 100644 --- a/rollup.config.js +++ b/rollup.config.js @@ -34,7 +34,7 @@ const bundles = [ outputFile: 'src/index', }, // Library plugins - ...['ads', 'cwv', 'email', 'form', 'navigation', 'onetrust', 'utm', 'video'].map((plugin) => ({ + ...['cwv', 'form', 'martech', 'onetrust', 'video'].map((plugin) => ({ source: `plugins/${plugin}.js`, outputFile: `src/plugins/${plugin}`, })), From 5c9adbc2502203495a05d4fd2be6e05cc11102df Mon Sep 17 00:00:00 2001 From: Julien Ramboz Date: Thu, 16 Jan 2025 10:12:06 -0800 Subject: [PATCH 08/42] fix: bugs and failing tests --- modules/index.js | 20 +++++++++++--------- plugins/martech.js | 2 +- plugins/onetrust.js | 2 +- plugins/video.js | 2 +- 4 files changed, 14 insertions(+), 12 deletions(-) diff --git a/modules/index.js b/modules/index.js index 38b759f..36c199d 100644 --- a/modules/index.js +++ b/modules/index.js @@ -33,7 +33,7 @@ const mediaMO = createMO(mediaMCB); // Check for the presence of a given cookie const hasCookieKey = (key) => () => document.cookie.split(';').map((c) => c.trim()).some((cookie) => cookie.startsWith(`${key}=`)); -const pluginBasePath = new URL('.rum/@adobe/helix-rum-enhancer@^2/src/plugins', sampleRUM.baseURL).href; +const pluginBasePath = '../plugins'; const PLUGINS = { cwv: `${pluginBasePath}/cwv.js`, @@ -41,8 +41,8 @@ const PLUGINS = { form: { url: `${pluginBasePath}/form.js`, condition: () => document.body.querySelector('form'), isBlockDependent: true }, video: { url: `${pluginBasePath}/video.js`, condition: () => document.body.querySelector('video'), isBlockDependent: true }, // Martech - martech: { url: `${pluginBasePath}/martech.js`, condition: ({ urlParameters }) => urlParameters.keys().length > 0 }, - onetrust: { url: `${pluginBasePath}/onetrust.js`, condition: () => hasCookieKey('OptanonAlertBoxClosed') || document.querySelector('body > div#onetrust-consent-sdk'), isBlockDependent: true }, + martech: { url: `${pluginBasePath}/martech.js`, condition: ({ urlParameters }) => urlParameters.keys().toArray().length > 0 }, + onetrust: { url: `${pluginBasePath}/onetrust.js`, condition: () => (document.body.querySelector('body > div#onetrust-consent-sdk') || hasCookieKey('OptanonAlertBoxClosed')), isBlockDependent: true }, }; const PLUGIN_PARAMETERS = { @@ -57,29 +57,31 @@ const pluginCache = new Map(); async function loadPlugin(key, params) { const plugin = PLUGINS[key]; - if (!plugin) return Promise.reject(new Error(`Plugin ${key} not found`)); + if (!plugin) return null; const usp = new URLSearchParams(window.location.search); if (!pluginCache.has(key) && plugin.condition && !plugin.condition({ urlParameters: usp })) { - return Promise.reject(new Error(`Condition for plugin ${key} not met`)); + return null; } if (!pluginCache.has(key)) { try { pluginCache.set(key, import(`${plugin.url || plugin}`)); } catch (e) { - return Promise.reject(new Error(`Error loading plugin ${key}: ${e.message}`)); + return null; } } - return pluginCache.get(key).then((p) => p.default && p.default(params)); + const pluginLoadPromise = pluginCache.get(key); + return pluginLoadPromise + .then((p) => (p.default && p.default(params)) || (typeof p === 'function' && p(params))); } async function loadPlugins(filter = () => true, params = PLUGIN_PARAMETERS) { return Promise.all( - Object.values(PLUGINS) + Object.entries(PLUGINS) .filter(([, plugin]) => filter(plugin)) .map(([key]) => loadPlugin(key, params)), ).catch((err) => { // eslint-disable-next-line no-console - console.error('Failed to load plugins', err); + console.error('Failed to load plugins', err.message); }); } diff --git a/plugins/martech.js b/plugins/martech.js index dec8ec0..6685312 100644 --- a/plugins/martech.js +++ b/plugins/martech.js @@ -46,7 +46,7 @@ function addUTMParametersTracking(usp, { sampleRUM }) { .forEach(([source, target]) => sampleRUM('utm', { source, target })); } -export function addMartechTraking({ sampleRUM }) { +export default function addMartechTraking({ sampleRUM }) { const usp = new URLSearchParams(window.location.search); addAdsParametersTracking(usp, { sampleRUM }); addEmailParameterTracking(usp, { sampleRUM }); diff --git a/plugins/onetrust.js b/plugins/onetrust.js index 0f34994..747912b 100644 --- a/plugins/onetrust.js +++ b/plugins/onetrust.js @@ -9,7 +9,7 @@ * OF ANY KIND, either express or implied. See the License for the specific language * governing permissions and limitations under the License. */ -export function addCookieConsentTracking({ sampleRUM }) { +export default function addCookieConsentTracking({ sampleRUM }) { const cmpCookie = document.cookie.split(';') .map((c) => c.trim()) .find((cookie) => cookie.startsWith('OptanonAlertBoxClosed=')); diff --git a/plugins/video.js b/plugins/video.js index 046680a..ff3b9fd 100644 --- a/plugins/video.js +++ b/plugins/video.js @@ -10,7 +10,7 @@ * governing permissions and limitations under the License. */ -export function addVideoTracking({ context }) { +export default function addVideoTracking({ context }) { context.querySelectorAll('video').forEach(() => { // TODO: Add video tracking }); From 1c21afd8cd982d4c33feba863d2251311f36e153 Mon Sep 17 00:00:00 2001 From: Julien Ramboz Date: Thu, 16 Jan 2025 10:27:40 -0800 Subject: [PATCH 09/42] fix: cross-browser compatibility --- modules/index.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/modules/index.js b/modules/index.js index 36c199d..748ba95 100644 --- a/modules/index.js +++ b/modules/index.js @@ -41,7 +41,7 @@ const PLUGINS = { form: { url: `${pluginBasePath}/form.js`, condition: () => document.body.querySelector('form'), isBlockDependent: true }, video: { url: `${pluginBasePath}/video.js`, condition: () => document.body.querySelector('video'), isBlockDependent: true }, // Martech - martech: { url: `${pluginBasePath}/martech.js`, condition: ({ urlParameters }) => urlParameters.keys().toArray().length > 0 }, + martech: { url: `${pluginBasePath}/martech.js`, condition: ({ urlParameters }) => [...urlParameters.keys()].length > 0 }, onetrust: { url: `${pluginBasePath}/onetrust.js`, condition: () => (document.body.querySelector('body > div#onetrust-consent-sdk') || hasCookieKey('OptanonAlertBoxClosed')), isBlockDependent: true }, }; From d88b010fd53d0d1a1fb4e5496c25ca8c65bd88d0 Mon Sep 17 00:00:00 2001 From: Lars Trieloff Date: Thu, 16 Jan 2025 10:14:49 -0800 Subject: [PATCH 10/42] build(rollup): remove broken cleanup plugin, replace with babel plugin --- package-lock.json | 556 +++++++++++++++++++++++++++++++++++++--------- package.json | 2 +- rollup.config.js | 9 +- 3 files changed, 455 insertions(+), 112 deletions(-) diff --git a/package-lock.json b/package-lock.json index c2353be..fb8598c 100644 --- a/package-lock.json +++ b/package-lock.json @@ -12,6 +12,7 @@ "@adobe/eslint-config-helix": "2.0.8", "@adobe/helix-rum-js": "2.10.0", "@esm-bundle/chai": "4.3.4-fix.0", + "@rollup/plugin-babel": "6.0.4", "@semantic-release/changelog": "6.0.3", "@semantic-release/git": "10.0.1", "@semantic-release/npm": "12.0.1", @@ -32,7 +33,6 @@ "mocha-multi-reporters": "1.5.1", "rollup": "4.30.1", "rollup-plugin-checksum": "1.0.1", - "rollup-plugin-cleanup": "3.2.1", "rollup-plugin-eslint-bundle": "9.0.0", "semantic-release": "24.2.1", "semantic-release-slack-bot": "^4.0.2", @@ -65,19 +65,194 @@ "dev": true, "license": "Apache-2.0" }, + "node_modules/@ampproject/remapping": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/@ampproject/remapping/-/remapping-2.3.0.tgz", + "integrity": "sha512-30iZtAPgz+LTIYoeivqYo853f02jBYSd5uGnGpkFV0M3xOt9aN73erkgYAmZU43x4VfqcnLxW9Kpg3R5LC4YYw==", + "dev": true, + "license": "Apache-2.0", + "peer": true, + "dependencies": { + "@jridgewell/gen-mapping": "^0.3.5", + "@jridgewell/trace-mapping": "^0.3.24" + }, + "engines": { + "node": ">=6.0.0" + } + }, "node_modules/@babel/code-frame": { - "version": "7.24.7", - "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.24.7.tgz", - "integrity": "sha512-BcYH1CVJBO9tvyIZ2jVeXgSIMvGZ2FDRvDdOIVQyuklNKSsx+eppDEBq/g47Ayw+RqNFE+URvOShmf+f/qwAlA==", + "version": "7.26.2", + "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.26.2.tgz", + "integrity": "sha512-RJlIHRueQgwWitWgF8OdFYGZX328Ax5BCemNGlqHfplnRT9ESi8JkFlvaVYbS+UubVY6dpv87Fs2u5M29iNFVQ==", "dev": true, + "license": "MIT", "dependencies": { - "@babel/highlight": "^7.24.7", + "@babel/helper-validator-identifier": "^7.25.9", + "js-tokens": "^4.0.0", "picocolors": "^1.0.0" }, "engines": { "node": ">=6.9.0" } }, + "node_modules/@babel/compat-data": { + "version": "7.26.5", + "resolved": "https://registry.npmjs.org/@babel/compat-data/-/compat-data-7.26.5.tgz", + "integrity": "sha512-XvcZi1KWf88RVbF9wn8MN6tYFloU5qX8KjuF3E1PVBmJ9eypXfs4GRiJwLuTZL0iSnJUKn1BFPa5BPZZJyFzPg==", + "dev": true, + "license": "MIT", + "peer": true, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/core": { + "version": "7.26.0", + "resolved": "https://registry.npmjs.org/@babel/core/-/core-7.26.0.tgz", + "integrity": "sha512-i1SLeK+DzNnQ3LL/CswPCa/E5u4lh1k6IAEphON8F+cXt0t9euTshDru0q7/IqMa1PMPz5RnHuHscF8/ZJsStg==", + "dev": true, + "license": "MIT", + "peer": true, + "dependencies": { + "@ampproject/remapping": "^2.2.0", + "@babel/code-frame": "^7.26.0", + "@babel/generator": "^7.26.0", + "@babel/helper-compilation-targets": "^7.25.9", + "@babel/helper-module-transforms": "^7.26.0", + "@babel/helpers": "^7.26.0", + "@babel/parser": "^7.26.0", + "@babel/template": "^7.25.9", + "@babel/traverse": "^7.25.9", + "@babel/types": "^7.26.0", + "convert-source-map": "^2.0.0", + "debug": "^4.1.0", + "gensync": "^1.0.0-beta.2", + "json5": "^2.2.3", + "semver": "^6.3.1" + }, + "engines": { + "node": ">=6.9.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/babel" + } + }, + "node_modules/@babel/core/node_modules/json5": { + "version": "2.2.3", + "resolved": "https://registry.npmjs.org/json5/-/json5-2.2.3.tgz", + "integrity": "sha512-XmOWe7eyHYH14cLdVPoyg+GOH3rYX++KpzrylJwSW98t3Nk+U8XOl8FWKOgwtzdb8lXGf6zYwDUzeHMWfxasyg==", + "dev": true, + "license": "MIT", + "peer": true, + "bin": { + "json5": "lib/cli.js" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/@babel/core/node_modules/semver": { + "version": "6.3.1", + "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.1.tgz", + "integrity": "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==", + "dev": true, + "license": "ISC", + "peer": true, + "bin": { + "semver": "bin/semver.js" + } + }, + "node_modules/@babel/generator": { + "version": "7.26.5", + "resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.26.5.tgz", + "integrity": "sha512-2caSP6fN9I7HOe6nqhtft7V4g7/V/gfDsC3Ag4W7kEzzvRGKqiv0pu0HogPiZ3KaVSoNDhUws6IJjDjpfmYIXw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/parser": "^7.26.5", + "@babel/types": "^7.26.5", + "@jridgewell/gen-mapping": "^0.3.5", + "@jridgewell/trace-mapping": "^0.3.25", + "jsesc": "^3.0.2" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-compilation-targets": { + "version": "7.26.5", + "resolved": "https://registry.npmjs.org/@babel/helper-compilation-targets/-/helper-compilation-targets-7.26.5.tgz", + "integrity": "sha512-IXuyn5EkouFJscIDuFF5EsiSolseme1s0CZB+QxVugqJLYmKdxI1VfIBOst0SUu4rnk2Z7kqTwmoO1lp3HIfnA==", + "dev": true, + "license": "MIT", + "peer": true, + "dependencies": { + "@babel/compat-data": "^7.26.5", + "@babel/helper-validator-option": "^7.25.9", + "browserslist": "^4.24.0", + "lru-cache": "^5.1.1", + "semver": "^6.3.1" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-compilation-targets/node_modules/lru-cache": { + "version": "5.1.1", + "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-5.1.1.tgz", + "integrity": "sha512-KpNARQA3Iwv+jTA0utUVVbrh+Jlrr1Fv0e56GGzAFOXN7dk/FviaDW8LHmK52DlcH4WP2n6gI8vN1aesBFgo9w==", + "dev": true, + "license": "ISC", + "peer": true, + "dependencies": { + "yallist": "^3.0.2" + } + }, + "node_modules/@babel/helper-compilation-targets/node_modules/semver": { + "version": "6.3.1", + "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.1.tgz", + "integrity": "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==", + "dev": true, + "license": "ISC", + "peer": true, + "bin": { + "semver": "bin/semver.js" + } + }, + "node_modules/@babel/helper-module-imports": { + "version": "7.25.9", + "resolved": "https://registry.npmjs.org/@babel/helper-module-imports/-/helper-module-imports-7.25.9.tgz", + "integrity": "sha512-tnUA4RsrmflIM6W6RFTLFSXITtl0wKjgpnLgXyowocVPrbYrLUXSBXDgTs8BlbmIzIdlBySRQjINYs2BAkiLtw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/traverse": "^7.25.9", + "@babel/types": "^7.25.9" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-module-transforms": { + "version": "7.26.0", + "resolved": "https://registry.npmjs.org/@babel/helper-module-transforms/-/helper-module-transforms-7.26.0.tgz", + "integrity": "sha512-xO+xu6B5K2czEnQye6BHA7DolFFmS3LB7stHZFaOLb1pAwO1HWLS8fXA+eh0A2yIvltPVmx3eNNDBJA2SLHXFw==", + "dev": true, + "license": "MIT", + "peer": true, + "dependencies": { + "@babel/helper-module-imports": "^7.25.9", + "@babel/helper-validator-identifier": "^7.25.9", + "@babel/traverse": "^7.25.9" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0" + } + }, "node_modules/@babel/helper-string-parser": { "version": "7.25.9", "resolved": "https://registry.npmjs.org/@babel/helper-string-parser/-/helper-string-parser-7.25.9.tgz", @@ -98,29 +273,40 @@ "node": ">=6.9.0" } }, - "node_modules/@babel/highlight": { - "version": "7.24.7", - "resolved": "https://registry.npmjs.org/@babel/highlight/-/highlight-7.24.7.tgz", - "integrity": "sha512-EStJpq4OuY8xYfhGVXngigBJRWxftKX9ksiGDnmlY3o7B/V7KIAc9X4oiK87uPJSc/vs5L869bem5fhZa8caZw==", + "node_modules/@babel/helper-validator-option": { + "version": "7.25.9", + "resolved": "https://registry.npmjs.org/@babel/helper-validator-option/-/helper-validator-option-7.25.9.tgz", + "integrity": "sha512-e/zv1co8pp55dNdEcCynfj9X7nyUKUXoUEwfXqaZt0omVOmDe9oOTdKStH4GmAw6zxMFs50ZayuMfHDKlO7Tfw==", + "dev": true, + "license": "MIT", + "peer": true, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helpers": { + "version": "7.26.0", + "resolved": "https://registry.npmjs.org/@babel/helpers/-/helpers-7.26.0.tgz", + "integrity": "sha512-tbhNuIxNcVb21pInl3ZSjksLCvgdZy9KwJ8brv993QtIVKJBBkYXz4q4ZbAv31GdnC+R90np23L5FbEBlthAEw==", "dev": true, + "license": "MIT", + "peer": true, "dependencies": { - "@babel/helper-validator-identifier": "^7.24.7", - "chalk": "^2.4.2", - "js-tokens": "^4.0.0", - "picocolors": "^1.0.0" + "@babel/template": "^7.25.9", + "@babel/types": "^7.26.0" }, "engines": { "node": ">=6.9.0" } }, "node_modules/@babel/parser": { - "version": "7.26.1", - "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.26.1.tgz", - "integrity": "sha512-reoQYNiAJreZNsJzyrDNzFQ+IQ5JFiIzAHJg9bn94S3l+4++J7RsIhNMoB+lgP/9tpmiAQqspv+xfdxTSzREOw==", + "version": "7.26.5", + "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.26.5.tgz", + "integrity": "sha512-SRJ4jYmXRqV1/Xc+TIVG84WjHBXKlxO9sHQnA2Pf12QQEAp1LOh6kDzNHXcUnbH1QI0FDoPPVOt+vyUDucxpaw==", "dev": true, "license": "MIT", "dependencies": { - "@babel/types": "^7.26.0" + "@babel/types": "^7.26.5" }, "bin": { "parser": "bin/babel-parser.js" @@ -129,10 +315,54 @@ "node": ">=6.0.0" } }, + "node_modules/@babel/template": { + "version": "7.25.9", + "resolved": "https://registry.npmjs.org/@babel/template/-/template-7.25.9.tgz", + "integrity": "sha512-9DGttpmPvIxBb/2uwpVo3dqJ+O6RooAFOS+lB+xDqoE2PVCE8nfoHMdZLpfCQRLwvohzXISPZcgxt80xLfsuwg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/code-frame": "^7.25.9", + "@babel/parser": "^7.25.9", + "@babel/types": "^7.25.9" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/traverse": { + "version": "7.26.5", + "resolved": "https://registry.npmjs.org/@babel/traverse/-/traverse-7.26.5.tgz", + "integrity": "sha512-rkOSPOw+AXbgtwUga3U4u8RpoK9FEFWBNAlTpcnkLFjL5CT+oyHNuUUC/xx6XefEJ16r38r8Bc/lfp6rYuHeJQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/code-frame": "^7.26.2", + "@babel/generator": "^7.26.5", + "@babel/parser": "^7.26.5", + "@babel/template": "^7.25.9", + "@babel/types": "^7.26.5", + "debug": "^4.3.1", + "globals": "^11.1.0" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/traverse/node_modules/globals": { + "version": "11.12.0", + "resolved": "https://registry.npmjs.org/globals/-/globals-11.12.0.tgz", + "integrity": "sha512-WOBp/EEGUiIsJSp7wcv/y6MO+lV9UoncWqxuFfm8eBwzWNgyfBd6Gz+IeKQ9jCmyhoH99g15M3T+QaVHFjizVA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=4" + } + }, "node_modules/@babel/types": { - "version": "7.26.0", - "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.26.0.tgz", - "integrity": "sha512-Z/yiTPj+lDVnF7lWeKCIJzaIkI0vYO87dMpZ4bg4TDrFe4XXLFWL1TbXU27gBP3QccxV9mZICCrnjnYlJjXHOA==", + "version": "7.26.5", + "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.26.5.tgz", + "integrity": "sha512-L6mZmwFDK6Cjh1nRCLXpa6no13ZIioJDz7mdkzHv399pThrTa/k0nUlNaenOeh2kWu/iaOQYElEpKPUswUa9Vg==", "dev": true, "license": "MIT", "dependencies": { @@ -394,6 +624,21 @@ "node": ">=8" } }, + "node_modules/@jridgewell/gen-mapping": { + "version": "0.3.8", + "resolved": "https://registry.npmjs.org/@jridgewell/gen-mapping/-/gen-mapping-0.3.8.tgz", + "integrity": "sha512-imAbBGkb+ebQyxKgzv5Hu2nmROxoDOXHh80evxdoXNOrvAnVx7zimzc1Oo5h9RlfV4vPXaE2iM5pOFbvOCClWA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@jridgewell/set-array": "^1.2.1", + "@jridgewell/sourcemap-codec": "^1.4.10", + "@jridgewell/trace-mapping": "^0.3.24" + }, + "engines": { + "node": ">=6.0.0" + } + }, "node_modules/@jridgewell/resolve-uri": { "version": "3.1.2", "resolved": "https://registry.npmjs.org/@jridgewell/resolve-uri/-/resolve-uri-3.1.2.tgz", @@ -403,6 +648,16 @@ "node": ">=6.0.0" } }, + "node_modules/@jridgewell/set-array": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/@jridgewell/set-array/-/set-array-1.2.1.tgz", + "integrity": "sha512-R8gLRTZeyp03ymzP/6Lil/28tGeGEzhx1q2k703KGWRAI1VdvPIXdG70VJc2pAMw3NA6JKL5hhFu1sJX0Mnn/A==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6.0.0" + } + }, "node_modules/@jridgewell/sourcemap-codec": { "version": "1.4.15", "resolved": "https://registry.npmjs.org/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.4.15.tgz", @@ -685,6 +940,33 @@ "node": ">=18" } }, + "node_modules/@rollup/plugin-babel": { + "version": "6.0.4", + "resolved": "https://registry.npmjs.org/@rollup/plugin-babel/-/plugin-babel-6.0.4.tgz", + "integrity": "sha512-YF7Y52kFdFT/xVSuVdjkV5ZdX/3YtmX0QulG+x0taQOtJdHYzVU61aSSkAgVJ7NOv6qPkIYiJSgSWWN/DM5sGw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-module-imports": "^7.18.6", + "@rollup/pluginutils": "^5.0.1" + }, + "engines": { + "node": ">=14.0.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0", + "@types/babel__core": "^7.1.9", + "rollup": "^1.20.0||^2.0.0||^3.0.0||^4.0.0" + }, + "peerDependenciesMeta": { + "@types/babel__core": { + "optional": true + }, + "rollup": { + "optional": true + } + } + }, "node_modules/@rollup/plugin-node-resolve": { "version": "15.2.3", "resolved": "https://registry.npmjs.org/@rollup/plugin-node-resolve/-/plugin-node-resolve-15.2.3.tgz", @@ -2639,6 +2921,40 @@ "integrity": "sha512-qhAVI1+Av2X7qelOfAIYwXONood6XlZE/fXaBSmW/T5SzLAmCgzi+eiWE7fUvbHaeNBQH13UftjpXxsfLkMpgw==", "dev": true }, + "node_modules/browserslist": { + "version": "4.24.4", + "resolved": "https://registry.npmjs.org/browserslist/-/browserslist-4.24.4.tgz", + "integrity": "sha512-KDi1Ny1gSePi1vm0q4oxSF8b4DR44GF4BbmS2YdhPLOEqd8pDviZOGH/GsmRwoWJ2+5Lr085X7naowMwKHDG1A==", + "dev": true, + "funding": [ + { + "type": "opencollective", + "url": "https://opencollective.com/browserslist" + }, + { + "type": "tidelift", + "url": "https://tidelift.com/funding/github/npm/browserslist" + }, + { + "type": "github", + "url": "https://github.com/sponsors/ai" + } + ], + "license": "MIT", + "peer": true, + "dependencies": { + "caniuse-lite": "^1.0.30001688", + "electron-to-chromium": "^1.5.73", + "node-releases": "^2.0.19", + "update-browserslist-db": "^1.1.1" + }, + "bin": { + "browserslist": "cli.js" + }, + "engines": { + "node": "^6 || ^7 || ^8 || ^9 || ^10 || ^11 || ^12 || >=13.7" + } + }, "node_modules/buffer": { "version": "5.7.1", "resolved": "https://registry.npmjs.org/buffer/-/buffer-5.7.1.tgz", @@ -2813,6 +3129,28 @@ "url": "https://github.com/sponsors/sindresorhus" } }, + "node_modules/caniuse-lite": { + "version": "1.0.30001692", + "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001692.tgz", + "integrity": "sha512-A95VKan0kdtrsnMubMKxEKUKImOPSuCpYgxSQBo036P5YYgVIcOYJEgt/txJWqObiRQeISNCfef9nvlQ0vbV7A==", + "dev": true, + "funding": [ + { + "type": "opencollective", + "url": "https://opencollective.com/browserslist" + }, + { + "type": "tidelift", + "url": "https://tidelift.com/funding/github/npm/caniuse-lite" + }, + { + "type": "github", + "url": "https://github.com/sponsors/ai" + } + ], + "license": "CC-BY-4.0", + "peer": true + }, "node_modules/catharsis": { "version": "0.9.0", "resolved": "https://registry.npmjs.org/catharsis/-/catharsis-0.9.0.tgz", @@ -4158,6 +4496,14 @@ "integrity": "sha512-WMwm9LhRUo+WUaRN+vRuETqG89IgZphVSNkdFgeb6sS/E4OrDIN7t48CAewSHXc6C8lefD8KKfr5vY61brQlow==", "dev": true }, + "node_modules/electron-to-chromium": { + "version": "1.5.83", + "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.5.83.tgz", + "integrity": "sha512-LcUDPqSt+V0QmI47XLzZrz5OqILSMGsPFkDYus22rIbgorSvBYEFqq854ltTmUdHkY92FSdAAvsh4jWEULMdfQ==", + "dev": true, + "license": "ISC", + "peer": true + }, "node_modules/emoji-regex": { "version": "10.3.0", "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-10.3.0.tgz", @@ -4525,10 +4871,11 @@ } }, "node_modules/escalade": { - "version": "3.1.2", - "resolved": "https://registry.npmjs.org/escalade/-/escalade-3.1.2.tgz", - "integrity": "sha512-ErCHMCae19vR8vQGe50xIsVomy19rg6gFu3+r3jkEO46suLMWBksvVyoGgQV+jOfl84ZSOSlmv6Gxa89PmTGmA==", + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/escalade/-/escalade-3.2.0.tgz", + "integrity": "sha512-WUj2qlxaQtO4g6Pq5c29GTcWGDyd8itL8zTlipgECz3JesAiiOKotd8JU6otB3PACgG6xkJUyVhboMS+bje/jA==", "dev": true, + "license": "MIT", "engines": { "node": ">=6" } @@ -5491,6 +5838,17 @@ "url": "https://github.com/sponsors/ljharb" } }, + "node_modules/gensync": { + "version": "1.0.0-beta.2", + "resolved": "https://registry.npmjs.org/gensync/-/gensync-1.0.0-beta.2.tgz", + "integrity": "sha512-3hN7NaskYvMDLQY55gnW3NQ+mesEAepTqlg+VEbj7zzqEMBVNhzcGYYeqFo/TlYz6eQiFcp1HcsCZO+nGgS8zg==", + "dev": true, + "license": "MIT", + "peer": true, + "engines": { + "node": ">=6.9.0" + } + }, "node_modules/get-caller-file": { "version": "2.0.5", "resolved": "https://registry.npmjs.org/get-caller-file/-/get-caller-file-2.0.5.tgz", @@ -6788,25 +7146,12 @@ "node": ">= 0.6.0" } }, - "node_modules/js-cleanup": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/js-cleanup/-/js-cleanup-1.2.0.tgz", - "integrity": "sha512-JeDD0yiiSt80fXzAVa/crrS0JDPQljyBG/RpOtaSbyDq03VHa9szJWMaWOYU/bcTn412uMN2MxApXq8v79cUiQ==", - "dev": true, - "dependencies": { - "magic-string": "^0.25.7", - "perf-regexes": "^1.0.1", - "skip-regex": "^1.0.2" - }, - "engines": { - "node": "^10.14.2 || >=12.0.0" - } - }, "node_modules/js-tokens": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-4.0.0.tgz", "integrity": "sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==", - "dev": true + "dev": true, + "license": "MIT" }, "node_modules/js-yaml": { "version": "3.14.1", @@ -7045,6 +7390,19 @@ "node": ">=8" } }, + "node_modules/jsesc": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/jsesc/-/jsesc-3.1.0.tgz", + "integrity": "sha512-/sM3dO2FOzXjKQhJuo0Q173wf2KOo8t4I8vHy6lF9poUp7bKT0/NHE8fPX23PwfhnykfqnC2xRxOnVw5XuGIaA==", + "dev": true, + "license": "MIT", + "bin": { + "jsesc": "bin/jsesc" + }, + "engines": { + "node": ">=6" + } + }, "node_modules/json-buffer": { "version": "3.0.1", "resolved": "https://registry.npmjs.org/json-buffer/-/json-buffer-3.0.1.tgz", @@ -8031,15 +8389,6 @@ "node": ">=16.14" } }, - "node_modules/magic-string": { - "version": "0.25.9", - "resolved": "https://registry.npmjs.org/magic-string/-/magic-string-0.25.9.tgz", - "integrity": "sha512-RmF0AsMzgt25qzqqLc1+MbHmhdx0ojF2Fvs4XnOqz2ZOBXzzkEwc/dJQZCYHAn7v1jbVOjAZfK8msRn4BxO4VQ==", - "dev": true, - "dependencies": { - "sourcemap-codec": "^1.4.8" - } - }, "node_modules/make-dir": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/make-dir/-/make-dir-4.0.0.tgz", @@ -9011,6 +9360,14 @@ "webidl-conversions": "^3.0.0" } }, + "node_modules/node-releases": { + "version": "2.0.19", + "resolved": "https://registry.npmjs.org/node-releases/-/node-releases-2.0.19.tgz", + "integrity": "sha512-xxOWJsBKtzAq7DY0J+DTzuz58K8e7sJbdgwkbMWQe8UYB6ekmsQ45q0M/tJDsGaZmbC+l7n57UV8Hl5tHxO9uw==", + "dev": true, + "license": "MIT", + "peer": true + }, "node_modules/normalize-package-data": { "version": "6.0.2", "resolved": "https://registry.npmjs.org/normalize-package-data/-/normalize-package-data-6.0.2.tgz", @@ -12202,20 +12559,12 @@ "dev": true, "license": "MIT" }, - "node_modules/perf-regexes": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/perf-regexes/-/perf-regexes-1.0.1.tgz", - "integrity": "sha512-L7MXxUDtqr4PUaLFCDCXBfGV/6KLIuSEccizDI7JxT+c9x1G1v04BQ4+4oag84SHaCdrBgQAIs/Cqn+flwFPng==", - "dev": true, - "engines": { - "node": ">=6.14" - } - }, "node_modules/picocolors": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/picocolors/-/picocolors-1.0.1.tgz", - "integrity": "sha512-anP1Z8qwhkbmu7MFP5iTt+wQKXgwzf7zTyGlcdzabySa9vd0Xt392U0rVmz9poOaBj0uHJKyyo9/upk0HrEQew==", - "dev": true + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/picocolors/-/picocolors-1.1.1.tgz", + "integrity": "sha512-xceH2snhtb5M9liqDsmEw56le376mTZkEX/jEb/RxNFyegNul7eNslCXP9FDj/Lcu0X8KEyMceP2ntpaHrDEVA==", + "dev": true, + "license": "ISC" }, "node_modules/picomatch": { "version": "2.3.1", @@ -13054,22 +13403,6 @@ "rollup": ">=1.26.0" } }, - "node_modules/rollup-plugin-cleanup": { - "version": "3.2.1", - "resolved": "https://registry.npmjs.org/rollup-plugin-cleanup/-/rollup-plugin-cleanup-3.2.1.tgz", - "integrity": "sha512-zuv8EhoO3TpnrU8MX8W7YxSbO4gmOR0ny06Lm3nkFfq0IVKdBUtHwhVzY1OAJyNCIAdLiyPnOrU0KnO0Fri1GQ==", - "dev": true, - "dependencies": { - "js-cleanup": "^1.2.0", - "rollup-pluginutils": "^2.8.2" - }, - "engines": { - "node": "^10.14.2 || >=12.0.0" - }, - "peerDependencies": { - "rollup": ">=2.0" - } - }, "node_modules/rollup-plugin-eslint-bundle": { "version": "9.0.0", "resolved": "https://registry.npmjs.org/rollup-plugin-eslint-bundle/-/rollup-plugin-eslint-bundle-9.0.0.tgz", @@ -13096,21 +13429,6 @@ "@jridgewell/sourcemap-codec": "^1.4.15" } }, - "node_modules/rollup-pluginutils": { - "version": "2.8.2", - "resolved": "https://registry.npmjs.org/rollup-pluginutils/-/rollup-pluginutils-2.8.2.tgz", - "integrity": "sha512-EEp9NhnUkwY8aif6bxgovPHMoMoNr2FulJziTndpt5H9RdwC47GSGuII9XxpSdzVGM0GWrNPHV6ie1LTNJPaLQ==", - "dev": true, - "dependencies": { - "estree-walker": "^0.6.1" - } - }, - "node_modules/rollup-pluginutils/node_modules/estree-walker": { - "version": "0.6.1", - "resolved": "https://registry.npmjs.org/estree-walker/-/estree-walker-0.6.1.tgz", - "integrity": "sha512-SqmZANLWS0mnatqbSfRP5g8OXZC12Fgg1IwNtLsyHDzJizORW4khDfjPqJZsemPWBB2uqykUah5YpQ6epsqC/w==", - "dev": true - }, "node_modules/run-parallel": { "version": "1.2.0", "resolved": "https://registry.npmjs.org/run-parallel/-/run-parallel-1.2.0.tgz", @@ -13748,15 +14066,6 @@ "node": ">=8" } }, - "node_modules/skip-regex": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/skip-regex/-/skip-regex-1.0.2.tgz", - "integrity": "sha512-pEjMUbwJ5Pl/6Vn6FsamXHXItJXSRftcibixDmNCWbWhic0hzHrwkMZo0IZ7fMRH9KxcWDFSkzhccB4285PutA==", - "dev": true, - "engines": { - "node": ">=4.2" - } - }, "node_modules/slackify-markdown": { "version": "4.4.0", "resolved": "https://registry.npmjs.org/slackify-markdown/-/slackify-markdown-4.4.0.tgz", @@ -13901,13 +14210,6 @@ "node": ">= 8" } }, - "node_modules/sourcemap-codec": { - "version": "1.4.8", - "resolved": "https://registry.npmjs.org/sourcemap-codec/-/sourcemap-codec-1.4.8.tgz", - "integrity": "sha512-9NykojV5Uih4lgo5So5dtw+f0JgJX30KCNI8gwhz2J9A15wD0Ml6tjHKwf6fTSa6fAdVBdZeNOs9eJ71qCk8vA==", - "deprecated": "Please use @jridgewell/sourcemap-codec instead", - "dev": true - }, "node_modules/spawn-error-forwarder": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/spawn-error-forwarder/-/spawn-error-forwarder-1.0.0.tgz", @@ -14983,6 +15285,38 @@ "node": ">= 0.8" } }, + "node_modules/update-browserslist-db": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/update-browserslist-db/-/update-browserslist-db-1.1.2.tgz", + "integrity": "sha512-PPypAm5qvlD7XMZC3BujecnaOxwhrtoFR+Dqkk5Aa/6DssiH0ibKoketaj9w8LP7Bont1rYeoV5plxD7RTEPRg==", + "dev": true, + "funding": [ + { + "type": "opencollective", + "url": "https://opencollective.com/browserslist" + }, + { + "type": "tidelift", + "url": "https://tidelift.com/funding/github/npm/browserslist" + }, + { + "type": "github", + "url": "https://github.com/sponsors/ai" + } + ], + "license": "MIT", + "peer": true, + "dependencies": { + "escalade": "^3.2.0", + "picocolors": "^1.1.1" + }, + "bin": { + "update-browserslist-db": "cli.js" + }, + "peerDependencies": { + "browserslist": ">= 4.21.0" + } + }, "node_modules/uri-js": { "version": "4.4.1", "resolved": "https://registry.npmjs.org/uri-js/-/uri-js-4.4.1.tgz", @@ -15417,6 +15751,14 @@ "node": ">=10" } }, + "node_modules/yallist": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/yallist/-/yallist-3.1.1.tgz", + "integrity": "sha512-a4UGQaWPH59mOXUYnAG2ewncQS4i4F43Tv3JoAM+s2VDAmS9NsK8GpDMLrCHPksFT7h3K6TOoUNn2pb7RoXx4g==", + "dev": true, + "license": "ISC", + "peer": true + }, "node_modules/yaml": { "version": "2.6.1", "resolved": "https://registry.npmjs.org/yaml/-/yaml-2.6.1.tgz", diff --git a/package.json b/package.json index 714d8d6..37656d7 100644 --- a/package.json +++ b/package.json @@ -36,6 +36,7 @@ "@adobe/eslint-config-helix": "2.0.8", "@adobe/helix-rum-js": "2.10.0", "@esm-bundle/chai": "4.3.4-fix.0", + "@rollup/plugin-babel": "6.0.4", "@semantic-release/changelog": "6.0.3", "@semantic-release/git": "10.0.1", "@semantic-release/npm": "12.0.1", @@ -56,7 +57,6 @@ "mocha-multi-reporters": "1.5.1", "rollup": "4.30.1", "rollup-plugin-checksum": "1.0.1", - "rollup-plugin-cleanup": "3.2.1", "rollup-plugin-eslint-bundle": "9.0.0", "semantic-release": "24.2.1", "semantic-release-slack-bot": "^4.0.2", diff --git a/rollup.config.js b/rollup.config.js index fcd998e..7bf5d2a 100644 --- a/rollup.config.js +++ b/rollup.config.js @@ -10,7 +10,8 @@ * governing permissions and limitations under the License. */ -import cleanup from 'rollup-plugin-cleanup'; +// eslint-disable-next-line import/no-extraneous-dependencies +import { babel } from '@rollup/plugin-babel'; import pkg from 'rollup-plugin-checksum'; const checksum = pkg.default; @@ -59,9 +60,9 @@ export default [...bundles.map(({ outputFile, source }) => ({ }, ], plugins: [ - cleanup({ - comments: [], - maxEmptyLines: 0, + babel({ + babelHelpers: 'bundled', + comments: false, }), checksum({ filename: `${outputFile.split('/').pop()}.md5`, From 7d89e9f664686d3a475ce829d7fb4f68f29ed71b Mon Sep 17 00:00:00 2001 From: Julien Ramboz Date: Thu, 16 Jan 2025 10:29:39 -0800 Subject: [PATCH 11/42] feat: inline web-vitals.js --- plugins/cwv.js | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/plugins/cwv.js b/plugins/cwv.js index d4442c0..ac20b50 100644 --- a/plugins/cwv.js +++ b/plugins/cwv.js @@ -9,6 +9,10 @@ * OF ANY KIND, either express or implied. See the License for the specific language * governing permissions and limitations under the License. */ +// eslint-disable-next-line max-len +// eslint-disable-next-line import/no-extraneous-dependencies, import/no-relative-packages, no-unused-vars +import * as webVitals from '../node_modules/web-vitals/dist/web-vitals.iife.js'; + export default function addCWVTracking({ sampleRUM, sourceSelector, targetSelector, fflags, }) { From 93b4537bd79b5feb4007d0007e78f5097bd4f1b4 Mon Sep 17 00:00:00 2001 From: Julien Ramboz Date: Thu, 16 Jan 2025 10:54:22 -0800 Subject: [PATCH 12/42] chore: update file size limit to 15KB --- modules/index.js | 34 ++++++++++++---------------------- test/it/size.test.html | 2 +- 2 files changed, 13 insertions(+), 23 deletions(-) diff --git a/modules/index.js b/modules/index.js index 748ba95..974d644 100644 --- a/modules/index.js +++ b/modules/index.js @@ -22,27 +22,23 @@ const { sampleRUM, queue, isSelected } = (window.hlx && window.hlx.rum) ? window const createMO = (cb) => (window.MutationObserver ? new MutationObserver(cb) /* c8 ignore next */ : {}); -// blocks mutation observer +// blocks & media mutation observer // eslint-disable-next-line no-use-before-define -const blocksMO = createMO(blocksMCB); - -// media mutation observer -// eslint-disable-next-line no-use-before-define -const mediaMO = createMO(mediaMCB); +const [blocksMO, mediaMO] = [blocksMCB, mediaMCB].map(createMO); // Check for the presence of a given cookie -const hasCookieKey = (key) => () => document.cookie.split(';').map((c) => c.trim()).some((cookie) => cookie.startsWith(`${key}=`)); +const hasCookieKey = (key) => () => document.cookie.split(';').some((c) => c.trim().startsWith(`${key}=`)); const pluginBasePath = '../plugins'; const PLUGINS = { cwv: `${pluginBasePath}/cwv.js`, // Interactive elements - form: { url: `${pluginBasePath}/form.js`, condition: () => document.body.querySelector('form'), isBlockDependent: true }, - video: { url: `${pluginBasePath}/video.js`, condition: () => document.body.querySelector('video'), isBlockDependent: true }, + form: { url: `${pluginBasePath}/form.js`, condition: () => document.querySelector('form'), isBlockDependent: true }, + video: { url: `${pluginBasePath}/video.js`, condition: () => document.querySelector('video'), isBlockDependent: true }, // Martech - martech: { url: `${pluginBasePath}/martech.js`, condition: ({ urlParameters }) => [...urlParameters.keys()].length > 0 }, - onetrust: { url: `${pluginBasePath}/onetrust.js`, condition: () => (document.body.querySelector('body > div#onetrust-consent-sdk') || hasCookieKey('OptanonAlertBoxClosed')), isBlockDependent: true }, + martech: { url: `${pluginBasePath}/martech.js`, condition: ({ urlParameters }) => urlParameters.size > 0 }, + onetrust: { url: `${pluginBasePath}/onetrust.js`, condition: () => (document.querySelector('#onetrust-consent-sdk') || hasCookieKey('OptanonAlertBoxClosed')), isBlockDependent: true }, }; const PLUGIN_PARAMETERS = { @@ -55,9 +51,8 @@ const PLUGIN_PARAMETERS = { const pluginCache = new Map(); -async function loadPlugin(key, params) { +function loadPlugin(key, params) { const plugin = PLUGINS[key]; - if (!plugin) return null; const usp = new URLSearchParams(window.location.search); if (!pluginCache.has(key) && plugin.condition && !plugin.condition({ urlParameters: usp })) { return null; @@ -74,15 +69,10 @@ async function loadPlugin(key, params) { .then((p) => (p.default && p.default(params)) || (typeof p === 'function' && p(params))); } -async function loadPlugins(filter = () => true, params = PLUGIN_PARAMETERS) { - return Promise.all( - Object.entries(PLUGINS) - .filter(([, plugin]) => filter(plugin)) - .map(([key]) => loadPlugin(key, params)), - ).catch((err) => { - // eslint-disable-next-line no-console - console.error('Failed to load plugins', err.message); - }); +function loadPlugins(filter = () => true, params = PLUGIN_PARAMETERS) { + Object.entries(PLUGINS) + .filter(([, plugin]) => filter(plugin)) + .map(([key]) => loadPlugin(key, params)); } function trackCheckpoint(checkpoint, data, t) { diff --git a/test/it/size.test.html b/test/it/size.test.html index 756de96..cda996d 100644 --- a/test/it/size.test.html +++ b/test/it/size.test.html @@ -62,7 +62,7 @@ setTimeout(resolve, 1000); }); expect(transferSize).to.be.greaterThan(0, 'the file should not be empty'); - expect(transferSize).to.be.lessThan(17 * 1024, 'we limit the size of the file to 17KB'); + expect(transferSize).to.be.lessThan(15 * 1024, 'we limit the size of the file to 15KB'); }); From c73eb31461115529922b82c3a8b678f21052b918 Mon Sep 17 00:00:00 2001 From: Julien Ramboz Date: Thu, 16 Jan 2025 12:59:45 -0800 Subject: [PATCH 13/42] fix: use proper fully qualified URLs for plugin path to avoid CORS --- modules/index.js | 2 +- web-test-runner.config.js | 11 ++++++++++- 2 files changed, 11 insertions(+), 2 deletions(-) diff --git a/modules/index.js b/modules/index.js index 974d644..fcf9d71 100644 --- a/modules/index.js +++ b/modules/index.js @@ -29,7 +29,7 @@ const [blocksMO, mediaMO] = [blocksMCB, mediaMCB].map(createMO); // Check for the presence of a given cookie const hasCookieKey = (key) => () => document.cookie.split(';').some((c) => c.trim().startsWith(`${key}=`)); -const pluginBasePath = '../plugins'; +const pluginBasePath = new URL(document.currentScript.src).href.replace(/index\.(map\.)js/, 'plugins'); const PLUGINS = { cwv: `${pluginBasePath}/cwv.js`, diff --git a/web-test-runner.config.js b/web-test-runner.config.js index 1d177b5..74f5b7e 100644 --- a/web-test-runner.config.js +++ b/web-test-runner.config.js @@ -35,7 +35,16 @@ export default { if (context.url.startsWith('/src/index.map.js')) { await next(); context.body = context.body - .replace(/navigator\.sendBeacon/g, 'fakeSendBeacon'); + .replace(/navigator\.sendBeacon/g, 'fakeSendBeacon') + // rewriting dynamic plugins base url + .replace(/document\.currentScript\.src/g, '"http://localhost:8000/plugins"'); + return true; + } else if (context.url.startsWith('/src/index.js') + || context.url.startsWith('/modules/index.js')) { + await next(); + context.body = context.body + // rewriting dynamic plugins base url + .replace(/document\.currentScript\.src/g, '"http://localhost:8000/plugins"'); return true; } else if (context.url.startsWith('/.rum')) { if (context.url.startsWith('/.rum/@adobe/helix-rum-js@%5E2/dist/') From f77d736a5e52b6e01fb83defe74b5e0f9622c127 Mon Sep 17 00:00:00 2001 From: Julien Ramboz Date: Thu, 16 Jan 2025 13:09:35 -0800 Subject: [PATCH 14/42] fix: plugin path resolution --- modules/index.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/modules/index.js b/modules/index.js index fcf9d71..25bacdb 100644 --- a/modules/index.js +++ b/modules/index.js @@ -29,7 +29,7 @@ const [blocksMO, mediaMO] = [blocksMCB, mediaMCB].map(createMO); // Check for the presence of a given cookie const hasCookieKey = (key) => () => document.cookie.split(';').some((c) => c.trim().startsWith(`${key}=`)); -const pluginBasePath = new URL(document.currentScript.src).href.replace(/index\.(map\.)js/, 'plugins'); +const pluginBasePath = new URL(document.currentScript.src).href.replace(/index(\.map)?\.js/, 'plugins'); const PLUGINS = { cwv: `${pluginBasePath}/cwv.js`, From 8964f80e28d32e0bb75c0174f38c2560067d7826 Mon Sep 17 00:00:00 2001 From: Julien Ramboz Date: Thu, 16 Jan 2025 13:49:21 -0800 Subject: [PATCH 15/42] test: ignore code coverage for error handler --- modules/index.js | 12 +++++++----- 1 file changed, 7 insertions(+), 5 deletions(-) diff --git a/modules/index.js b/modules/index.js index 25bacdb..40d39cf 100644 --- a/modules/index.js +++ b/modules/index.js @@ -29,16 +29,17 @@ const [blocksMO, mediaMO] = [blocksMCB, mediaMCB].map(createMO); // Check for the presence of a given cookie const hasCookieKey = (key) => () => document.cookie.split(';').some((c) => c.trim().startsWith(`${key}=`)); +// Set the base path for the plugins const pluginBasePath = new URL(document.currentScript.src).href.replace(/index(\.map)?\.js/, 'plugins'); const PLUGINS = { cwv: `${pluginBasePath}/cwv.js`, // Interactive elements - form: { url: `${pluginBasePath}/form.js`, condition: () => document.querySelector('form'), isBlockDependent: true }, - video: { url: `${pluginBasePath}/video.js`, condition: () => document.querySelector('video'), isBlockDependent: true }, + form: { url: `${pluginBasePath}/form.js`, when: () => document.querySelector('form'), isBlockDependent: true }, + video: { url: `${pluginBasePath}/video.js`, when: () => document.querySelector('video'), isBlockDependent: true }, // Martech - martech: { url: `${pluginBasePath}/martech.js`, condition: ({ urlParameters }) => urlParameters.size > 0 }, - onetrust: { url: `${pluginBasePath}/onetrust.js`, condition: () => (document.querySelector('#onetrust-consent-sdk') || hasCookieKey('OptanonAlertBoxClosed')), isBlockDependent: true }, + martech: { url: `${pluginBasePath}/martech.js`, when: ({ urlParameters }) => urlParameters.size > 0 }, + onetrust: { url: `${pluginBasePath}/onetrust.js`, when: () => (document.querySelector('#onetrust-consent-sdk') || hasCookieKey('OptanonAlertBoxClosed')), isBlockDependent: true }, }; const PLUGIN_PARAMETERS = { @@ -54,12 +55,13 @@ const pluginCache = new Map(); function loadPlugin(key, params) { const plugin = PLUGINS[key]; const usp = new URLSearchParams(window.location.search); - if (!pluginCache.has(key) && plugin.condition && !plugin.condition({ urlParameters: usp })) { + if (!pluginCache.has(key) && plugin.when && !plugin.when({ urlParameters: usp })) { return null; } if (!pluginCache.has(key)) { try { pluginCache.set(key, import(`${plugin.url || plugin}`)); + /* c8 ignore next 3 */ } catch (e) { return null; } From 8ee7b04585994c7edc30a6cf22e952a500ea9505 Mon Sep 17 00:00:00 2001 From: Julien Ramboz Date: Thu, 16 Jan 2025 14:52:22 -0800 Subject: [PATCH 16/42] test: add explicit test for broken plugin --- modules/index.js | 11 +++--- test/it/broken-plugin.test.html | 62 +++++++++++++++++++++++++++++++++ web-test-runner.config.js | 9 +++++ 3 files changed, 75 insertions(+), 7 deletions(-) create mode 100644 test/it/broken-plugin.test.html diff --git a/modules/index.js b/modules/index.js index 40d39cf..b830126 100644 --- a/modules/index.js +++ b/modules/index.js @@ -40,6 +40,7 @@ const PLUGINS = { // Martech martech: { url: `${pluginBasePath}/martech.js`, when: ({ urlParameters }) => urlParameters.size > 0 }, onetrust: { url: `${pluginBasePath}/onetrust.js`, when: () => (document.querySelector('#onetrust-consent-sdk') || hasCookieKey('OptanonAlertBoxClosed')), isBlockDependent: true }, + // test: broken-plugin }; const PLUGIN_PARAMETERS = { @@ -59,16 +60,12 @@ function loadPlugin(key, params) { return null; } if (!pluginCache.has(key)) { - try { - pluginCache.set(key, import(`${plugin.url || plugin}`)); - /* c8 ignore next 3 */ - } catch (e) { - return null; - } + pluginCache.set(key, import(`${plugin.url || plugin}`)); } const pluginLoadPromise = pluginCache.get(key); return pluginLoadPromise - .then((p) => (p.default && p.default(params)) || (typeof p === 'function' && p(params))); + .then((p) => (p.default && p.default(params)) || (typeof p === 'function' && p(params))) + .catch(() => { /* silent plugin error catching */ }); } function loadPlugins(filter = () => true, params = PLUGIN_PARAMETERS) { diff --git a/test/it/broken-plugin.test.html b/test/it/broken-plugin.test.html new file mode 100644 index 0000000..d70bde3 --- /dev/null +++ b/test/it/broken-plugin.test.html @@ -0,0 +1,62 @@ + + + + Test Runner + + + +

Some content

+ + + + \ No newline at end of file diff --git a/web-test-runner.config.js b/web-test-runner.config.js index 74f5b7e..9352fed 100644 --- a/web-test-runner.config.js +++ b/web-test-runner.config.js @@ -46,6 +46,15 @@ export default { // rewriting dynamic plugins base url .replace(/document\.currentScript\.src/g, '"http://localhost:8000/plugins"'); return true; + } else if (context.url.startsWith('/modules/index-broken.js')) { + const [_, search] = context.url.split('?'); + context.url = `/modules/index.js?${search}`; + await next(); + context.body = context.body + // rewriting dynamic plugins base url + .replace(/document\.currentScript\.src/g, '"http://localhost:8000/plugins"') + .replace(/\/\/ test: broken-plugin/g, 'foo: "foo.js",'); + return true; } else if (context.url.startsWith('/.rum')) { if (context.url.startsWith('/.rum/@adobe/helix-rum-js@%5E2/dist/') || context.url.startsWith('/.rum/@adobe/helix-rum-js@^2/dist/') From 29e71382b44b1b229bb4fe930c517e642dadf764 Mon Sep 17 00:00:00 2001 From: Lars Trieloff Date: Wed, 9 Oct 2024 10:17:28 +0200 Subject: [PATCH 17/42] ci(release): enable prereleases on beta branch --- .github/workflows/main.yaml | 2 +- .releaserc.cjs | 2 +- package.json | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/.github/workflows/main.yaml b/.github/workflows/main.yaml index 69f82b8..bd41b31 100644 --- a/.github/workflows/main.yaml +++ b/.github/workflows/main.yaml @@ -34,7 +34,7 @@ jobs: name: Release runs-on: ubuntu-latest needs: test - if: github.ref == 'refs/heads/main' + if: github.ref == 'refs/heads/main' || github.ref == 'refs/heads/beta' steps: - uses: actions/checkout@v4 with: diff --git a/.releaserc.cjs b/.releaserc.cjs index b7eca54..c6106c3 100644 --- a/.releaserc.cjs +++ b/.releaserc.cjs @@ -29,5 +29,5 @@ module.exports = { slackChannel: "rum-explorers", }], ], - branches: ['main'], + branches: ['main', { name: 'beta', prerelease: true }], }; diff --git a/package.json b/package.json index 37656d7..48cccbb 100644 --- a/package.json +++ b/package.json @@ -14,7 +14,7 @@ "build-bundle": "rollup --config", "prepack": "npm run build-bundle", "semantic-release": "semantic-release", - "semantic-release-dry": "semantic-release --dry-run --branches $CI_BRANCH 1.x main", + "semantic-release-dry": "semantic-release --dry-run --branches $CI_BRANCH 1.x main beta", "prepare": "husky" }, "repository": { From 3181698ea202ebb389dd82ab35a8d206a82b2006 Mon Sep 17 00:00:00 2001 From: Alexandre Capt Date: Tue, 8 Oct 2024 11:26:57 +0200 Subject: [PATCH 18/42] feat: handle pre-rendering --- modules/index.js | 3 +++ 1 file changed, 3 insertions(+) diff --git a/modules/index.js b/modules/index.js index b830126..cf8b487 100644 --- a/modules/index.js +++ b/modules/index.js @@ -108,8 +108,11 @@ function addNavigationTracking() { const navigate = (source, type, redirectCount) => { // target can be 'visible', 'hidden' (background tab) or 'prerendered' (speculation rules) const payload = { source, target: document.visibilityState }; +<<<<<<< HEAD /* c8 ignore next 13 */ // prerendering cannot be tested yet with headless browsers +======= +>>>>>>> bb11187 (feat: handle pre-rendering) if (document.prerendering) { // listen for "activation" of the current pre-rendered page document.addEventListener('prerenderingchange', () => { From 9a9608b81be035149865d89e39a7ebf6b7766b51 Mon Sep 17 00:00:00 2001 From: semantic-release-bot Date: Wed, 9 Oct 2024 08:29:52 +0000 Subject: [PATCH 19/42] chore(release): 2.26.0-beta.1 [skip ci] * handle pre-rendering ([bb11187](https://github.com/adobe/helix-rum-enhancer/commit/bb11187058b8cb521a270c316323b66414a8d817)) --- modules/index.js | 3 --- 1 file changed, 3 deletions(-) diff --git a/modules/index.js b/modules/index.js index cf8b487..b830126 100644 --- a/modules/index.js +++ b/modules/index.js @@ -108,11 +108,8 @@ function addNavigationTracking() { const navigate = (source, type, redirectCount) => { // target can be 'visible', 'hidden' (background tab) or 'prerendered' (speculation rules) const payload = { source, target: document.visibilityState }; -<<<<<<< HEAD /* c8 ignore next 13 */ // prerendering cannot be tested yet with headless browsers -======= ->>>>>>> bb11187 (feat: handle pre-rendering) if (document.prerendering) { // listen for "activation" of the current pre-rendered page document.addEventListener('prerenderingchange', () => { From 08d993324172e9f091437bebfcb8401a945aa132 Mon Sep 17 00:00:00 2001 From: Lars Trieloff Date: Tue, 14 Jan 2025 09:08:39 -0800 Subject: [PATCH 20/42] refactor(fflags): more compact feature flags code --- modules/fflags.js | 12 +++++------- 1 file changed, 5 insertions(+), 7 deletions(-) diff --git a/modules/fflags.js b/modules/fflags.js index 1dfa36d..9ca2377 100644 --- a/modules/fflags.js +++ b/modules/fflags.js @@ -9,14 +9,12 @@ * OF ANY KIND, either express or implied. See the License for the specific language * governing permissions and limitations under the License. */ +const h = (s, a) => [...s].reduce((p, c) => p + c.charCodeAt(0), a) % 1371; + export const fflags = { - has: (flag) => fflags[flag].indexOf(Array.from(window.origin) - .map((a) => a.charCodeAt(0)) - .reduce((a, b) => a + b, 1) % 1371) !== -1 - || !!window.origin.match(/localhost/), - enabled: (flag, callback) => fflags.has(flag) && callback(), - /* c8 ignore next */ - disabled: (flag, callback) => !fflags.has(flag) && callback(), + has: (f) => fflags[f].includes(h(window.origin, 1)) || /localhost/.test(window.origin), + enabled: (f, c) => fflags.has(f) && c(), + disabled: (f, c) => !fflags.has(f) && c(), eagercwv: [683], redirect: [620, 1139], example: [543, 770, 1136], From b2e0b5ded065b0e2cdc3cbe1d68dd53771bee37f Mon Sep 17 00:00:00 2001 From: vdua Date: Tue, 14 Jan 2025 09:04:51 -0800 Subject: [PATCH 21/42] fixing coverage report --- web-test-runner.config.js | 1 - 1 file changed, 1 deletion(-) diff --git a/web-test-runner.config.js b/web-test-runner.config.js index 9352fed..cbcb6ee 100644 --- a/web-test-runner.config.js +++ b/web-test-runner.config.js @@ -23,7 +23,6 @@ export default { 'test/fixtures/**', 'node_modules/**', '.rum/**', - 'src/**', ], }, files: [ From ab954d74a2aa44c91c2f0054624aad121970cb0a Mon Sep 17 00:00:00 2001 From: vdua Date: Tue, 14 Jan 2025 09:44:20 -0800 Subject: [PATCH 22/42] tests: removing only src/index.js from instrumentation to get the proper coverage report --- web-test-runner.config.js | 1 + 1 file changed, 1 insertion(+) diff --git a/web-test-runner.config.js b/web-test-runner.config.js index cbcb6ee..4542c1c 100644 --- a/web-test-runner.config.js +++ b/web-test-runner.config.js @@ -23,6 +23,7 @@ export default { 'test/fixtures/**', 'node_modules/**', '.rum/**', + 'src/index.js', ], }, files: [ From 351876c5b77591828df2385066f6eebabcd5a3cf Mon Sep 17 00:00:00 2001 From: Lars Trieloff Date: Tue, 14 Jan 2025 10:22:19 -0800 Subject: [PATCH 23/42] ci(github): report test results in github, pretty --- .github/workflows/main.yaml | 7 +++++++ package-lock.json | 34 ++++++++++++++++++++++++++++++++++ package.json | 1 + web-test-runner.config.js | 10 ++++++++++ 4 files changed, 52 insertions(+) diff --git a/.github/workflows/main.yaml b/.github/workflows/main.yaml index bd41b31..3dd7e45 100644 --- a/.github/workflows/main.yaml +++ b/.github/workflows/main.yaml @@ -19,6 +19,13 @@ jobs: node-version: '20.x' - run: npm ci - run: npm run test:ci + - name: Test Report + uses: dorny/test-reporter@v1 + if: success() || failure() # run this step even if previous step failed + with: + name: Tests # Name of the check run which will be created + path: test-results.xml # Path to test results + reporter: junit # Format of test results - uses: codecov/codecov-action@v5 with: token: ${{ secrets.CODECOV_TOKEN }} diff --git a/package-lock.json b/package-lock.json index fb8598c..631d73c 100644 --- a/package-lock.json +++ b/package-lock.json @@ -18,6 +18,7 @@ "@semantic-release/npm": "12.0.1", "@web/test-runner": "0.19.0", "@web/test-runner-commands": "0.9.0", + "@web/test-runner-junit-reporter": "^0.7.2", "@web/test-runner-mocha": "0.9.0", "@web/test-runner-playwright": "0.11.0", "c8": "10.1.3", @@ -2360,6 +2361,22 @@ "node": ">=18.0.0" } }, + "node_modules/@web/test-runner-junit-reporter": { + "version": "0.7.2", + "resolved": "https://registry.npmjs.org/@web/test-runner-junit-reporter/-/test-runner-junit-reporter-0.7.2.tgz", + "integrity": "sha512-XMHgBCwaHxJDkGebI17EJEzk94Sgvcf2hrYkpHj7Zya2xcIL8g7cYVLYD024j5MKehfYTonNvhNYGOCiqzlp8g==", + "dev": true, + "license": "MIT", + "dependencies": { + "@web/test-runner-chrome": "^0.17.0", + "@web/test-runner-core": "^0.13.0", + "array-flat-polyfill": "^1.0.1", + "xml": "^1.0.1" + }, + "engines": { + "node": ">=18.0.0" + } + }, "node_modules/@web/test-runner-mocha": { "version": "0.9.0", "resolved": "https://registry.npmjs.org/@web/test-runner-mocha/-/test-runner-mocha-0.9.0.tgz", @@ -2588,6 +2605,16 @@ "url": "https://github.com/sponsors/ljharb" } }, + "node_modules/array-flat-polyfill": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/array-flat-polyfill/-/array-flat-polyfill-1.0.1.tgz", + "integrity": "sha512-hfJmKupmQN0lwi0xG6FQ5U8Rd97RnIERplymOv/qpq8AoNKPPAnxJadjFA23FNWm88wykh9HmpLJUUwUtNU/iw==", + "dev": true, + "license": "CC0-1.0", + "engines": { + "node": ">=6.0.0" + } + }, "node_modules/array-ify": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/array-ify/-/array-ify-1.0.0.tgz", @@ -15717,6 +15744,13 @@ } } }, + "node_modules/xml": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/xml/-/xml-1.0.1.tgz", + "integrity": "sha512-huCv9IH9Tcf95zuYCsQraZtWnJvBtLVE0QHMOs8bWyZAFZNDcYjsPq1nEx8jKA9y+Beo9v+7OBPRisQTjinQMw==", + "dev": true, + "license": "MIT" + }, "node_modules/xmlbuilder": { "version": "15.1.1", "resolved": "https://registry.npmjs.org/xmlbuilder/-/xmlbuilder-15.1.1.tgz", diff --git a/package.json b/package.json index 48cccbb..bf47ef8 100644 --- a/package.json +++ b/package.json @@ -42,6 +42,7 @@ "@semantic-release/npm": "12.0.1", "@web/test-runner": "0.19.0", "@web/test-runner-commands": "0.9.0", + "@web/test-runner-junit-reporter": "0.7.2", "@web/test-runner-mocha": "0.9.0", "@web/test-runner-playwright": "0.11.0", "c8": "10.1.3", diff --git a/web-test-runner.config.js b/web-test-runner.config.js index 4542c1c..1ea391f 100644 --- a/web-test-runner.config.js +++ b/web-test-runner.config.js @@ -9,7 +9,17 @@ * OF ANY KIND, either express or implied. See the License for the specific language * governing permissions and limitations under the License. */ + +// eslint-disable-next-line import/no-extraneous-dependencies +import { defaultReporter } from '@web/test-runner'; +// eslint-disable-next-line import/no-extraneous-dependencies +import { junitReporter } from '@web/test-runner-junit-reporter'; + export default { + reporters: [ + defaultReporter(), + junitReporter(), + ], testFramework: { type: 'mocha', config: { From 1f1fa8f09b540645f3b8df931f6044cb9a09d916 Mon Sep 17 00:00:00 2001 From: Lars Trieloff Date: Tue, 14 Jan 2025 10:26:39 -0800 Subject: [PATCH 24/42] ci(github): update test results reporter format to jest-junit --- .github/workflows/main.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/main.yaml b/.github/workflows/main.yaml index 3dd7e45..2bf5701 100644 --- a/.github/workflows/main.yaml +++ b/.github/workflows/main.yaml @@ -25,7 +25,7 @@ jobs: with: name: Tests # Name of the check run which will be created path: test-results.xml # Path to test results - reporter: junit # Format of test results + reporter: jest-junit # Format of test results - uses: codecov/codecov-action@v5 with: token: ${{ secrets.CODECOV_TOKEN }} From aacaf8d0e07dcb427e2acd960fd93bb26ac9f0bf Mon Sep 17 00:00:00 2001 From: Lars Trieloff Date: Tue, 14 Jan 2025 11:06:50 -0800 Subject: [PATCH 25/42] test: implement custom JSON test reporter --- .github/workflows/main.yaml | 4 +- .gitignore | 3 +- package.json | 7 +-- web-test-runner.config.js | 111 +++++++++++++++++++++++++++++++++++- 4 files changed, 115 insertions(+), 10 deletions(-) diff --git a/.github/workflows/main.yaml b/.github/workflows/main.yaml index 2bf5701..320c3b5 100644 --- a/.github/workflows/main.yaml +++ b/.github/workflows/main.yaml @@ -24,8 +24,8 @@ jobs: if: success() || failure() # run this step even if previous step failed with: name: Tests # Name of the check run which will be created - path: test-results.xml # Path to test results - reporter: jest-junit # Format of test results + path: test-results/test-results.json + reporter: mocha-json - uses: codecov/codecov-action@v5 with: token: ${{ secrets.CODECOV_TOKEN }} diff --git a/.gitignore b/.gitignore index 582005b..9109263 100644 --- a/.gitignore +++ b/.gitignore @@ -9,4 +9,5 @@ logs test-results.xml .env .idea -src \ No newline at end of file +src +test-results/test-results.json diff --git a/package.json b/package.json index bf47ef8..ca289c0 100644 --- a/package.json +++ b/package.json @@ -6,9 +6,9 @@ "type": "module", "scripts": { "setup-playwright": "npx playwright install --with-deps chromium firefox webkit", - "test": "npm run build-bundle && npm run setup-playwright && web-test-runner --node-resolve --coverage --playwright --browsers chromium firefox webkit", - "test:ci": "npm run build-bundle && npm run setup-playwright && web-test-runner --node-resolve --coverage --playwright --browsers chromium firefox webkit", - "test:watch": "npm run build-bundle && npm run setup-playwright && web-test-runner --node-resolve --playwright --coverage --watch", + "test": "npm run build-bundle && npm run setup-playwright && web-test-runner --config web-test-runner.config.js", + "test:ci": "npm run build-bundle && npm run setup-playwright && web-test-runner --config web-test-runner.config.js", + "test:watch": "npm run build-bundle && npm run setup-playwright && web-test-runner --config web-test-runner.config.js --watch", "lint": "eslint .", "docs": "npx jsdoc2md -c .jsdoc.json --files 'src/*.js' > docs/API.md", "build-bundle": "rollup --config", @@ -42,7 +42,6 @@ "@semantic-release/npm": "12.0.1", "@web/test-runner": "0.19.0", "@web/test-runner-commands": "0.9.0", - "@web/test-runner-junit-reporter": "0.7.2", "@web/test-runner-mocha": "0.9.0", "@web/test-runner-playwright": "0.11.0", "c8": "10.1.3", diff --git a/web-test-runner.config.js b/web-test-runner.config.js index 1ea391f..d2cfe2f 100644 --- a/web-test-runner.config.js +++ b/web-test-runner.config.js @@ -12,13 +12,118 @@ // eslint-disable-next-line import/no-extraneous-dependencies import { defaultReporter } from '@web/test-runner'; -// eslint-disable-next-line import/no-extraneous-dependencies -import { junitReporter } from '@web/test-runner-junit-reporter'; +import fs from 'fs'; + +function myReporter() { + let startTime; + + return { + start() { + startTime = Date.now(); + console.log('Test run started at:', new Date(startTime).toISOString()); + }, + + stop({ sessions }) { + console.log('\nTest run finished. Processing results...'); + console.log('Number of sessions:', sessions.length); + sessions.forEach((session, idx) => { + console.log(`\nSession ${idx + 1}:`, { + browser: session.browser?.name, + testFile: session.testFile, + passed: session.passed, + failed: session.failed, + skipped: session.skipped, + error: !!session.error, + }); + }); + + const endTime = Date.now(); + const results = { + stats: { + suites: sessions.length, + tests: 0, + passes: 0, + pending: 0, + failures: 0, + start: new Date(startTime).toISOString(), + end: new Date(endTime).toISOString(), + duration: endTime - startTime, + }, + tests: [], + }; + + sessions.forEach((session) => { + // Each session represents a test file + results.stats.tests += 1; + + if (session.passed) { + results.stats.passes += 1; + } else if (session.skipped) { + results.stats.pending += 1; + } else { + // If not passed and not skipped, it's a failure + results.stats.failures += 1; + } + + // Add the test result + const testName = session.testFile.split('/').pop().replace('.test.html', '').replace('.test.js', ''); + const error = session.error || (session.passed === false ? { + message: `Test failed in ${testName}`, + stack: `No stack trace available for ${testName}`, + } : null); + + results.tests.push({ + title: testName, + fullTitle: session.testFile, + file: session.testFile, + duration: session.duration || 0, + currentRetry: 0, + browser: session.browser?.name || 'unknown', + err: error, + skipped: session.skipped || false, + pending: session.skipped || false, + passed: session.passed || false, + }); + }); + + console.log('\nFinal stats:', results.stats); + console.log('Total test results:', results.tests.length); + + try { + if (!fs.existsSync('test-results')) { + console.log('Creating test-results directory...'); + fs.mkdirSync('test-results', { recursive: true }); + } + + const outputPath = 'test-results/test-results.json'; + fs.writeFileSync(outputPath, JSON.stringify(results, null, 2)); + console.log(`\nTest results written to ${outputPath}`); + + // Verify the file was created + if (fs.existsSync(outputPath)) { + const stats = fs.statSync(outputPath); + console.log(`File size: ${stats.size} bytes`); + } else { + console.error('Failed to create output file!'); + } + } catch (error) { + console.error('Error writing test results:', error); + } + }, + + onTestRunStarted() { }, + onTestRunFinished() { }, + reportTestFileResults() { }, + getTestProgress() { return ''; }, + }; +} export default { + nodeResolve: true, + coverage: true, reporters: [ defaultReporter(), - junitReporter(), + myReporter(), ], testFramework: { type: 'mocha', From be228fa8af3561f9f9ea2fdfd6db1698a8cb9702 Mon Sep 17 00:00:00 2001 From: Lars Trieloff Date: Tue, 14 Jan 2025 11:28:36 -0800 Subject: [PATCH 26/42] ci(github): use the test-summary action instead --- .github/workflows/main.yaml | 10 ++-- package.json | 7 ++- web-test-runner.config.js | 109 +----------------------------------- 3 files changed, 11 insertions(+), 115 deletions(-) diff --git a/.github/workflows/main.yaml b/.github/workflows/main.yaml index 320c3b5..e9cb979 100644 --- a/.github/workflows/main.yaml +++ b/.github/workflows/main.yaml @@ -19,13 +19,11 @@ jobs: node-version: '20.x' - run: npm ci - run: npm run test:ci - - name: Test Report - uses: dorny/test-reporter@v1 - if: success() || failure() # run this step even if previous step failed + - name: Test Summary + uses: test-summary/action@v2 with: - name: Tests # Name of the check run which will be created - path: test-results/test-results.json - reporter: mocha-json + paths: "test-results.xml" + if: always() - uses: codecov/codecov-action@v5 with: token: ${{ secrets.CODECOV_TOKEN }} diff --git a/package.json b/package.json index ca289c0..bf47ef8 100644 --- a/package.json +++ b/package.json @@ -6,9 +6,9 @@ "type": "module", "scripts": { "setup-playwright": "npx playwright install --with-deps chromium firefox webkit", - "test": "npm run build-bundle && npm run setup-playwright && web-test-runner --config web-test-runner.config.js", - "test:ci": "npm run build-bundle && npm run setup-playwright && web-test-runner --config web-test-runner.config.js", - "test:watch": "npm run build-bundle && npm run setup-playwright && web-test-runner --config web-test-runner.config.js --watch", + "test": "npm run build-bundle && npm run setup-playwright && web-test-runner --node-resolve --coverage --playwright --browsers chromium firefox webkit", + "test:ci": "npm run build-bundle && npm run setup-playwright && web-test-runner --node-resolve --coverage --playwright --browsers chromium firefox webkit", + "test:watch": "npm run build-bundle && npm run setup-playwright && web-test-runner --node-resolve --playwright --coverage --watch", "lint": "eslint .", "docs": "npx jsdoc2md -c .jsdoc.json --files 'src/*.js' > docs/API.md", "build-bundle": "rollup --config", @@ -42,6 +42,7 @@ "@semantic-release/npm": "12.0.1", "@web/test-runner": "0.19.0", "@web/test-runner-commands": "0.9.0", + "@web/test-runner-junit-reporter": "0.7.2", "@web/test-runner-mocha": "0.9.0", "@web/test-runner-playwright": "0.11.0", "c8": "10.1.3", diff --git a/web-test-runner.config.js b/web-test-runner.config.js index d2cfe2f..346645c 100644 --- a/web-test-runner.config.js +++ b/web-test-runner.config.js @@ -12,118 +12,15 @@ // eslint-disable-next-line import/no-extraneous-dependencies import { defaultReporter } from '@web/test-runner'; -import fs from 'fs'; - -function myReporter() { - let startTime; - - return { - start() { - startTime = Date.now(); - console.log('Test run started at:', new Date(startTime).toISOString()); - }, - - stop({ sessions }) { - console.log('\nTest run finished. Processing results...'); - console.log('Number of sessions:', sessions.length); - sessions.forEach((session, idx) => { - console.log(`\nSession ${idx + 1}:`, { - browser: session.browser?.name, - testFile: session.testFile, - passed: session.passed, - failed: session.failed, - skipped: session.skipped, - error: !!session.error, - }); - }); - - const endTime = Date.now(); - const results = { - stats: { - suites: sessions.length, - tests: 0, - passes: 0, - pending: 0, - failures: 0, - start: new Date(startTime).toISOString(), - end: new Date(endTime).toISOString(), - duration: endTime - startTime, - }, - tests: [], - }; - - sessions.forEach((session) => { - // Each session represents a test file - results.stats.tests += 1; - - if (session.passed) { - results.stats.passes += 1; - } else if (session.skipped) { - results.stats.pending += 1; - } else { - // If not passed and not skipped, it's a failure - results.stats.failures += 1; - } - - // Add the test result - const testName = session.testFile.split('/').pop().replace('.test.html', '').replace('.test.js', ''); - const error = session.error || (session.passed === false ? { - message: `Test failed in ${testName}`, - stack: `No stack trace available for ${testName}`, - } : null); - - results.tests.push({ - title: testName, - fullTitle: session.testFile, - file: session.testFile, - duration: session.duration || 0, - currentRetry: 0, - browser: session.browser?.name || 'unknown', - err: error, - skipped: session.skipped || false, - pending: session.skipped || false, - passed: session.passed || false, - }); - }); - - console.log('\nFinal stats:', results.stats); - console.log('Total test results:', results.tests.length); - - try { - if (!fs.existsSync('test-results')) { - console.log('Creating test-results directory...'); - fs.mkdirSync('test-results', { recursive: true }); - } - - const outputPath = 'test-results/test-results.json'; - fs.writeFileSync(outputPath, JSON.stringify(results, null, 2)); - console.log(`\nTest results written to ${outputPath}`); - - // Verify the file was created - if (fs.existsSync(outputPath)) { - const stats = fs.statSync(outputPath); - console.log(`File size: ${stats.size} bytes`); - } else { - console.error('Failed to create output file!'); - } - } catch (error) { - console.error('Error writing test results:', error); - } - }, - - onTestRunStarted() { }, - onTestRunFinished() { }, - reportTestFileResults() { }, - getTestProgress() { return ''; }, - }; -} +// eslint-disable-next-line import/no-extraneous-dependencies +import { junitReporter } from '@web/test-runner-junit-reporter'; export default { nodeResolve: true, coverage: true, reporters: [ defaultReporter(), - myReporter(), + junitReporter(), ], testFramework: { type: 'mocha', From a8fa936035f56b13ff8db66f32db17c828318972 Mon Sep 17 00:00:00 2001 From: Lars Trieloff Date: Mon, 13 Jan 2025 16:11:32 -0800 Subject: [PATCH 27/42] feat(loadresource): add `allresources` feature flag that enables tracking all resources, not just same host --- modules/fflags.js | 1 + modules/index.js | 2 +- 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/modules/fflags.js b/modules/fflags.js index 9ca2377..0bbe186 100644 --- a/modules/fflags.js +++ b/modules/fflags.js @@ -19,4 +19,5 @@ export const fflags = { redirect: [620, 1139], example: [543, 770, 1136], language: [543, 959, 1139, 620], + allresources: [1139], }; diff --git a/modules/index.js b/modules/index.js index b830126..aff373f 100644 --- a/modules/index.js +++ b/modules/index.js @@ -156,7 +156,7 @@ function addLoadResourceTracking() { try { list.getEntries() .filter((e) => !e.responseStatus || e.responseStatus < 400) - .filter((e) => window.location.hostname === new URL(e.name).hostname) + .filter((e) => window.location.hostname === new URL(e.name).hostname || fflags.has('allresources')) .filter((e) => new URL(e.name).pathname.match('.*(\\.plain\\.html$|\\.json|graphql|api)')) .forEach((e) => { sampleRUM('loadresource', { source: e.name, target: Math.round(e.duration) }); From f531f09dfe6892edd8c067eaee3084d67901dca2 Mon Sep 17 00:00:00 2001 From: semantic-release-bot Date: Wed, 15 Jan 2025 21:49:23 +0000 Subject: [PATCH 28/42] chore(release): 2.29.0 [skip ci] # [2.29.0](https://github.com/adobe/helix-rum-enhancer/compare/v2.28.0...v2.29.0) (2025-01-15) ### Features * **loadresource:** add `allresources` feature flag that enables tracking all resources, not just same host ([7c536d7](https://github.com/adobe/helix-rum-enhancer/commit/7c536d7b8ec77c40c4b9868dd3dff53c39529699)) --- CHANGELOG.md | 7 +++++++ package-lock.json | 4 ++-- package.json | 2 +- 3 files changed, 10 insertions(+), 3 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index b0c366a..a3301b1 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,10 @@ +# [2.29.0](https://github.com/adobe/helix-rum-enhancer/compare/v2.28.0...v2.29.0) (2025-01-15) + + +### Features + +* **loadresource:** add `allresources` feature flag that enables tracking all resources, not just same host ([7c536d7](https://github.com/adobe/helix-rum-enhancer/commit/7c536d7b8ec77c40c4b9868dd3dff53c39529699)) + # [2.28.0](https://github.com/adobe/helix-rum-enhancer/compare/v2.27.0...v2.28.0) (2025-01-02) diff --git a/package-lock.json b/package-lock.json index 631d73c..f63a5b2 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,12 +1,12 @@ { "name": "@adobe/helix-rum-enhancer", - "version": "2.28.0", + "version": "2.29.0", "lockfileVersion": 3, "requires": true, "packages": { "": { "name": "@adobe/helix-rum-enhancer", - "version": "2.28.0", + "version": "2.29.0", "license": "Apache-2.0", "devDependencies": { "@adobe/eslint-config-helix": "2.0.8", diff --git a/package.json b/package.json index bf47ef8..0a5b245 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "@adobe/helix-rum-enhancer", - "version": "2.28.0", + "version": "2.29.0", "description": "Helix RUM Enhancer", "main": "src/index.js", "type": "module", From e3ad482454e5fe874e5cef5842a08915c53dbad4 Mon Sep 17 00:00:00 2001 From: Lars Trieloff Date: Mon, 13 Jan 2025 16:07:36 -0800 Subject: [PATCH 29/42] feat(missingresource): report all resource error with http status code the target field was until now unused. this change uses it for the status code and in turn tracks all errored resources as `missingresource` --- modules/index.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/modules/index.js b/modules/index.js index aff373f..0c7eb0d 100644 --- a/modules/index.js +++ b/modules/index.js @@ -162,9 +162,9 @@ function addLoadResourceTracking() { sampleRUM('loadresource', { source: e.name, target: Math.round(e.duration) }); }); list.getEntries() - .filter((e) => e.responseStatus === 404) + .filter((e) => e.responseStatus >= 400) .forEach((e) => { - sampleRUM('missingresource', { source: e.name, target: e.hostname }); + sampleRUM('missingresource', { source: e.name, target: e.responseStatus }); }); /* c8 ignore next 3 */ } catch (error) { From 8bf19f452a4492e271038a6b7d4cc871761c24e0 Mon Sep 17 00:00:00 2001 From: semantic-release-bot Date: Wed, 15 Jan 2025 21:52:59 +0000 Subject: [PATCH 30/42] chore(release): 2.30.0 [skip ci] # [2.30.0](https://github.com/adobe/helix-rum-enhancer/compare/v2.29.0...v2.30.0) (2025-01-15) ### Features * **missingresource:** report all resource error with http status code ([e238136](https://github.com/adobe/helix-rum-enhancer/commit/e238136c46a9801be1e3ce7887c7b4b292cbcf5b)) --- CHANGELOG.md | 7 +++++++ package-lock.json | 4 ++-- package.json | 2 +- 3 files changed, 10 insertions(+), 3 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index a3301b1..092355e 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,10 @@ +# [2.30.0](https://github.com/adobe/helix-rum-enhancer/compare/v2.29.0...v2.30.0) (2025-01-15) + + +### Features + +* **missingresource:** report all resource error with http status code ([e238136](https://github.com/adobe/helix-rum-enhancer/commit/e238136c46a9801be1e3ce7887c7b4b292cbcf5b)) + # [2.29.0](https://github.com/adobe/helix-rum-enhancer/compare/v2.28.0...v2.29.0) (2025-01-15) diff --git a/package-lock.json b/package-lock.json index f63a5b2..bf598c8 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,12 +1,12 @@ { "name": "@adobe/helix-rum-enhancer", - "version": "2.29.0", + "version": "2.30.0", "lockfileVersion": 3, "requires": true, "packages": { "": { "name": "@adobe/helix-rum-enhancer", - "version": "2.29.0", + "version": "2.30.0", "license": "Apache-2.0", "devDependencies": { "@adobe/eslint-config-helix": "2.0.8", diff --git a/package.json b/package.json index 0a5b245..6ef5317 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "@adobe/helix-rum-enhancer", - "version": "2.29.0", + "version": "2.30.0", "description": "Helix RUM Enhancer", "main": "src/index.js", "type": "module", From f1bf66aff79f62b2d062e4c8dfdea7b039225608 Mon Sep 17 00:00:00 2001 From: Lars Trieloff Date: Thu, 16 Jan 2025 11:11:18 -0800 Subject: [PATCH 31/42] chore: align with main branch --- package-lock.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package-lock.json b/package-lock.json index bf598c8..730d5ce 100644 --- a/package-lock.json +++ b/package-lock.json @@ -18,7 +18,7 @@ "@semantic-release/npm": "12.0.1", "@web/test-runner": "0.19.0", "@web/test-runner-commands": "0.9.0", - "@web/test-runner-junit-reporter": "^0.7.2", + "@web/test-runner-junit-reporter": "0.7.2", "@web/test-runner-mocha": "0.9.0", "@web/test-runner-playwright": "0.11.0", "c8": "10.1.3", From b030130d44eac1b018aa2b327dab457d8a66e95a Mon Sep 17 00:00:00 2001 From: semantic-release-bot Date: Thu, 16 Jan 2025 19:14:48 +0000 Subject: [PATCH 32/42] chore(release): 2.31.0-beta.1 [skip ci] # [2.31.0-beta.1](https://github.com/adobe/helix-rum-enhancer/compare/v2.30.0...v2.31.0-beta.1) (2025-01-16) ### Features * handle pre-rendering ([bb11187](https://github.com/adobe/helix-rum-enhancer/commit/bb11187058b8cb521a270c316323b66414a8d817)) --- CHANGELOG.md | 7 +++++++ package-lock.json | 4 ++-- package.json | 2 +- 3 files changed, 10 insertions(+), 3 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 092355e..6667e9c 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,10 @@ +# [2.31.0-beta.1](https://github.com/adobe/helix-rum-enhancer/compare/v2.30.0...v2.31.0-beta.1) (2025-01-16) + + +### Features + +* handle pre-rendering ([bb11187](https://github.com/adobe/helix-rum-enhancer/commit/bb11187058b8cb521a270c316323b66414a8d817)) + # [2.30.0](https://github.com/adobe/helix-rum-enhancer/compare/v2.29.0...v2.30.0) (2025-01-15) diff --git a/package-lock.json b/package-lock.json index 730d5ce..5ef40e6 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,12 +1,12 @@ { "name": "@adobe/helix-rum-enhancer", - "version": "2.30.0", + "version": "2.31.0-beta.1", "lockfileVersion": 3, "requires": true, "packages": { "": { "name": "@adobe/helix-rum-enhancer", - "version": "2.30.0", + "version": "2.31.0-beta.1", "license": "Apache-2.0", "devDependencies": { "@adobe/eslint-config-helix": "2.0.8", diff --git a/package.json b/package.json index 6ef5317..08d20d7 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "@adobe/helix-rum-enhancer", - "version": "2.30.0", + "version": "2.31.0-beta.1", "description": "Helix RUM Enhancer", "main": "src/index.js", "type": "module", From 9603927774966fcfadb3ba3f8f7b42a0c003fd2e Mon Sep 17 00:00:00 2001 From: Lars Trieloff Date: Thu, 16 Jan 2025 11:22:27 -0800 Subject: [PATCH 33/42] Revert "feat: handle pre-rendering" This reverts commit bb11187058b8cb521a270c316323b66414a8d817. --- modules/index.js | 1 - 1 file changed, 1 deletion(-) diff --git a/modules/index.js b/modules/index.js index 0c7eb0d..a0b5edc 100644 --- a/modules/index.js +++ b/modules/index.js @@ -106,7 +106,6 @@ function processQueue() { function addNavigationTracking() { // enter checkpoint when referrer is not the current page url const navigate = (source, type, redirectCount) => { - // target can be 'visible', 'hidden' (background tab) or 'prerendered' (speculation rules) const payload = { source, target: document.visibilityState }; /* c8 ignore next 13 */ // prerendering cannot be tested yet with headless browsers From 179dd62ae6c0b54894032ad3e2c14bcdc9e82523 Mon Sep 17 00:00:00 2001 From: semantic-release-bot Date: Thu, 16 Jan 2025 19:25:15 +0000 Subject: [PATCH 34/42] chore(release): 2.31.0-beta.2 [skip ci] # [2.31.0-beta.2](https://github.com/adobe/helix-rum-enhancer/compare/v2.31.0-beta.1...v2.31.0-beta.2) (2025-01-16) ### Reverts * Revert "feat: handle pre-rendering" ([6471af5](https://github.com/adobe/helix-rum-enhancer/commit/6471af5cce4d895ca036a7b04a33530a3715b810)) --- CHANGELOG.md | 7 +++++++ package-lock.json | 4 ++-- package.json | 2 +- 3 files changed, 10 insertions(+), 3 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 6667e9c..516377c 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,10 @@ +# [2.31.0-beta.2](https://github.com/adobe/helix-rum-enhancer/compare/v2.31.0-beta.1...v2.31.0-beta.2) (2025-01-16) + + +### Reverts + +* Revert "feat: handle pre-rendering" ([6471af5](https://github.com/adobe/helix-rum-enhancer/commit/6471af5cce4d895ca036a7b04a33530a3715b810)) + # [2.31.0-beta.1](https://github.com/adobe/helix-rum-enhancer/compare/v2.30.0...v2.31.0-beta.1) (2025-01-16) diff --git a/package-lock.json b/package-lock.json index 5ef40e6..98a744d 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,12 +1,12 @@ { "name": "@adobe/helix-rum-enhancer", - "version": "2.31.0-beta.1", + "version": "2.31.0-beta.2", "lockfileVersion": 3, "requires": true, "packages": { "": { "name": "@adobe/helix-rum-enhancer", - "version": "2.31.0-beta.1", + "version": "2.31.0-beta.2", "license": "Apache-2.0", "devDependencies": { "@adobe/eslint-config-helix": "2.0.8", diff --git a/package.json b/package.json index 08d20d7..b50e32e 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "@adobe/helix-rum-enhancer", - "version": "2.31.0-beta.1", + "version": "2.31.0-beta.2", "description": "Helix RUM Enhancer", "main": "src/index.js", "type": "module", From bbae3e7499507358086072268d922b3aaf90b25a Mon Sep 17 00:00:00 2001 From: semantic-release-bot Date: Thu, 16 Jan 2025 21:05:34 +0000 Subject: [PATCH 35/42] chore(release): 2.31.0-beta.3 [skip ci] # [2.31.0-beta.3](https://github.com/adobe/helix-rum-enhancer/compare/v2.31.0-beta.2...v2.31.0-beta.3) (2025-01-16) ### Bug Fixes * bugs and failing tests ([5c9adbc](https://github.com/adobe/helix-rum-enhancer/commit/5c9adbc2502203495a05d4fd2be6e05cc11102df)) * cross-browser compatibility ([1c21afd](https://github.com/adobe/helix-rum-enhancer/commit/1c21afd8cd982d4c33feba863d2251311f36e153)) * set proper url base for plugins ([9726dc8](https://github.com/adobe/helix-rum-enhancer/commit/9726dc8f98bd71936c8a8f430cae73b6a8f5d63f)) * use proper fully qualified URLs for plugin path to avoid CORS ([c73eb31](https://github.com/adobe/helix-rum-enhancer/commit/c73eb31461115529922b82c3a8b678f21052b918)) ### Features * allow external extension via window.RUM_PLUGINS ([4613b00](https://github.com/adobe/helix-rum-enhancer/commit/4613b004c617f4d503355b5c43008149df9101ef)) * inline web-vitals.js ([7d89e9f](https://github.com/adobe/helix-rum-enhancer/commit/7d89e9f664686d3a475ce829d7fb4f68f29ed71b)) * introduce minimal plugin system to offset non-essenial logic ([8642557](https://github.com/adobe/helix-rum-enhancer/commit/8642557beaef5161d1d4d51d2b04ce06bf7dbeb7)) * introduce minimal plugin system to offset non-essenial logic ([6066f0b](https://github.com/adobe/helix-rum-enhancer/commit/6066f0bd56393a10391e190b9a338f9a65b772b0)) --- CHANGELOG.md | 18 ++++++++++++++++++ package-lock.json | 4 ++-- package.json | 2 +- 3 files changed, 21 insertions(+), 3 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 516377c..4719b08 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,21 @@ +# [2.31.0-beta.3](https://github.com/adobe/helix-rum-enhancer/compare/v2.31.0-beta.2...v2.31.0-beta.3) (2025-01-16) + + +### Bug Fixes + +* bugs and failing tests ([5c9adbc](https://github.com/adobe/helix-rum-enhancer/commit/5c9adbc2502203495a05d4fd2be6e05cc11102df)) +* cross-browser compatibility ([1c21afd](https://github.com/adobe/helix-rum-enhancer/commit/1c21afd8cd982d4c33feba863d2251311f36e153)) +* set proper url base for plugins ([9726dc8](https://github.com/adobe/helix-rum-enhancer/commit/9726dc8f98bd71936c8a8f430cae73b6a8f5d63f)) +* use proper fully qualified URLs for plugin path to avoid CORS ([c73eb31](https://github.com/adobe/helix-rum-enhancer/commit/c73eb31461115529922b82c3a8b678f21052b918)) + + +### Features + +* allow external extension via window.RUM_PLUGINS ([4613b00](https://github.com/adobe/helix-rum-enhancer/commit/4613b004c617f4d503355b5c43008149df9101ef)) +* inline web-vitals.js ([7d89e9f](https://github.com/adobe/helix-rum-enhancer/commit/7d89e9f664686d3a475ce829d7fb4f68f29ed71b)) +* introduce minimal plugin system to offset non-essenial logic ([8642557](https://github.com/adobe/helix-rum-enhancer/commit/8642557beaef5161d1d4d51d2b04ce06bf7dbeb7)) +* introduce minimal plugin system to offset non-essenial logic ([6066f0b](https://github.com/adobe/helix-rum-enhancer/commit/6066f0bd56393a10391e190b9a338f9a65b772b0)) + # [2.31.0-beta.2](https://github.com/adobe/helix-rum-enhancer/compare/v2.31.0-beta.1...v2.31.0-beta.2) (2025-01-16) diff --git a/package-lock.json b/package-lock.json index 98a744d..e4b203f 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,12 +1,12 @@ { "name": "@adobe/helix-rum-enhancer", - "version": "2.31.0-beta.2", + "version": "2.31.0-beta.3", "lockfileVersion": 3, "requires": true, "packages": { "": { "name": "@adobe/helix-rum-enhancer", - "version": "2.31.0-beta.2", + "version": "2.31.0-beta.3", "license": "Apache-2.0", "devDependencies": { "@adobe/eslint-config-helix": "2.0.8", diff --git a/package.json b/package.json index b50e32e..4d67d57 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "@adobe/helix-rum-enhancer", - "version": "2.31.0-beta.2", + "version": "2.31.0-beta.3", "description": "Helix RUM Enhancer", "main": "src/index.js", "type": "module", From 65ee6dca9543eea20a3f872bd74c672810bcb818 Mon Sep 17 00:00:00 2001 From: semantic-release-bot Date: Thu, 16 Jan 2025 21:13:18 +0000 Subject: [PATCH 36/42] chore(release): 2.31.0-beta.4 [skip ci] # [2.31.0-beta.4](https://github.com/adobe/helix-rum-enhancer/compare/v2.31.0-beta.3...v2.31.0-beta.4) (2025-01-16) ### Bug Fixes * plugin path resolution ([f464652](https://github.com/adobe/helix-rum-enhancer/commit/f464652df5bef5f42e0b32c1f10bebef013dd1b0)) --- CHANGELOG.md | 7 +++++++ package-lock.json | 4 ++-- package.json | 2 +- 3 files changed, 10 insertions(+), 3 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 4719b08..e399adb 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,10 @@ +# [2.31.0-beta.4](https://github.com/adobe/helix-rum-enhancer/compare/v2.31.0-beta.3...v2.31.0-beta.4) (2025-01-16) + + +### Bug Fixes + +* plugin path resolution ([f464652](https://github.com/adobe/helix-rum-enhancer/commit/f464652df5bef5f42e0b32c1f10bebef013dd1b0)) + # [2.31.0-beta.3](https://github.com/adobe/helix-rum-enhancer/compare/v2.31.0-beta.2...v2.31.0-beta.3) (2025-01-16) diff --git a/package-lock.json b/package-lock.json index e4b203f..a340b62 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,12 +1,12 @@ { "name": "@adobe/helix-rum-enhancer", - "version": "2.31.0-beta.3", + "version": "2.31.0-beta.4", "lockfileVersion": 3, "requires": true, "packages": { "": { "name": "@adobe/helix-rum-enhancer", - "version": "2.31.0-beta.3", + "version": "2.31.0-beta.4", "license": "Apache-2.0", "devDependencies": { "@adobe/eslint-config-helix": "2.0.8", diff --git a/package.json b/package.json index 4d67d57..c273db8 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "@adobe/helix-rum-enhancer", - "version": "2.31.0-beta.3", + "version": "2.31.0-beta.4", "description": "Helix RUM Enhancer", "main": "src/index.js", "type": "module", From 0a643d55440216adc5ca8b66e5cf70b31997b800 Mon Sep 17 00:00:00 2001 From: Julien Ramboz Date: Thu, 16 Jan 2025 17:04:39 -0800 Subject: [PATCH 37/42] fix: just forcing a release From 361afee186a32b25c6043303b24a422ff526ba56 Mon Sep 17 00:00:00 2001 From: semantic-release-bot Date: Fri, 17 Jan 2025 01:08:48 +0000 Subject: [PATCH 38/42] chore(release): 2.31.0-beta.5 [skip ci] # [2.31.0-beta.5](https://github.com/adobe/helix-rum-enhancer/compare/v2.31.0-beta.4...v2.31.0-beta.5) (2025-01-17) ### Bug Fixes * just forcing a release ([84ab687](https://github.com/adobe/helix-rum-enhancer/commit/84ab68734b5862816a532d4847df0ffa753b0717)) --- CHANGELOG.md | 7 +++++++ package-lock.json | 4 ++-- package.json | 2 +- 3 files changed, 10 insertions(+), 3 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index e399adb..b379f4e 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,10 @@ +# [2.31.0-beta.5](https://github.com/adobe/helix-rum-enhancer/compare/v2.31.0-beta.4...v2.31.0-beta.5) (2025-01-17) + + +### Bug Fixes + +* just forcing a release ([84ab687](https://github.com/adobe/helix-rum-enhancer/commit/84ab68734b5862816a532d4847df0ffa753b0717)) + # [2.31.0-beta.4](https://github.com/adobe/helix-rum-enhancer/compare/v2.31.0-beta.3...v2.31.0-beta.4) (2025-01-16) diff --git a/package-lock.json b/package-lock.json index a340b62..cc1269e 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,12 +1,12 @@ { "name": "@adobe/helix-rum-enhancer", - "version": "2.31.0-beta.4", + "version": "2.31.0-beta.5", "lockfileVersion": 3, "requires": true, "packages": { "": { "name": "@adobe/helix-rum-enhancer", - "version": "2.31.0-beta.4", + "version": "2.31.0-beta.5", "license": "Apache-2.0", "devDependencies": { "@adobe/eslint-config-helix": "2.0.8", diff --git a/package.json b/package.json index c273db8..b5db6dc 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "@adobe/helix-rum-enhancer", - "version": "2.31.0-beta.4", + "version": "2.31.0-beta.5", "description": "Helix RUM Enhancer", "main": "src/index.js", "type": "module", From dfc1eea7bf230d95456ee2f7ee200e6a37c2f8c3 Mon Sep 17 00:00:00 2001 From: Julien Ramboz Date: Thu, 16 Jan 2025 17:19:16 -0800 Subject: [PATCH 39/42] fix: plugins are not executing because they are exported as iife --- rollup.config.js | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/rollup.config.js b/rollup.config.js index 7bf5d2a..814290e 100644 --- a/rollup.config.js +++ b/rollup.config.js @@ -38,22 +38,23 @@ const bundles = [ ...['cwv', 'form', 'martech', 'onetrust', 'video'].map((plugin) => ({ source: `plugins/${plugin}.js`, outputFile: `src/plugins/${plugin}`, + format: 'es', })), ]; -export default [...bundles.map(({ outputFile, source }) => ({ +export default [...bundles.map(({ outputFile, source, format }) => ({ input: source, output: [ { file: `${outputFile}.map.js`, - format: 'iife', + format: format || 'iife', sourcemap: 'inline', exports: 'auto', banner, }, { file: `${outputFile}.js`, - format: 'iife', + format: format || 'iife', sourcemap: false, exports: 'auto', banner, From 10decef5f8d0ff392ce02e7b87e16083912ad248 Mon Sep 17 00:00:00 2001 From: Julien Ramboz Date: Thu, 16 Jan 2025 17:32:25 -0800 Subject: [PATCH 40/42] chore: cleanup PR --- .github/workflows/main.yaml | 2 +- .releaserc.cjs | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/workflows/main.yaml b/.github/workflows/main.yaml index e9cb979..7198279 100644 --- a/.github/workflows/main.yaml +++ b/.github/workflows/main.yaml @@ -39,7 +39,7 @@ jobs: name: Release runs-on: ubuntu-latest needs: test - if: github.ref == 'refs/heads/main' || github.ref == 'refs/heads/beta' + if: github.ref == 'refs/heads/main' steps: - uses: actions/checkout@v4 with: diff --git a/.releaserc.cjs b/.releaserc.cjs index c6106c3..b7eca54 100644 --- a/.releaserc.cjs +++ b/.releaserc.cjs @@ -29,5 +29,5 @@ module.exports = { slackChannel: "rum-explorers", }], ], - branches: ['main', { name: 'beta', prerelease: true }], + branches: ['main'], }; From f3a3385a1e6cb93644555854d6b2cd5b02ddd576 Mon Sep 17 00:00:00 2001 From: Julien Ramboz Date: Thu, 16 Jan 2025 17:33:06 -0800 Subject: [PATCH 41/42] chore: cleanup PR --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index 6ef5317..f15c21f 100644 --- a/package.json +++ b/package.json @@ -14,7 +14,7 @@ "build-bundle": "rollup --config", "prepack": "npm run build-bundle", "semantic-release": "semantic-release", - "semantic-release-dry": "semantic-release --dry-run --branches $CI_BRANCH 1.x main beta", + "semantic-release-dry": "semantic-release --dry-run --branches $CI_BRANCH 1.x main", "prepare": "husky" }, "repository": { From 2bb5f45a5422b482f9d7be192299fcc7c847778d Mon Sep 17 00:00:00 2001 From: Julien Ramboz Date: Fri, 17 Jan 2025 14:21:44 -0800 Subject: [PATCH 42/42] chore: ignore uncovered lines --- plugins/cwv.js | 1 + 1 file changed, 1 insertion(+) diff --git a/plugins/cwv.js b/plugins/cwv.js index ac20b50..1a22421 100644 --- a/plugins/cwv.js +++ b/plugins/cwv.js @@ -19,6 +19,7 @@ export default function addCWVTracking({ setTimeout(() => { try { const cwvScript = new URL('.rum/web-vitals/dist/web-vitals.iife.js', sampleRUM.baseURL).href; + /* c8 ignore next 3 */ if (document.querySelector(`script[src="${cwvScript}"]`)) { // web vitals script has been loaded already return;