diff --git a/packages/rrweb/src/replay/index.ts b/packages/rrweb/src/replay/index.ts
index 5d02cac396..4b0650b192 100644
--- a/packages/rrweb/src/replay/index.ts
+++ b/packages/rrweb/src/replay/index.ts
@@ -1835,17 +1835,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 dc2f3e1bfd..df3d1cc04e 100644
--- a/packages/rrweb/test/__snapshots__/replayer.test.ts.snap
+++ b/packages/rrweb/test/__snapshots__/replayer.test.ts.snap
@@ -144,6 +144,66 @@ 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 59c5a9a90c..723988638a 100644
--- a/packages/rrweb/test/replayer.test.ts
+++ b/packages/rrweb/test/replayer.test.ts
@@ -7,6 +7,7 @@ import {
launchPuppeteer,
sampleEvents as events,
sampleStyleSheetRemoveEvents as stylesheetRemoveEvents,
+ sampleRemoteStyleSheetEvents as remoteStyleSheetEvents,
waitForRAF,
} from './utils';
import styleSheetRuleEvents from './events/style-sheet-rule-events';
@@ -210,6 +211,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 ed6f5f2159..364cf9c68e 100644
--- a/packages/rrweb/test/utils.ts
+++ b/packages/rrweb/test/utils.ts
@@ -559,6 +559,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