Skip to content

Instantly share code, notes, and snippets.

@paulirish
Created January 25, 2023 22:44
Show Gist options
  • Star 6 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save paulirish/20e0b92bb704050070252dafcb550cfd to your computer and use it in GitHub Desktop.
Save paulirish/20e0b92bb704050070252dafcb550cfd to your computer and use it in GitHub Desktop.
Log all DOM mutations to console
// Log all DOM mutations to console.
// Modern interpretation of https://github.com/kdzwinel/DOMListenerExtension
observer = new MutationObserver(onMutation);
observerSettings = {
subtree: true,
childList: true,
attributes: true,
attributeOldValue: true,
characterData: true,
characterDataOldValue: true,
};
function onMutation(records) {
for (const record of records) {
if (record.type === 'childList') {
record.addedNodes.forEach(observeShadowRoots);
}
logMutation(record);
}
}
function logMutation(r) {
console.log(r.type, {el: r.target},
r.type === 'childList'
? Object.fromEntries(['addedNodes', 'removedNodes'].filter(key => r[key].length).map(key => ([key, r[key]])))
: r.type === 'attributes'
? [r.attributeName, r.oldValue, '➤', r.target.getAttribute(r.attributeName)]
: undefined,
{record: r},
);
}
function observeShadowRoots(node) {
findShadowRoots(node).forEach((shadowRoot) => {
observer.observe(shadowRoot, observerSettings);
});
}
function findShadowRoots(node, list = new Set()) {
if (node.shadowRoot) list.add(node.shadowRoot);
node?.querySelectorAll && node.querySelectorAll('*').forEach((child) => {
if (child.shadowRoot) findShadowRoots(child, list);
});
return list;
}
// console.clear();
observer.disconnect(); // call manually to stop logging
observer.observe(document, observerSettings);
observeShadowRoots(document);
@paulirish
Copy link
Author

Screenshot of its output:
image

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment