diff --git a/README.md b/README.md
index 53095c44..77139b66 100644
--- a/README.md
+++ b/README.md
@@ -7,6 +7,13 @@
# rrweb
+
+
[](https://travis-ci.org/rrweb-io/rrweb)
[](https://gitter.im/rrweb-io/rrweb?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge&utm_content=badge)

@@ -24,6 +31,8 @@ rrweb refers to 'record and replay the web', which is a tool for recording and r
[**📚 Read the rrweb guide here. 📚**](./guide.md)
+[**Recipes**](./docs/recipes/index.md)
+
## Project Structure
rrweb is mainly composed of 3 parts:
diff --git a/README.zh_CN.md b/README.zh_CN.md
index 6d02c7b1..f8363148 100644
--- a/README.zh_CN.md
+++ b/README.zh_CN.md
@@ -7,6 +7,13 @@
# rrweb
+
+
[](https://travis-ci.org/rrweb-io/rrweb)
[](https://gitter.im/rrweb-io/rrweb?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge&utm_content=badge)

diff --git a/docs/recipes/canvas.md b/docs/recipes/canvas.md
new file mode 100644
index 00000000..8e5c7522
--- /dev/null
+++ b/docs/recipes/canvas.md
@@ -0,0 +1,23 @@
+# Canvas
+
+Canvas is a special HTML element, which will not be recorded by rrweb by default. There are some options for recording and replaying Canvas.
+
+Enable recording Canvas:
+
+```js
+rrweb.record({
+ emit(event) {},
+ recordCanvas: true,
+});
+```
+
+Enable replaying Canvas:
+
+```js
+const replayer = new rrweb.Replayer(events, {
+ UNSAFE_replayCanvas: true,
+});
+replayer.play();
+```
+
+**Enable replaying Canvas will remove the sandbox, which may cause a potential security issue.**
diff --git a/docs/recipes/custom-event.md b/docs/recipes/custom-event.md
new file mode 100644
index 00000000..287b8e7d
--- /dev/null
+++ b/docs/recipes/custom-event.md
@@ -0,0 +1,53 @@
+# Custom Event
+
+You may need to record some custom events along with the rrweb events, and let them be played as other events. The custom event API was designed for this.
+
+After starting the recording, we can call the `record.addCustomEvent` API to add a custom event.
+
+```js
+// start recording
+rrweb.record({
+ emit(event) {
+ ...
+ }
+})
+
+// record some custom events at any time
+rrweb.record.addCustomEvent('submit-form', {
+ name: 'Adam',
+ age: 18
+})
+rrweb.record.addCustomEvent('some-error', {
+ error
+})
+```
+
+`addCustomEvent` accepts two parameters. The first one is a string-type `tag`, while the second one is an any-type `payload`.
+
+During the replay, we can add an event listener to custom events, or configure the style of custom events in rrweb-player's timeline.
+
+**Listen to custom events**
+
+```js
+const replayer = new rrweb.Replayer(events);
+
+replayer.on('custom-event', (event) => {
+ console.log(event.tag, event.payload);
+});
+```
+
+**Display in rrweb-player**
+
+```js
+new rrwebPlayer({
+ target: document.body,
+ props: {
+ events,
+ // configure the color of tag which will be displayed on the timeline
+ tags: {
+ 'submit-form': '#21e676',
+ 'some-error': 'red',
+ },
+ },
+});
+```
diff --git a/docs/recipes/customize-replayer.md b/docs/recipes/customize-replayer.md
new file mode 100644
index 00000000..de2bcec8
--- /dev/null
+++ b/docs/recipes/customize-replayer.md
@@ -0,0 +1,72 @@
+# Customize the Replayer
+
+When rrweb's Replayer and the rrweb-player UI do not fit your need, you can customize your replayer UI.
+
+There are several ways to do this:
+
+1. Use rrweb-player, and customize its CSS.
+2. Use rrweb-player, and set `showController: false` to hide the controller UI. With this config, you can implement your controller UI.
+3. Use the `insertStyleRules` options to inject some CSS into the replay iframe.
+4. Develop a new replayer UI with rrweb's Replayer.
+
+## Implement Your Controller UI
+
+When using rrweb-player, you can hide its controller UI:
+
+```js
+new rrwebPlayer({
+ target: document.body,
+ props: {
+ events,
+ showController: false,
+ },
+});
+```
+
+When you are implementing a controller UI, you may need to interact with rrweb-player.
+
+The follwing APIs show some common use case of a controller UI:
+
+```js
+// toggle between play and pause
+rrwebPlayer.toggle();
+// play
+rrwebPlayer.play();
+// pause
+rrwebPlayer.pause();
+// update the dimension
+rrwebPlayer.$set({
+ width: NEW_WIDTH,
+ height: NEW_HEIGHT,
+});
+rrwebPlayer.triggerResize();
+// toggle whether to skip the inactive time
+rrwebPlayer.toggleSkipInactive();
+// set replay speed
+rrwebPlayer.setSpeed(2);
+// go to some timing
+rrwebPlayer.goto(3000);
+```
+
+And there are some ways to listen rrweb-player's state:
+
+```js
+// get current timing
+rrwebPlayer.addEventListener('ui-update-current-time', (event) => {
+ console.log(event.detail.payload);
+});
+
+// get current state
+rrwebPlayer.addEventListener('ui-update-player-state', (event) => {
+ console.log(event.detail.payload);
+});
+
+// get current progress
+rrwebPlayer.addEventListener('ui-update-progress', (event) => {
+ console.log(event.detail.payload);
+});
+```
+
+## Develop a new replayer UI with rrweb's Replayer.
+
+Please refer [rrweb-player](https://github.com/rrweb-io/rrweb-player).
diff --git a/docs/recipes/dive-into-event.md b/docs/recipes/dive-into-event.md
new file mode 100644
index 00000000..b1044261
--- /dev/null
+++ b/docs/recipes/dive-into-event.md
@@ -0,0 +1,70 @@
+# Dive Into Events
+
+The events recorded by rrweb are a set of strictly-typed JSON data. You may discover some flexible ways to use them when you are familiar with the details.
+
+## Data Types
+
+Every event has a `timestamp` attribute to record the time it was emitted.
+
+There is also a `type` attribute indicates the event's type, the semantic of event's type is:
+
+```
+type -> EventType.DomContentLoaded
+event -> domContentLoadedEvent
+
+type = EventType.Load
+event -> loadedEvent
+
+type -> EventType.FullSnapshot
+event -> fullSnapshotEvent
+
+type -> EventType.IncrementalSnapshot
+event -> incrementalSnapshotEvent
+
+type -> EventType.Meta
+event -> metaEvent
+
+type -> EventType.Custom
+event -> customEvent
+```
+
+The EventType is Typescript's numeric enum, which is a self-increased number from 0 in runtime. You can find its definition in this [list](https://github.com/rrweb-io/rrweb/blob/9488deb6d54a5f04350c063d942da5e96ab74075/src/types.ts#L10).
+
+In these kinds of events, the incrementalSnapshotEvent is the event that contains incremental data. You can use `event.data.source` to find which kind of incremental data it belongs to:
+
+```
+source -> IncrementalSource.Mutation
+data -> mutationData
+
+source -> IncrementalSource.MouseMove
+data -> mousemoveData
+
+source -> IncrementalSource.MouseInteraction
+data -> mouseInteractionData
+
+source -> IncrementalSource.Scroll
+data -> scrollData
+
+source -> IncrementalSource.ViewportResize
+data -> viewportResizeData
+
+source -> IncrementalSource.Input
+data -> inputData
+
+source -> IncrementalSource.TouchMove
+data -> mouseInteractionData
+
+source -> IncrementalSource.MediaInteraction
+data -> mediaInteractionData
+
+source -> IncrementalSource.StyleSheetRule
+data -> styleSheetRuleData
+
+source -> IncrementalSource.CanvasMutation
+data -> canvasMutationData
+
+source -> IncrementalSource.Font
+data -> fontData
+```
+
+enum IncrementalSource's definition can be found in this [list](https://github.com/rrweb-io/rrweb/blob/master/src/types.ts#L64).
diff --git a/docs/recipes/export-to-video.md b/docs/recipes/export-to-video.md
new file mode 100644
index 00000000..557ad9b0
--- /dev/null
+++ b/docs/recipes/export-to-video.md
@@ -0,0 +1,7 @@
+# Convert To Video
+
+The event data recorded by rrweb is a performant, easy to compress, text-based format. And the replay is also pixel perfect.
+
+But if you really need to convert it into a video format, there are some tools that can do this work.
+
+Use [rrvideo](https://github.com/rrweb-io/rrvideo).
diff --git a/docs/recipes/index.md b/docs/recipes/index.md
new file mode 100644
index 00000000..ce11ec8a
--- /dev/null
+++ b/docs/recipes/index.md
@@ -0,0 +1,67 @@
+# Recipes
+
+> You may also want to read the [guide](../../guide.md) to understand the APIs, or read the [design docs](../) to know more technical details of rrweb.
+
+## Scenarios
+
+### Record And Replay
+
+Record and Replay is the most common use case, which is suitable for any scenario that needs to collect user behaviors and replay them.
+
+[link](./record-and-replay.md)
+
+### Dive Into Events
+
+The events recorded by rrweb are a set of strictly-typed JSON data. You may discover some flexible ways to use them when you are familiar with the details.
+
+[link](./dive-into-event.md)
+
+### Load Events Asynchronous
+
+When the size of the recorded events increased, load them in one request is not performant. You can paginate the events and load them as you need.
+
+[link](./pagination.md)
+
+### Real-time Replay (Live Mode)
+
+If you want to replay the events in a real-time way, you can use the live mode API. This API is also useful for some real-time collaboration usage.
+
+[link](./live-mode.md)
+
+### Custom Event
+
+You may need to record some custom events along with the rrweb events, and let them be played as other events. The custom event API was designed for this.
+
+[link](./custom-event.md)
+
+### Interact With UI During Replay
+
+By default, the UI could not interact during replay. But you can use API to enable/disable this programmatically.
+
+[link](./interaction.md)
+
+### Customize The Replayer
+
+When rrweb's Replayer and the rrweb-player UI do not fit your need, you can customize your own replayer UI.
+
+[link](./customize-replayer.md)
+
+### Convert To Video
+
+The event data recorded by rrweb is a performant, easy to compress, text-based format. And the replay is also pixel perfect.
+
+But if you really need to convert it into a video format, there are some tools that can do this work.
+
+[link](./export-to-video.md)
+
+### Optimize The Storage Size
+
+In some Apps, rrweb may record an unexpected amount of data. This part will help to find a suitable way to optimize the storage.
+
+[link](./optimize-storage.md)
+
+### Canvas
+
+Canvas is a special HTML element, which will not be recorded by rrweb by default. There are some options for recording and replaying Canvas.
+
+[link](./canvas.md)
diff --git a/docs/recipes/interaction.md b/docs/recipes/interaction.md
new file mode 100644
index 00000000..b2d8e9c5
--- /dev/null
+++ b/docs/recipes/interaction.md
@@ -0,0 +1,19 @@
+# Interact With UI During Replay
+
+By default, the UI could not interact during replay. But you can use API to enable/disable this programmatically.
+
+```js
+const replayer = new rrweb.Replayer(events);
+
+// enable user interact with the UI
+replayer.enableInteract();
+
+// disable user interact with the UI
+replayer.disableInteract();
+```
+
+rrweb uses the `pointer-events: none` CSS property to disable interaction.
+
+This will let the replay more stable and avoid some problems like navigate by clicking an external link.
+
+If you want to enable user interaction, like input, then you can use the `enableInteract` API. But be sure you have handled the problems that may cause unstable replay.
diff --git a/docs/recipes/live-mode.md b/docs/recipes/live-mode.md
new file mode 100644
index 00000000..d415e856
--- /dev/null
+++ b/docs/recipes/live-mode.md
@@ -0,0 +1,27 @@
+# Real-time Replay (Live Mode)
+
+If you want to replay the events in a real-time way, you can use the live mode API. This API is also useful for some real-time collaboration usage.
+
+When you are using rrweb's Replayer to do a real-time replay, you need to configure `liveMode: true` and call the `startLive` API to enable the live mode.
+
+```js
+const replayer = new rrweb.Replayer([], {
+ liveMode: true,
+});
+
+replayer.startLive(FIRST_EVENT.timestamp - BUFFER);
+```
+
+When calling the `startLive` API, there is an optional parameter to set the baseline time. This is quite useful when you live scenario needs a buffer time.
+
+For example, you have an event recorded at timestamp 1500. Calling `startLive(1500)` will set the baseline time to 1500 and all the timing calculation will be based on this.
+
+But this may cause your replay to look laggy. Because data transportation needs time(such as the delay of the network). And some events have been throttled(such as mouse movements) which has a delay by default.
+
+So we can configure a smaller baseline time to the `startLive` API, like `startLive(500)`. This will let the replay always delay 1 second than the source. If the time of data transportation is not longer than 1 second, the user will not feel laggy.
+
+When live mode is on, we can call `addEvent` API to add the latest events into the replayer:
+
+```js
+replayer.addEvent(NEW_EVENT);
+```
diff --git a/docs/recipes/optimize-storage.md b/docs/recipes/optimize-storage.md
new file mode 100644
index 00000000..55e3dd0f
--- /dev/null
+++ b/docs/recipes/optimize-storage.md
@@ -0,0 +1,104 @@
+# Optimize The Storage Size
+
+In some Apps, rrweb may record an unexpected amount of data. This part will help to find a suitable way to optimize the storage.
+
+Currently, we have the following optimize strategies:
+
+- block some DOM element to reduce the recording area
+- use sampling config to reduce the events
+- use deduplication and compression to reduce storage size
+
+## Block DOM element
+
+Some DOM elements may emit lots of events, and some of them may not be the thing user cares about. So you can use the block class to ignore these kinds of elements.
+
+Some common patterns may emit lots of events are:
+
+- long list
+- complex SVG
+- element with JS controlled animation
+
+## Sampling
+
+Use the sampling config in the recording can reduce the storage size by dropping some events:
+
+**Scenario 1**
+
+```js
+rrweb.record({
+ emit(event) {},
+ sampling: {
+ // do not record mouse movement
+ mousemove: false
+ // do not record mouse interaction
+ mouseInteraction: false,
+ // set the interval of scrolling event
+ scroll: 150 // do not emit twice in 150ms
+ // set the timing of record input
+ input: 'last' // When input mulitple characters, only record the final input
+ }
+})
+```
+
+**Scenario 2**
+
+```js
+rrweb.record({
+ emit(event) {},
+ sampling: {
+ // Configure which kins of mouse interaction should be recorded
+ mouseInteraction: {
+ MouseUp: false,
+ MouseDown: false,
+ Click: false,
+ ContextMenu: false,
+ DblClick: false,
+ Focus: false,
+ Blur: false,
+ TouchStart: false,
+ TouchEnd: false,
+ },
+ },
+});
+```
+
+## Compression
+
+### Use packFn to compress every event
+
+rrweb provides a pako-based simple compress function rrweb.pack.
+
+You can use it by passing it as the `packFn` in the recording.
+
+```js
+rrweb.record({
+ emit(event) {},
+ packFn: rrweb.pack,
+});
+```
+
+And you need to pass rrweb.unpack as the `unpackFn` in replaying.
+
+```js
+const replayer = new rrweb.Replayer(events, {
+ unpackFn: rrweb.unpack,
+});
+```
+
+### Compress the whole session
+
+Use packFn to compress every event may not get the best result.
+
+It's recommended to compress the whole session in the backend, which will have a more efficient compression ratio for some algorithms like deflate.
+
+## Deduplication
+
+Another optimizing strategy is deduplication.
+
+Since we need to simulate hover in the replay, rrweb will try its best to inline CSS styles in the events.
+
+So if we are applying rrweb to github.com, we may record many duplicate CSS styles across sessions.
+
+We can iterate the events and extract CSS. Then we can only store one copy of the styles.
+
+This strategy is also possible for the full snapshot across sessions.
diff --git a/docs/recipes/pagination.md b/docs/recipes/pagination.md
new file mode 100644
index 00000000..ac851b27
--- /dev/null
+++ b/docs/recipes/pagination.md
@@ -0,0 +1,23 @@
+# Load Events Asynchronous
+
+When the size of the recorded events increased, load them in one request is not performant. You can paginate the events and load them as you need.
+
+rrweb's API for loading async events is quite simple:
+
+```js
+const replayer = new rrweb.Replayer(events);
+
+replayer.addEvent(NEW_EVENT);
+```
+
+When calling the `addEvent` API to add a new event, rrweb will resolve its timestamp and replay it as need.
+
+If you need to load several events, you can do a lool like this:
+
+```js
+const replayer = new rrweb.Replayer(events);
+
+for (const event of NEW_EVENTS) {
+ replayer.addEvent(event);
+}
+```
diff --git a/docs/recipes/record-and-replay.md b/docs/recipes/record-and-replay.md
new file mode 100644
index 00000000..7b4b77bb
--- /dev/null
+++ b/docs/recipes/record-and-replay.md
@@ -0,0 +1,31 @@
+# Record And Replay
+
+Record and Replay is the most common use case, which is suitable for any scenario that needs to collect user behaviors and replay them.
+
+You only need a simple API call to record the website:
+
+```js
+const stopFn = rrweb.record({
+ emit(event) {
+ // save the event
+ },
+});
+```
+
+You can use any approach to store the recorded events, like sending the events to your backend and save them into the database.
+
+But you should guarantee:
+
+- a set of events are sorted by its timestamp
+- save every event
+
+You can use the `stopFn` to stop the recording.
+
+The replay is also as simple as putting events into rrweb's Replayer.
+
+```js
+const events = GET_YOUR_EVENTS;
+
+const replayer = new rrweb.Replayer(events);
+replayer.play();
+```
diff --git a/guide.md b/guide.md
index 81e26058..17d9e0e7 100644
--- a/guide.md
+++ b/guide.md
@@ -1,6 +1,8 @@
# Guide
-[中文指南](./guide.zh_CN.md)
+[中文指南](./guide.md)
+
+> You may also want to read the [recipes](./docs/recipes/index.md) to find some use real-world use case, or read the [design docs](../) to know more technical details of rrweb.
## Installation
@@ -31,17 +33,44 @@ This also can be done by using the CDN service:
```
+#### Other bundles
+
+Besides the `record/rrweb-record.min.js` entry, rrweb also provides other bundles for different usage.
+
+```shell
+# Include record, replay, compression, and decompression.
+rrweb-all.js
+rrweb-all.min.js
+# Include record and replay.
+rrweb.js
+rrweb.min.js
+# Include the styles for replay.
+rrweb.min.css
+# Record
+record/rrweb-record.js
+record/rrweb-record.min.js
+# Data compression.
+record/rrweb-record-pack.js
+record/rrweb-record-pack.min.js
+# Replay
+replay/rrweb-replay.js
+replay/rrweb-replay.min.js
+# Data decompression.
+replay/rrweb-replay-unpack.js
+replay/rrweb-replay-unpack.min.js
+```
+
### NPM
```shell
npm install --save rrweb
```
-rrweb provides both commonJS and ES modules bundles, which is easy to use with the popular bundlers.
+rrweb provides both commonJS and ES modules bundles, which are easy to use with the popular bundlers.
### Compatibility Note
-rrweb does **not** support IE11 and below, because it uses the `MutationObserver` API which was supported by [these browsers](https://caniuse.com/#feat=mutationobserver).
+rrweb does **not** support IE11 and below because it uses the `MutationObserver` API which was supported by [these browsers](https://caniuse.com/#feat=mutationobserver).
## Getting Started
@@ -73,7 +102,7 @@ let stopFn = rrweb.record({
});
```
-A more real-world usage may looks like this:
+A more real-world usage may look like this:
```js
let events = [];
@@ -102,6 +131,26 @@ function save() {
setInterval(save, 10 * 1000);
```
+#### Options
+
+The parameter of `rrweb.record` accepts the following options.
+
+| key | default | description |
+| ---------------- | ----------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------- |
+| emit | required | the callback function to get emitted events |
+| checkoutEveryNth | - | take a full snapshot after every N events
refer to the [checkout](#checkout) chapter |
+| checkoutEveryNms | - | take a full snapshot after every N ms
refer to the [checkout](#checkout) chapter |
+| blockClass | 'rr-block' | Use a string or RegExp to configure which elements should be blocked, refer to the [privacy](#privacy) chapter |
+| ignoreClass | 'rr-ignore' | Use a string or RegExp to configure which elements should be ignored, refer to the [privacy](#privacy) chapter |
+| maskAllInputs | false | mask all input content as \* |
+| maskInputOptions | {} | mask some kinds of input \*
refert ot the [list](https://github.com/rrweb-io/rrweb-snapshot/blob/6728d12b3cddd96951c86d948578f99ada5749ff/src/types.ts#L72) |
+| inlineStylesheet | true | whether to inline the stylesheet in the events |
+| hooks | {} | hooks for events
refer to the [list](https://github.com/rrweb-io/rrweb/blob/9488deb6d54a5f04350c063d942da5e96ab74075/src/types.ts#L207) |
+| packFn | - | refer to the [storage optimization recipe](./docs/recipes/optimize-storage.md) |
+| sampling | - | refer to the [storage optimization recipe](./docs/recipes/optimize-storage.md) |
+| recordCanvas | false | whether to record the canvas element |
+| collectFonts | false | whether to collect fonts in the website |
+
#### Privacy
You may find some contents on the webpage which are not willing to be recorded, then you can use the following approaches:
@@ -109,6 +158,7 @@ You may find some contents on the webpage which are not willing to be recorded,
- An element with the class name `.rr-block` will not be recorded. Instead, it will replay as a placeholder with the same dimension.
- An element with the class name `.rr-ignore` will not record its input events.
- `input[type="password"]` will be ignored as default.
+- Mask options to mask the content in input elements.
#### Checkout
@@ -204,18 +254,43 @@ const replayer = new rrweb.Replayer(events);
replayer.play();
```
+#### Control the replayer by API
+
+```js
+const replayer = new rrweb.Replayer(events);
+
+// play
+replayer.play();
+
+// play from the third seconds
+replayer.play(3000);
+
+// pause
+replayer.pause();
+
+// pause at the fifth seconds
+replayer.pause(5000);
+```
+
#### Options
The replayer accepts options as its constructor's second parameter, and it has the following options:
-| key | default | description |
-| ------------ | ------------- | ----------------------------------------------- |
-| speed | 1 | replay speed ratio |
-| root | document.body | the root element of replayer |
-| loadTimeout | 0 | timeout of loading remote style sheet |
-| skipInactive | false | whether to skip inactive time |
-| showWarning | true | whether to print warning messages during replay |
-| showDebug | false | whether to print debug messages during replay |
+| key | default | description |
+| ------------------- | ------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ |
+| speed | 1 | replay speed ratio |
+| root | document.body | the root element of replayer |
+| loadTimeout | 0 | timeout of loading remote style sheet |
+| skipInactive | false | whether to skip inactive time |
+| showWarning | true | whether to print warning messages during replay |
+| showDebug | false | whether to print debug messages during replay |
+| blockClass | 'rr-block' | element with the class name will display as a blocked area |
+| liveMode | false | whether to enable live mode |
+| inertStyleRules | [] | accepts multiple CSS rule string, which will be injected into the replay iframe |
+| triggerFocus | true | whether to trigger focus during replay |
+| UNSAFE_replayCanvas | false | whether to replay the canvas element. **Enable this will remove the sandbox, which is unsafe.** |
+| mouseTail | true | whether to show mouse tail during replay. Set to false to disable mouse tail. A complete config can be found in this [type](https://github.com/rrweb-io/rrweb/blob/9488deb6d54a5f04350c063d942da5e96ab74075/src/types.ts#L407) |
+| unpackFn | - | refer to the [storage optimization recipe](./docs/recipes/optimize-storage.md) |
#### Use rrweb-player
@@ -244,73 +319,63 @@ npm install --save rrweb-player
```js
new rrwebPlayer({
target: document.body, // customizable root element
- data: {
+ props: {
events,
- autoPlay: true,
},
});
```
+##### Options
+
+| key | default | description |
+| -------------- | ------------ | ------------------------------------------------------ |
+| events | [] | the events for replaying |
+| width | 1024 | the width of the replayer |
+| height | 576 | the height of the replayer |
+| autoPlay | true | whether to autoplay |
+| speedOption | [1, 2, 4, 8] | speed options in UI |
+| showController | true | whether to show the controller UI |
+| tags | {} | customize the custom events style with a key-value map |
+| ... | - | all the rrweb Replayer options will be bypassed |
+
#### Events
-Developers may want to extend the rrweb's replayer or respond to its events. Such as giving a notification when the replayer starts to skip inactive time.
-So rrweb expose a public API `on` which allow developers listen to the events and customize the reactions, and it has the following events:
+Developers may want to extend the rrweb's replayer or respond to its events. Such as giving notification when the replayer starts to skip inactive time.
+So rrweb expose a public API `on` which allow developers to listen to the events and customize the reactions, and it has the following events:
-| event | description |
-| ---------------------- | ---------------------------------- |
-| start | started to replay |
-| pause | paused the replay |
-| finish | finished the replay |
-| fullsnapshot-rebuilded | rebuilded a full snapshot |
-| load-stylesheet-start | started to load remote stylesheets |
-| load-stylesheet-end | loaded remote stylesheets |
-| skip-start | started to skip inactive time |
-| skip-end | skipped inactive time |
+```js
+const replayer = new rrweb.Replayer(events);
+replayer.on(EVENT_NAME, (payload) => {
+ ...
+})
+```
+
+The event list:
+
+| Event | Description | Value |
+| ---------------------- | ----------------------------------- | ----------------- |
+| start | started to replay | - |
+| pause | paused the replay | - |
+| finish | finished the replay | - |
+| resize | the viewport has changed | { width, height } |
+| fullsnapshot-rebuilded | rebuilded a full snapshot | event |
+| load-stylesheet-start | started to load remote stylesheets | - |
+| load-stylesheet-end | loaded remote stylesheets | - |
+| skip-start | started to skip inactive time | { speed } |
+| skip-end | skipped inactive time | { speed } |
+| mouse-interaction | mouse interaction has been replayed | { type, target } |
+| event-cast | event has been replayed | event |
+| custom-event | custom event has been replayed | event |
The rrweb-replayer also re-expose the event listener via a `component.addEventListener` API.
-## API
+And there are three rrweb-replayer event will be emitted in the same way:
-### rrweb
-
-#### rrweb.record
-
-```typescript
-type record = (options: recordOptions) => listenerHandler;
-
-type recordOptions = {
- emit: (e: eventWithTime) => void;
-};
-type listenerHandler = () => void;
-```
-
-#### rrweb.Replayer
-
-```typescript
-class Replayer {
- public wrapper: HTMLDivElement;
-
- constructor(events: eventWithTime[], config?: Partial);
-
- public on(event: string, handler: mitt.Handler): void;
- public setConfig(config: Partial): void;
- public getMetaData(): playerMetaData;
- public getTimeOffset(): number;
- public play(timeOffset?: number): void;
- public pause(timeOffset?: number): void;
-}
-
-type playerConfig = {
- speed: number;
- root: Element;
- loadTimeout: number;
- skipInactive: Boolean;
-};
-
-type playerMetaData = {
- totalTime: number;
-};
-```
+| Event | Description | Value |
+| ---------------------- | -------------------------------- | ----------------------- |
+| ui-update-current-time | current time has changed | { detail: { payload } } |
+| ui-update-player-state | current player state has changed | { detail: { payload } } |
+| ui-update-progress | current progress has changed | { detail: { payload } } |
## REPL tool
@@ -331,7 +396,7 @@ Ready to record. You can do any interaction on the page.
Once you want to finish the recording, enter 'y' to start replay:
```
-At this point, you can interact in the web page. After the desired operations have been recorded, enter 'y' on the CLI, and the test tool will replay the operations to verify whether the recording was successful.
+At this point, you can interact on the web page. After the desired operations have been recorded, enter 'y' on the CLI, and the test tool will replay the operations to verify whether the recording was successful.
The following messages will be printed on the CLI during replay:
diff --git a/guide.zh_CN.md b/guide.zh_CN.md
index 270a226d..39a66daf 100644
--- a/guide.zh_CN.md
+++ b/guide.zh_CN.md
@@ -134,10 +134,10 @@ setInterval(save, 10 * 1000);
| key | 默认值 | 功能 |
| ---------------- | ----------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------ |
| emit | 必填 | 获取当前录制的数据 |
-| checkoutEveryNth | - | 每 N 次事件重新制作一次全量快照
详见[“重新制作快照”](#重新制作快照)章节 |
-| checkoutEveryNms | - | 每 N 毫秒重新制作一次全量快照
详见[“重新制作快照”](#重新制作快照)章节 |
-| blockClass | 'rr-block' | 字符串或正则表达式,可用于自定义屏蔽元素的类名,详见[“隐私”](#隐私)章节 |
-| ignoreClass | 'rr-ignore' | 字符串或正则表达式,可用域自定义忽略元素的类名,详见[“隐私”](#隐私)章节 |
+| checkoutEveryNth | - | 每 N 次事件重新制作一次全量快照
详见[“重新制作快照”](#重新制作快照)章节 |
+| checkoutEveryNms | - | 每 N 毫秒重新制作一次全量快照
详见[“重新制作快照”](#重新制作快照)章节 |
+| blockClass | 'rr-block' | 字符串或正则表达式,可用于自定义屏蔽元素的类名,详见[“隐私”](#隐私)章节 |
+| ignoreClass | 'rr-ignore' | 字符串或正则表达式,可用于自定义忽略元素的类名,详见[“隐私”](#隐私)章节 |
| maskAllInputs | false | 将所有输入内容记录为 \* |
| maskInputOptions | {} | 选择将特定类型的输入框内容记录为 \*
类型详见[列表](https://github.com/rrweb-io/rrweb-snapshot/blob/6728d12b3cddd96951c86d948578f99ada5749ff/src/types.ts#L72) |
| inlineStylesheet | true | 是否将样式表内联 |
@@ -255,7 +255,7 @@ replayer.play();
```js
const replayer = new rrweb.Replayer(events);
-//播放
+// 播放
replayer.play();
// 从第 3 秒的内容开始播放
diff --git a/test/integration.test.ts b/test/integration.test.ts
index d102db20..8d1f2d32 100644
--- a/test/integration.test.ts
+++ b/test/integration.test.ts
@@ -272,7 +272,7 @@ describe('record integration tests', function (this: ISuite) {
assertSnapshot(snapshots, __filename, 'react-styled-components');
});
- it.only('should record canvas mutations', async () => {
+ it('should record canvas mutations', async () => {
const page: puppeteer.Page = await this.browser.newPage();
await page.goto('about:blank');
await page.setContent(