diff --git a/packages/rrweb/src/replay/index.ts b/packages/rrweb/src/replay/index.ts
index 5dacdc104d..a80e1de592 100644
--- a/packages/rrweb/src/replay/index.ts
+++ b/packages/rrweb/src/replay/index.ts
@@ -1792,17 +1792,22 @@ export class Replayer {
const newSn = mirror.getMeta(
target as Node & RRNode,
) as serializedElementNodeWithId;
- Object.assign(
- newSn.attributes,
- mutation.attributes as attributes,
+ const newNode = buildNodeWithSN(
+ {
+ ...newSn,
+ attributes: {
+ ...newSn.attributes,
+ ...(mutation.attributes as attributes),
+ },
+ },
+ {
+ doc: target.ownerDocument as Document, // can be Document or RRDocument
+ mirror: mirror as Mirror,
+ skipChild: true,
+ hackCss: true,
+ cache: this.cache,
+ },
);
- const newNode = buildNodeWithSN(newSn, {
- doc: target.ownerDocument as Document, // can be Document or RRDocument
- mirror: mirror as Mirror,
- skipChild: true,
- hackCss: true,
- cache: this.cache,
- });
const siblingNode = target.nextSibling;
const parentNode = target.parentNode;
if (newNode && parentNode) {
diff --git a/packages/rrweb/test/__snapshots__/replayer.test.ts.snap b/packages/rrweb/test/__snapshots__/replayer.test.ts.snap
index c4edd6d540..1682d09ed5 100644
--- a/packages/rrweb/test/__snapshots__/replayer.test.ts.snap
+++ b/packages/rrweb/test/__snapshots__/replayer.test.ts.snap
@@ -158,6 +158,73 @@ file-cid-3
"
`;
+exports[`replayer > can handle remote stylesheets 1`] = `
+"file-frame-2
+
+
+
+
+
+
+
+
+
+
+file-frame-3
+
+
+
+
+
+
+
+
+
+
+file-cid-0
+@charset \\"utf-8\\";
+
+.rr-block { background: currentcolor; }
+
+noscript { display: none !important; }
+
+html.rrweb-paused *, html.rrweb-paused ::before, html.rrweb-paused ::after { animation-play-state: paused !important; }
+
+
+file-cid-1
+@charset \\"utf-8\\";
+
+.OverlayDrawer-modal-187 { }
+
+.OverlayDrawer-paper-188 { width: 100%; }
+
+@media (min-width: 48em) {
+ .OverlayDrawer-paper-188 { width: 38rem; }
+}
+
+@media (min-width: 48em) {
+}
+
+@media (min-width: 48em) {
+}
+"
+`;
+
exports[`replayer > can handle removing style elements 1`] = `
"file-frame-1
diff --git a/packages/rrweb/test/replayer.test.ts b/packages/rrweb/test/replayer.test.ts
index 96e2012b15..c38ec356da 100644
--- a/packages/rrweb/test/replayer.test.ts
+++ b/packages/rrweb/test/replayer.test.ts
@@ -8,6 +8,7 @@ import {
launchPuppeteer,
sampleEvents as events,
sampleStyleSheetRemoveEvents as stylesheetRemoveEvents,
+ sampleRemoteStyleSheetEvents as remoteStyleSheetEvents,
waitForRAF,
} from './utils';
import styleSheetRuleEvents from './events/style-sheet-rule-events';
@@ -209,6 +210,23 @@ describe('replayer', function () {
await assertDomSnapshot(page);
});
+ it('can handle remote stylesheets', async () => {
+ await page.evaluate(`events = ${JSON.stringify(remoteStyleSheetEvents)}`);
+ const actionLength = await page.evaluate(`
+ const { Replayer } = rrweb;
+ const replayer = new Replayer(events);
+ replayer.play(2500);
+ replayer['timer']['actions'].length;
+ `);
+ expect(actionLength).toEqual(
+ remoteStyleSheetEvents.filter(
+ (e) => e.timestamp - remoteStyleSheetEvents[0].timestamp >= 2500,
+ ).length,
+ );
+
+ await assertDomSnapshot(page);
+ });
+
it('can fast forward selection events', async () => {
await page.evaluate(`events = ${JSON.stringify(selectionEvents)}`);
diff --git a/packages/rrweb/test/utils.ts b/packages/rrweb/test/utils.ts
index 50b39ccb99..9699543a4a 100644
--- a/packages/rrweb/test/utils.ts
+++ b/packages/rrweb/test/utils.ts
@@ -561,6 +561,98 @@ export const sampleStyleSheetRemoveEvents: eventWithTime[] = [
},
];
+export const sampleRemoteStyleSheetEvents: eventWithTime[] = [
+ {
+ type: EventType.DomContentLoaded,
+ data: {},
+ timestamp: now,
+ },
+ {
+ type: EventType.Load,
+ data: {},
+ timestamp: now + 1000,
+ },
+ {
+ type: EventType.Meta,
+ data: {
+ href: 'http://localhost',
+ width: 1000,
+ height: 800,
+ },
+ timestamp: now + 1000,
+ },
+ {
+ type: EventType.FullSnapshot,
+ data: {
+ node: {
+ type: 0,
+ childNodes: [
+ {
+ type: 2,
+ tagName: 'html',
+ attributes: {},
+ childNodes: [
+ {
+ type: 2,
+ tagName: 'head',
+ attributes: {},
+ childNodes: [
+ {
+ type: 2,
+ tagName: 'link',
+ attributes: {
+ rel: 'stylesheet',
+ href: '',
+ },
+ childNodes: [],
+ id: 4,
+ },
+ ],
+ id: 3,
+ },
+ {
+ type: 2,
+ tagName: 'body',
+ attributes: {},
+ childNodes: [],
+ id: 6,
+ },
+ ],
+ id: 2,
+ },
+ ],
+ id: 1,
+ },
+ initialOffset: {
+ top: 0,
+ left: 0,
+ },
+ },
+ timestamp: now + 1000,
+ },
+ {
+ type: EventType.IncrementalSnapshot,
+ data: {
+ source: IncrementalSource.Mutation,
+ texts: [],
+ attributes: [
+ {
+ id: 4,
+ attributes: {
+ href: null,
+ rel: null,
+ _cssText:
+ '.OverlayDrawer-modal-187 { }.OverlayDrawer-paper-188 { width: 100%; }@media (min-width: 48em) {\n .OverlayDrawer-paper-188 { width: 38rem; }\n}@media (min-width: 48em) {\n}@media (min-width: 48em) {\n}',
+ },
+ },
+ ],
+ removes: [],
+ adds: [],
+ },
+ timestamp: now + 2000,
+ },
+];
+
export const polyfillWebGLGlobals = () => {
// polyfill as jsdom does not have support for these classes
// consider replacing with https://www.npmjs.com/package/canvas