Нужен Code-Review: избавиться от всех вложенных shadow-root узлов и получить обычный HTML без shadow-root
Сама задача вроде бы достаточно ясно описана в заголовке...
Вот что получилось у меня на данный момент:
const unShadow = () => {
const allNodes = Array.prototype.slice.call(document.querySelectorAll('*'));
let result = false;
let count = window.lastShadowID || 0;
allNodes.forEach(nodeFrom => {
const shadow = nodeFrom.shadowRoot;
if (shadow && shadow.mode == 'open') {
const subs = Array.prototype.slice.call(shadow.childNodes);
if (subs.length > 0) {
count++;
result = true;
let shadowFrom = nodeFrom.getAttribute('shadow-from');
if (!shadowFrom) {
shadowFrom = count;
nodeFrom.setAttribute('shadow-from', shadowFrom);
};
let nodeTo = document.querySelector(`[shadow-to="${shadowFrom}"]`);
if (!nodeTo) {
nodeTo = document.createElement(nodeFrom.nodeName);
if (nodeFrom.hasAttributes()) {
for (const attribute of nodeFrom.attributes) {
if (attribute.name == 'shadow-from')
continue;
nodeTo.setAttribute(attribute.name, attribute.value);
};
};
nodeTo.setAttribute('shadow-to', shadowFrom);
nodeFrom.parentNode.insertBefore(nodeTo, nodeFrom);
};
subs.forEach(sub => nodeTo.append(sub));
Array.prototype.slice.call(nodeFrom.childNodes).forEach(child => nodeTo.append(child));
nodeFrom.parentNode.removeChild(nodeFrom);
};
};
});
window.lastShadowID = count;
console.info('count', count);
return result;
};
const unShadowAll = () => {
let count = 0;
while (unShadow()) {
count++;
console.info('Итерация unShadow() завершена:', count);
};
console.info('Функция unShadowAll() завершена!');
};
unShadowAll();
На простых страницах, где етих shadow-root относительно мало - вроде бы всё работает и довольно шустро.
Но на странице с огромным количеством сильно вложенных shadow-root - страница внешне портится, сильно виснет. В случае если count доходит примерно до 4000+ страница грохается с "Недостаточно памяти". Выбивает странные ошибки, например:
Uncaught Error: Assertion failed
Uncaught TypeError: Cannot set properties of undefined (setting 'shadow')
Uncaught DOMException: Failed to execute 'removeChild' on 'Node': The node to be removed is not a child of this node.
(причём они идут из каких-то непонятных незнакомых путей StackTrace)
Может ругаться когда попадаются нестандартные nodeName у узлов. Вроде как shadowRoot понимает такой nodeName, а основной DOM пугается такого nodeName... Может из shadowRoot можно как-то и это вытянуть, нет?
В общем буду благодарен если кто-нибудь сможет глянуть код и подсказать что можно улучшить или возможно я где-то сделал не так?
Спасибо!