Skip to content

Commit 8e55c45

Browse files
authored
fix(rrdom): Ignore invalid DOM attributes when diffing (#1561)
* fix(rrdom): Ignore invalid DOM attributes when diffing (#213) We encountered an issue where replays with invalid attributes (e.g. `@click`) would break rendering the replay after seeking. The exception bubbles up to [here](https://github.com/rrweb-io/rrweb/blob/62093d4385a09eb0980c2ac02d97eea5ce2882be/packages/rrweb/src/replay/index.ts#L270-L279), which means the replay will continue to play, but the replay mirror will be incomplete. Closes getsentry/team-replay#458 * add changeset
1 parent 61ab209 commit 8e55c45

File tree

3 files changed

+41
-1
lines changed

3 files changed

+41
-1
lines changed

.changeset/chilled-penguins-sin.md

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
---
2+
"rrdom": patch
3+
---
4+
5+
Ignore invalid DOM attributes when diffing

packages/rrdom/src/diff.ts

Lines changed: 10 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -354,7 +354,16 @@ function diffProps(
354354
}
355355
};
356356
} else if (newTree.tagName === 'IFRAME' && name === 'srcdoc') continue;
357-
else oldTree.setAttribute(name, newValue);
357+
else {
358+
try {
359+
oldTree.setAttribute(name, newValue);
360+
} catch (err) {
361+
// We want to continue diffing so we quietly catch
362+
// this exception. Otherwise, this can throw and bubble up to
363+
// the `ReplayerEvents.Flush` listener and break rendering
364+
console.warn(err);
365+
}
366+
}
358367
}
359368

360369
for (const { name } of Array.from(oldAttributes))

packages/rrdom/test/diff.test.ts

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -335,6 +335,32 @@ describe('diff algorithm for rrdom', () => {
335335
expect((node as Node as HTMLElement).className).toBe('node');
336336
});
337337

338+
it('ignores invalid attributes', () => {
339+
const tagName = 'DIV';
340+
const node = document.createElement(tagName);
341+
const sn = Object.assign({}, elementSn, {
342+
attributes: { '@click': 'foo' },
343+
tagName,
344+
});
345+
mirror.add(node, sn);
346+
347+
const rrDocument = new RRDocument();
348+
const rrNode = rrDocument.createElement(tagName);
349+
const sn2 = Object.assign({}, elementSn, {
350+
attributes: { '@click': 'foo' },
351+
tagName,
352+
});
353+
rrDocument.mirror.add(rrNode, sn2);
354+
355+
rrNode.attributes = { id: 'node1', class: 'node', '@click': 'foo' };
356+
diff(node, rrNode, replayer);
357+
expect((node as Node as HTMLElement).id).toBe('node1');
358+
expect((node as Node as HTMLElement).className).toBe('node');
359+
expect('@click' in (node as Node as HTMLElement)).toBe(false);
360+
expect(warn).toHaveBeenCalledTimes(1);
361+
warn.mockClear();
362+
});
363+
338364
it('can update exist properties', () => {
339365
const tagName = 'DIV';
340366
const node = document.createElement(tagName);

0 commit comments

Comments
 (0)