rrweb-io / rrweb-snapshot

rrweb's snapshot and rebuild module

Geek Repo:Geek Repo

Github PK Tool:Github PK Tool

snapshot is produced with non-unique IDs

hvpavel opened this issue · comments

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

commented

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.