rrweb icon indicating copy to clipboard operation
rrweb copied to clipboard

[Bug]: Initial "fullSnapshot" does not include styles added via CSSStyleSheet / "adoptedStylesheets"

Open jluxenberg opened this issue 9 months ago • 0 comments

Preflight Checklist

  • [X] I have searched the issue tracker for a bug report that matches the one I want to file, without success.

What package is this bug report for?

rrweb

Version

2.0.0-alpha.18

Expected Behavior

  • The initial "fullSnapshot" frame includes styles which are synchronously added via Javascript

Actual Behavior

  • The initial "fullSnapshot" frame does NOT include styles added via creation of a new CSSStyleSheet(); added to the DOM via document.adoptedStyleSheets

Steps to Reproduce

Issue:

The Initial "fullSnapshot" in a recording does not include styles added via CSSStyleSheet / "adoptedStylesheets".

Styles added via direct DOM manipulation (e.g. "elem.style.border = ...") and via document.createElement("<style>") "work" in the sense that the initial "fullSnapshot" includes those styles.

This is a bug because the un-styled frame is never painted by the browser, but the replay includes this unstyled initial "fullSnapshot."

To reproduce:

Copy this into an HTML file and then open it, and look at the DevTools console log (or download this gist):

<html>

<head>
    <link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/rrweb@latest/dist/style.css" />

    <script type="module">
        import { record } from 'https://cdn.jsdelivr.net/npm/[email protected]/+esm';
        window.events = [];

        record({
            emit(event) {
                // store the event in any way you like
                window.events.push(event);
            },
        });

        setTimeout(() => {
            const initialFrame = window.events.find(e => e.type === 2);
            const success = JSON.stringify(initialFrame).includes("lightgrey");
            if (success) {
                console.log("TEST PASSED: initial frame has our styles");
            } else {
                console.error("TEST FAILED: initial frame does not have our styles");
                const eventIdx = window.events.findIndex(e => JSON.stringify(e).includes("lightgrey"))
                console.log(`\t however; window.events[${eventIdx}] does have our styles`, window.events[eventIdx]);
            }
        }, 1500)
    </script>
</head>

<body>
    <div id="content">
        <h1>test</h1>
        <p>some text</p>
    </div>

    <script>
        // three ways to add styles via JS to `#content` div
        // the first two work, the third one fails

        // ** method (1) **
        // const elem = document.getElementById('content');
        // elem.style.border = '1px solid black';
        // elem.style.backgroundColor = 'lightgrey';

        // ** method (2) **
        // const s = document.createElement('style');
        // const cssVars = `border: 1px solid black;\nbackground-color: lightgrey;`;
        // s.type = 'text/css';
        // s.innerText = `#content { ${cssVars} }`;
        // document.head.appendChild(s);

        // ** method (3) **
        // this does not; causes unstyled initial "fullSnapshot" frame
        let sheet = new CSSStyleSheet();
        const cssVars = `border: 1px solid black;\nbackground-color: lightgrey;`;
        sheet.insertRule(`#content { ${cssVars} }`);
        document.adoptedStyleSheets = [...(document.adoptedStyleSheets ?? []), sheet];
    </script>
</body>

</html>

Testcase Gist URL

No response

Additional Information

This is related to, but slightly different from, this issue: https://github.com/rrweb-io/rrweb/issues/1230

jluxenberg avatar Jan 14 '25 18:01 jluxenberg