rrweb-snapshot
rrweb-snapshot copied to clipboard
snapshot is produced with non-unique IDs
In some cases calling snapshot(document) produces a tree with elements which IDs are not unique. In most cases these elements are the root element document and the first element from <head> e.g. <link> or <style>.
It leads to the situation where in Player the root element document with id = 1 is overwritten by some child node, that also has id = 1. In this case IncrementalSource.Event, which is fired for document, won't be correctly processed by the Player instance.
Here the assignment of non-unique IDs happen: https://github.com/rrweb-io/rrweb-snapshot/blob/master/src/snapshot.ts#L693
Is this happening when you snapshot a page more than once?
No, it isn't happening when requesting a page snapshot more than once.
I was able to identify that for some websites the assignment node.__sn = {/* serialized node */} gets transferred through the page reload. Probably it's happening because of particular cache configuration, but I didn't find the exact reason.
So if you create a snapshot for a page and then refresh it, you'll be able to see that, for instance, document has __sn property assigned even if you don't load rrweb-snapshot after the page refresh.
Unfortunately, I don't have any strong case to share. However, I've noticed that this issue is happening more often in Safari than in any other browser (probably only in Safari).
I was able to fix it by collecting the serialized objects into a WeakMap instead of directly modifying the Node element.
In a separate file:
export const serializedCache = new WeakMap<Node, serializedNodeWithId>();
Restoring cache:
let serializedNode = serializedCache.get(node);
// Try to reuse the previous id
if (serializedNode) {
id = serializedNode.id;
}
Caching a serialized node:
const serializedNode = Object.assign(_serializedNode, { id });
serializedCache.set(n, serializedNode);
I can create a PR if you approve this modification.