Retrieving event metadata from node id
Hi there. As discussed in another issue, I'm using the event-cast to get a stream of events as the replay is happening. I'd like to be able to get more metadata about each event, however. For example, for a click event, how can I get the name/id of the div that was clicked?
Is there a way to search the node map in some way? It looks like the replayer doesn't have any exported methods for this.
Seems like mirror.getNode(id) would to the trick? It looks like mirror.map is being populated here on the rebuild:
https://sourcegraph.com/github.com/rrweb-io/rrweb/-/blob/src/replay/index.ts#L412
Could mirror (or the map) be exported in the Replayer? Or alternatively, some more metadata on each event would work as well.
I believe mirror is already exported: https://github.com/rrweb-io/rrweb/blob/master/src/index.ts#L15
Hi @Yuyz0112 , sorry to bother here. I'm using mirror.getNode to retrieve node metadat (tagName, attributes, etc.) for each event, however, it seems like the data in mirror.map is dynamically changing as the replay is happening.
Is this observation correct? And if so, do you mind directing me to the right place to see how this works?
And beyond that, is there any way that I can arbitrarily request the data for any node id at any time? I'd like to make a nice UI that shows all the events/elements as the player is happening.
Friendly reminder here @Yuyz0112 .
@jay-khatri
Sorry for the late.
I'd like to make a nice UI that shows all the events/elements as the player is happening.
This is a good feature-request I'd love to work on. And you are right, the DOM map is a map from id to element object, which is dynamically changed during the replay since elements are adding and removing from the document.
I think we can provide a feature which can build a static map from id to some element attributes, like CSS path and tag name, by replaying all the events in a background mode. It may not be a good idea to keep all the element object all the time, since it may cause some complex memory problem.
So could tell me the info your need to store in this static map?
Hi @Yuyz0112 , no worries!
My use case for this feature is:
- being able to show a nice UI of events (as discussed)
- indexing each session based on these attributes.
Therefore, it would be nice to have access to this map via record((e) => ...), so that indexing can be done asynchronously on the server. Now that I think of it, I could filter the event that's emitted in record to create the map myself 🤔 , but I might still have some trouble with looking up the attributes I want.
Some things I'd like to have in the static map:
- css selectors/path
- event id / timestamp
-
node.attributes,node.tagName
@Yuyz0112 I've taken a closer look at the implementation of this, and it seems there could be an event emitter that outputs a serializedNodeWithId whenever this method is called. Then, in the client code, I can add a custom method that writes to my backend, for example.
On the replay side, your approach of replaying all the events in a background mode makes a lot of sense.
Overall, I'm thinking its probably best to decouple the replay/record implementations of this feature, but any thoughts here? I'd also be happy to help; maybe I can work on the record part?
Yep, you can try the record part!
Hi @Yuyz0112 , I've been thinking about how this should be implemented and here's my thoughts.
In rrweb-snapshot here, the idNodeMap is being populated for every serialized node (and its respective children). Ideally, whenever a node is added to this map, I'd like a method to get called so that it can be picked up by the client code via record.
What I'm thinking is to extend the mirror type so that it looks like:
export type Mirror = {
getId: (n: INode) => number;
getNode: (id: number) => INode \| null;
removeNodeFromMap: (n: INode) => void;
has: (id: number) => boolean;
// new
setNode: (n: INode, id: number)
_map: idNodeMap;
onNewEntry: ()...
};
And rather than explicitly setting the new member of the map via map[], we call setNode so that we can pick up changes and run onNewEntry() as an option to record. Further down the line, we use setNode to prepopulate the _map when replay happens as well.
Thoughts?
@Yuyz0112 thought more about this, and I don't actually need the record feature in the short term. I would, however, like to have the replay part. Do you mind directing me to the right place to start looking at:
build[ing] a static map from id to some element attributes, like CSS path and tag name, by replaying all the events in a background mode
Ping here! @Yuyz0112 (sorry to bother)
@jay-khatri I've sent you a draft implementation via slack.
I am very interested in this. How is it going? @Yuyz0112 @jay-khatri