Skip to content

Commit

Permalink
highlight: merge rrweb (#74)
Browse files Browse the repository at this point in the history
  • Loading branch information
Vadman97 authored Jun 1, 2022
1 parent 5c10bf7 commit 73b87ca
Show file tree
Hide file tree
Showing 265 changed files with 28,566 additions and 11,013 deletions.
Binary file removed .DS_Store
Binary file not shown.
12 changes: 5 additions & 7 deletions .github/workflows/release.yml
Original file line number Diff line number Diff line change
Expand Up @@ -9,18 +9,16 @@ jobs:
- name: Setup Node.js
uses: actions/setup-node@v1
with:
node-version: 14.15.4
node-version: 16.15.0
registry-url: https://registry.npmjs.org
- name: Install
run: yarn install
- name: Bundle Browser
run: yarn bundle:browser
- name: Bundle Highlight
run: yarn bundle:highlight
run: yarn
- name: Build all
run: yarn build:all
- name: Confirm new version
run: python3 compare.py
- name: Publish
if: github.ref == 'refs/heads/master'
run: yarn publish --access public
run: yarn lerna publish from-package --no-private
env:
NODE_AUTH_TOKEN: ${{ secrets.NPM_TOKEN }}
12 changes: 7 additions & 5 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -1,15 +1,17 @@
.vscode
.vscode/*
!/.vscode/rrweb-monorepo.code-workspace
.idea
node_modules
package-lock.json
# yarn.lock
build
dist
es
lib

temp

*.log

.env

.DS_Store

build
dist
18 changes: 9 additions & 9 deletions .release-it.json
Original file line number Diff line number Diff line change
@@ -1,15 +1,15 @@
{
"non-interactive": true,
"hooks": {
"before:init": [
"npm run bundle",
"npm run typings"
]
},
"hooks": {},
"git": {
"requireCleanWorkingDir": false
"commit": false,
"tag": false,
"push": false
},
"npm": {
"publish": false
},
"github": {
"release": true
"release": true,
"releaseName": "Release ${version}"
}
}
4 changes: 3 additions & 1 deletion .travis.yml
Original file line number Diff line number Diff line change
Expand Up @@ -11,4 +11,6 @@ install:
- yarn

script:
- xvfb-run --server-args="-screen 0 1920x1080x24" npm test
- yarn lerna run prepublish
- yarn lerna run check-types
- xvfb-run --server-args="-screen 0 1920x1080x24" yarn lerna run test
31 changes: 31 additions & 0 deletions .vscode/rrweb-monorepo.code-workspace
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
{
"folders": [
{
"name": " rrweb monorepo", // added a space to bump it to the top
"path": ".."
},
{
"name": "rrdom (package)",
"path": "../packages/rrdom"
},
{
"name": "rrweb (package)",
"path": "../packages/rrweb"
},
{
"name": "rrweb-player (package)",
"path": "../packages/rrweb-player"
},
{
"name": "rrweb-snapshot (package)",
"path": "../packages/rrweb-snapshot"
}
],
"settings": {
"jest.disabledWorkspaceFolders": [
" rrweb monorepo",
"rrweb-player (package)",
"rrdom (package)"
]
}
}
68 changes: 56 additions & 12 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -7,9 +7,10 @@

# rrweb

**[The new adventure of the rrweb community](http://www.myriptide.com/rrweb-community/)**
**[The rrweb documentary (in Chinese, with English subtitles)](https://www.bilibili.com/video/BV1wL4y1B7wN?share_source=copy_web)**

[![Join the chat at slack](https://img.shields.io/badge/[email protected]?logo=slack)](https://join.slack.com/t/rrweb/shared_invite/zt-siwoc6hx-uWay3s2wyG8t5GpZVb8rWg)
[![Twitter Follow](https://img.shields.io/badge/twitter-@rrweb__io-teal.svg?logo=twitter)](https://twitter.com/rrweb_io)
![total gzip size](https://img.badgesize.io/https://cdn.jsdelivr.net/npm/rrweb@latest/dist/rrweb.min.js?compression=gzip&label=total%20gzip%20size)
![recorder gzip size](https://img.badgesize.io/https://cdn.jsdelivr.net/npm/rrweb@latest/dist/record/rrweb-record.min.js?compression=gzip&label=recorder%20gzip%20size)
[![](https://data.jsdelivr.com/v1/package/npm/rrweb/badge)](https://www.jsdelivr.com/package/npm/rrweb)
Expand All @@ -26,13 +27,21 @@ rrweb refers to 'record and replay the web', which is a tool for recording and r

[**🍳 Recipes 🍳**](./docs/recipes/index.md)

## Version History

### 2.0.0

This version updates the highlight rrweb fork on rrweb 1.1.3 April 2022 Release.
Because this is a major update, it may not be suitable for customers looking for stable recording and replay functionality.
However, the major update brings lots of rrweb features that have been in development. See the rrweb release notes for more details.

## Project Structure

rrweb is mainly composed of 3 parts:

- **[rrweb-snapshot](https://github.com/rrweb-io/rrweb-snapshot)**, including both snapshot and rebuilding features. The snapshot is used to convert the DOM and its state into a serializable data structure with a unique identifier; the rebuilding feature is to rebuild the snapshot into corresponding DOM.
- **[rrweb-snapshot](https://github.com/rrweb-io/rrweb/tree/master/packages/rrweb-snapshot/)**, including both snapshot and rebuilding features. The snapshot is used to convert the DOM and its state into a serializable data structure with a unique identifier; the rebuilding feature is to rebuild the snapshot into corresponding DOM.
- **[rrweb](https://github.com/rrweb-io/rrweb)**, including two functions, record and replay. The record function is used to record all the mutations in the DOM; the replay is to replay the recorded mutations one by one according to the corresponding timestamp.
- **[rrweb-player](https://github.com/rrweb-io/rrweb-player)**, is a player UI for rrweb, providing GUI-based functions like pause, fast-forward, drag and drop to play at any time.
- **[rrweb-player](https://github.com/rrweb-io/rrweb/tree/master/packages/rrweb-player/)**, is a player UI for rrweb, providing GUI-based functions like pause, fast-forward, drag and drop to play at any time.

## Roadmap

Expand All @@ -59,10 +68,14 @@ Since we want the record and replay sides to share a strongly typed data structu

[Typescript handbook](https://www.typescriptlang.org/docs/handbook/declaration-files/introduction.html)

1. Fork the rrweb component repository you want to patch.
2. Run `npm install` to install required dependencies.
3. Patch the code and pass all the tests.
4. Push the code and create a pull request.
1. Fork this repository.
2. Run `yarn install` in the root to install required dependencies for all sub-packages (note: `npm install` is _not_ recommended).
3. Run `yarn dev` in the root to get auto-building for all the sub-packages whenever you modify anything.
4. Navigate to one of the sub-packages (in the `packages` folder) where you'd like to make a change.
5. Patch the code and run `yarn test` to run the tests, make sure they pass before you commit anything.
6. Push the code and create a pull request.

Protip: You can run `yarn test` in the root folder to run all the tests.

In addition to adding integration tests and unit tests, rrweb also provides a REPL testing tool.

Expand Down Expand Up @@ -117,8 +130,39 @@ In addition to adding integration tests and unit tests, rrweb also provides a RE

## Who's using rrweb

<p align="center">
<a href="http://www.smartx.com/" target="_blank">
<img width="260px" src="https://www.rrweb.io/logos/smartx.png">
</a>
</p>
<table>
<tr>
<td align="center">
<a href="http://www.smartx.com/" target="_blank">
<img width="195px" src="https://www.rrweb.io/logos/smartx.png">
</a>
</td>
<td align="center">
<a href="https://posthog.com?utm_source=rrweb&utm_medium=sponsorship&utm_campaign=open-source-sponsorship" target="_blank">
<img width="195px" src="https://www.rrweb.io/logos/posthog.png">
</a>
</td>
<td align="center">
<a href="https://statcounter.com/session-replay/" target="_blank">
<img width="195px" src="https://statcounter.com/images/logo-statcounter-arc-blue.svg">
</a>
</td>
<td align="center">
<a href="https://cux.io" target="_blank">
<img style="padding: 8px" alt="The first ever UX automation tool" width="195px" src="https://static.cux.io/logo.svg">
</a>
</td>
</tr>
<tr>
<td align="center">
<a href="https://recordonce.com/" target="_blank">
<img width="195px" src="https://uploads-ssl.webflow.com/5f3d133183156245630d4446/5f3d1940abe8db8612c23521_Record-Once-logo-554x80px.svg">
</a>
</td>
<td align="center">
<a href="https://remsupp.com" target="_blank">
<img style="padding: 8px" alt="Remote Access & Co-Browsing" width="195px" src="https://remsupp.com/images/logo.png">
</a>
</td>
</tr>
</table>
32 changes: 23 additions & 9 deletions README.zh_CN.md
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@

# rrweb

**[rrweb 社区新的征程](http://www.myriptide.com/rrweb-community-cn/)**
**[rrweb 纪录片(中文)](https://www.bilibili.com/video/BV1wL4y1B7wN?share_source=copy_web)**

[![Join the chat at slack](https://img.shields.io/badge/[email protected]?logo=slack)](https://join.slack.com/t/rrweb/shared_invite/zt-siwoc6hx-uWay3s2wyG8t5GpZVb8rWg)
![total gzip size](https://img.badgesize.io/https://cdn.jsdelivr.net/npm/rrweb@latest/dist/rrweb.min.js?compression=gzip&label=total%20gzip%20size)
Expand All @@ -28,9 +28,9 @@ rrweb 是 'record and replay the web' 的简写,旨在利用现代浏览器所

rrweb 主要由 3 部分组成:

- **[rrweb-snapshot](https://github.com/rrweb-io/rrweb-snapshot)**,包含 snapshot 和 rebuild 两个功能。snapshot 用于将 DOM 及其状态转化为可序列化的数据结构并添加唯一标识;rebuild 则是将 snapshot 记录的数据结构重建为对应的 DOM。
- **[rrweb-snapshot](https://github.com/rrweb-io/rrweb/tree/master/packages/rrweb-snapshot/)**,包含 snapshot 和 rebuild 两个功能。snapshot 用于将 DOM 及其状态转化为可序列化的数据结构并添加唯一标识;rebuild 则是将 snapshot 记录的数据结构重建为对应的 DOM。
- **[rrweb](https://github.com/rrweb-io/rrweb)**,包含 record 和 replay 两个功能。record 用于记录 DOM 中的所有变更(mutation);replay 则是将记录的变更按照对应的时间一一重放。
- **[rrweb-player](https://github.com/rrweb-io/rrweb-player)**,为 rrweb 提供一套 UI 控件,提供基于 GUI 的暂停、快进、拖拽至任意时间点播放等功能。
- **[rrweb-player](https://github.com/rrweb-io/rrweb/tree/master/packages/rrweb-player/)**,为 rrweb 提供一套 UI 控件,提供基于 GUI 的暂停、快进、拖拽至任意时间点播放等功能。

## Roadmap

Expand Down Expand Up @@ -58,7 +58,7 @@ rrweb 主要由 3 部分组成:
[Typescript 手册](https://www.typescriptlang.org/docs/handbook/declaration-files/introduction.html)

1. Fork 需要修改的 rrweb 组件仓库
2. `npm install` 安装所需依赖
2. `yarn install` 安装所需依赖
3. 修改代码并通过测试
4. 提交代码,创建 pull request

Expand Down Expand Up @@ -115,8 +115,22 @@ rrweb 主要由 3 部分组成:

## Who's using rrweb

<p align="center">
<a href="http://www.smartx.com/" target="_blank">
<img width="260px" src="https://www.rrweb.io/logos/smartx.png">
</a>
</p>
<table>
<tr>
<td align="center">
<a href="http://www.smartx.com/" target="_blank">
<img width="260px" src="https://www.rrweb.io/logos/smartx.png">
</a>
</td>
<td align="center">
<a href="https://posthog.com?utm_source=rrweb&utm_medium=sponsorship&utm_campaign=open-source-sponsorship" target="_blank">
<img width="260px" src="https://www.rrweb.io/logos/posthog.png">
</a>
</td>
<td align="center">
<a href="https://statcounter.com/session-replay/" target="_blank">
<img width="260px" src="https://statcounter.com/images/logo-statcounter-arc-blue.svg">
</a>
</td>
</tr>
</table>
14 changes: 13 additions & 1 deletion docs/observer.md
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
# Incremental snapshots

After completing a full snapshot, we need to record events that change the state.

Right now, rrweb records the following events (we will expand upon this):
Expand All @@ -18,9 +19,11 @@ Right now, rrweb records the following events (we will expand upon this):
- Input

## Mutation Observer

Since we don't execute any JavaScript during replay, we instead need to record all changes scripts make to the document.

Consider this example:

> User clicks a button. A dropdown menu appears. User selects the first item. The dropdown menu disappears.
During replay, the dropdown menu does not automatically appear after the "click button" is executed, because the original JavaScript is not part of the recording. Thus, we need to record the creation of the dropdown menu DOM nodes, the selection of the first item, and subsequent deletion of the dropdown menu DOM nodes. This is the most difficult part.
Expand All @@ -33,9 +36,10 @@ The first thing to understand is that MutationObserver uses a **Bulk Asynchronou

This mechanism is not problematic for normal use, because we do not only have the mutation record, but we can also directly access the DOM object of the mutated node as well as any parent, child and sibling nodes.

However in rrweb, since we have a serialization process, we need more sophisticated soluation to be able to deal with various scenarios.
However in rrweb, since we have a serialization process, we need more sophisticated solution to be able to deal with various scenarios.

### Add node

For example, the following two operations generate the same DOM structure, but produce a different set of mutation records:

```
Expand Down Expand Up @@ -63,32 +67,40 @@ We already introduced in the [serialization design document](./serialization.md)
As you can see, since we have delayed serialization of the newly added nodes, all mutation records also need to be processed first, and only then the new nodes can be de-duplicated without causing trouble.

### Remove node

When processing mutation records, we may encounter a removed node that has not yet been serialized. That indicates that it is a newly added node, and the "add node" mutation record is also somewhere in the mutation records we received. We label these nodes as "dropped nodes".

There are two cases we need to handle here:

1. Since the node was removed already, there is no need to replay it, and thus we remove it from the newly added node pool.
2. This also applies to descendants of the dropped node, thus when processing newly added nodes we need to check if it has a dropped node as an ancestor.

### Attribute change

Although MutationObserver is an asynchronous batch callback, we can still assume that the time interval between mutations occurring in a callback is extremely short, so we can optimize the size of the incremental snapshot by overwriting some data when recording the DOM property changes.

For example, resizing a `<textarea>` will trigger a large number of mutation records with varying width and height properties. While a full record will make replay more realistic, it can also result in a large increase in the number of incremental snapshots. After making a trade-off, we think that only the final value of an attribute of the same node needs to be recorded in a single mutation callback, that is, each subsequent mutation record will overwrite the attribute change part of the mutation record that existing before the write.

## Mouse movement

By recording the mouse movement position, we can simulate the mouse movement trajectory during replay.

Try to ensure that the mouse moves smoothly during replay and also minimize the number of corresponding incremental snapshots, so we need to perform two layers of throttling while listening to mousemove. The first layer records the mouse coordinates at most once every 20 ms, the second layer transmits the mouse coordinate set at most once every 500 ms to ensure a single snapshot doesn't accumulate a lot of mouse position data and becomes too large.

### Time reversal

We record a timestamp when each incremental snapshot is generated so that during replay it can be applied at the correct time. However, due to the effect of throttling, the timestamps of the mouse movement corresponding to the incremental snapshot will be later than the actual recording time, so we need to record a negative time difference for correction and time calibration during replay.

## Input

We need to observe the input of the three elements `<input>`, `<textarea>`, `<select>`, including human input and programmatic changes.

### Human input

For human input, we mainly rely on listening to the input and change events. It is necessary to deduplicate different events triggered for the same the human input action. In addition, `<input type="radio" />` is also a special kind of control. If the multiple radio elements have the same name attribute, then when one is selected, the others will be reversed, but no event will be triggered on those others, so this needs to be handled separately.

### Programmatic changes

Setting the properties of these elements directly through the code will not trigger the MutationObserver. We can still achieve monitoring by hijacking the setter of the corresponding property. The sample code is as follows:

```typescript
Expand Down
Loading

0 comments on commit 73b87ca

Please sign in to comment.