UNPKG

@funnelenvy-npm/fe-dev-utils

Version:

Helper function to build client side A/B tests

68 lines (60 loc) 3.06 kB
import onError from '../on-error'; /** * Executes a callback function when the URL changes in a single page application (SPA). * Uses a MutationObserver to observe changes to the document body and detect URL changes. * @param {Object} options - Options object to configure the function. * @param {function} options.callback - The callback function to execute when the URL changes. * @param {string} [options.activity] - (Optional) Name of the activity the function is being called from. * @param {function} [options.errorHandler] - (Optional) Function to call when execution encounters an error. */ type OnUrlChangeOptions = { callback: (oldHref: string | undefined, mutation: MutationRecord) => void; activity?: string; errorHandler?: ((params: { activity?: string; error: Error }) => void) | null; }; const onUrlChange = ({ callback, activity, errorHandler, }: OnUrlChangeOptions): void => { if (typeof callback !== 'function') { throw new Error('Callback function must be provided'); } const mutationConfig: MutationObserverInit = { childList: true, subtree: true }; // Create a new MutationObserver instance to observe changes to the document body const observer: MutationObserver & { previousUrl?: string } = new MutationObserver((mutationsList) => { mutationsList.forEach((mutation) => { // Store the current URL in a separate variable to make the code more concise const currentUrl = window.location.href; // Check if the URL has changed since the last observation if (observer.previousUrl !== currentUrl) { const oldHref = observer.previousUrl; // Update the previous URL and execute the callback function observer.previousUrl = currentUrl; // console.log('URL changed!'); observer.disconnect(); // Disconnect the observer to avoid triggering an infinite loop when making DOM changes in the callback function try { callback(oldHref, mutation); } catch (error) { console.log(`Error in callback function: ${error}`); } observer.observe(document.documentElement, mutationConfig); // Reconnect the observer to continue observing URL changes } }); }); // Initialize the previous URL to the current URL try { observer.previousUrl = window.location.href; // Start observing changes to the document documentElement to detect URL changes observer.observe(document.documentElement, mutationConfig); } catch (err) { // Validate that `err` is an Error or convert it to an Error const error = err instanceof Error ? err : new Error('Unknown error occurred'); if (errorHandler && typeof errorHandler === 'function') { errorHandler({ activity, error }); } else { onError({ activity, error }); } } }; export default onUrlChange;