Нужен Code-Review: избавиться от всех вложенных shadow-root узлов и получить обычный HTML без shadow-root

Рейтинг: 0Ответов: 0Опубликовано: 07.08.2023

Сама задача вроде бы достаточно ясно описана в заголовке...

Вот что получилось у меня на данный момент:

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 можно как-то и это вытянуть, нет?

В общем буду благодарен если кто-нибудь сможет глянуть код и подсказать что можно улучшить или возможно я где-то сделал не так?

Спасибо!

Ответы

Ответов пока нет.