Skip to content
Merged
Show file tree
Hide file tree
Changes from 1 commit
Commits
Show all changes
72 commits
Select commit Hold shift + click to select a range
42009f3
inline stylesheets when loaded
Juice10 May 31, 2022
b9ddfae
set empty link elements to loaded by default
Juice10 Jun 1, 2022
4c10804
Clean up stylesheet manager
Juice10 Jun 1, 2022
e9f8e06
Remove attribute mutation code
Juice10 Jun 2, 2022
c11e052
Update packages/rrweb/test/record.test.ts
Juice10 Jun 7, 2022
244a26a
Update packages/rrweb/test/record.test.ts
Juice10 Jun 7, 2022
1edb1ea
Update packages/rrweb/test/record.test.ts
Juice10 Jun 7, 2022
45bafbd
Merge branch 'master' of https://github.com/rrweb-io/rrweb into seria…
Juice10 Jun 7, 2022
401c503
Update packages/rrweb/scripts/repl.js
Juice10 Jun 7, 2022
2ec406b
Update packages/rrweb/test/record.test.ts
Juice10 Jun 7, 2022
2e8492e
Update packages/rrweb/src/record/index.ts
Juice10 Jun 7, 2022
217bd7c
Add todo
Juice10 Jun 7, 2022
c0371f0
Move require out of time sensitive assert
Juice10 Jun 7, 2022
fd38d43
Merge branch 'serialize-stylesheet-contents' of https://github.com/rr…
Juice10 Jun 7, 2022
dee14a6
Add waitForRAF, its more reliable than waitForTimeout
Juice10 Jun 7, 2022
1965152
Remove flaky tests
Juice10 Jun 7, 2022
8ff7bc6
Add recording stylesheets in iframes
Juice10 Jun 7, 2022
d5a83be
Remove variability from flaky test
Juice10 Jun 7, 2022
7e3a1a8
Make test more robust
Juice10 Jun 7, 2022
8c7a38f
Fix naming
Juice10 Jun 27, 2022
6878711
Merge branch 'master' of https://github.com/rrweb-io/rrweb into seria…
Juice10 Jun 27, 2022
d2cb411
Add test cases for inlineImages
Juice10 Jun 29, 2022
18c4475
Add test cases for inlineImages
Juice10 Jun 29, 2022
9efecfe
Merge branch 'inline-image-test-cases' of https://github.com/rrweb-io…
Juice10 Jun 30, 2022
da245bd
Record iframe mutations cross page
Juice10 Jun 30, 2022
be618d3
Test: should record images inside iframe with blob url after iframe w…
Juice10 Jun 30, 2022
9fc54b4
Merge branch 'master' of https://github.com/rrweb-io/rrweb into inlin…
Juice10 Jul 1, 2022
d63a529
Handle negative ids in rrdom correctly
Juice10 Jul 1, 2022
83102f0
Update packages/rrdom/src/diff.ts
Juice10 Jul 25, 2022
f872f76
Merge branch 'master' into rrdom-negative-ids
Juice10 Jul 25, 2022
3cabbf7
Start unserialized nodes at -2
Juice10 Jul 25, 2022
3a8ce08
Set unserialized id starting number at -2
Juice10 Jul 25, 2022
14179d6
Remove duplication
Juice10 Jul 25, 2022
7317ac3
Use turbo instead of lerna
Juice10 Jul 26, 2022
7cbb307
Skip benchmark as it is unreliable when executed in parallel
Juice10 Jul 26, 2022
eed8174
Strip port number from serialization, it can vary
Juice10 Jul 26, 2022
b43fafb
Add settimeout to virtual dom test
Juice10 Jul 26, 2022
c093928
Remove console.log and refactor blob:url serialization
Juice10 Jul 26, 2022
23c8711
Include references in tsconfig to indicate which monorepo packages ar…
Juice10 Jul 26, 2022
5006ed4
Add stream setup
Juice10 Jul 26, 2022
9291a05
Migrate project to es module
Juice10 Jul 27, 2022
f66b1c2
Add reference to rrweb from rrdom
Juice10 Jul 28, 2022
9599257
Move jest config to ESM
Juice10 Jul 28, 2022
bb1c5c5
Setup basic WebRTC canvas streaming
Juice10 Jul 28, 2022
03b6b28
Cleanup and refactor WebRTC streaming
Juice10 Jul 28, 2022
48a4ad3
Remove ? which isn't propper javascript
Juice10 Aug 22, 2022
05300fd
Yarn lock
Juice10 Aug 22, 2022
9be9176
Remove webrtc code from rrweb
Juice10 Aug 25, 2022
9925f07
Add plugin hooks
Juice10 Aug 25, 2022
7b768c7
Expose plugins with server
Juice10 Aug 25, 2022
678bd60
Use unminified version for tests
Juice10 Aug 25, 2022
9df08ea
Don't include simple-peer in rrweb main project
Juice10 Aug 25, 2022
e913c03
Add canvas webrtc plugin
Juice10 Aug 25, 2022
17164b2
Merge branch 'master' into live-stream
Juice10 Aug 25, 2022
22a5c1d
ignore tsconfig.tsbuildinfo
Juice10 Aug 25, 2022
b2065d6
Cleanup unused code
Juice10 Aug 25, 2022
41e3775
type definition files are no longer committed
Juice10 Aug 25, 2022
5ea10d7
Devtools off by default
Juice10 Aug 25, 2022
0d807e0
Extract .css into its own file
Juice10 Aug 25, 2022
43a73ed
Refactor plugin apis and fix multi canvas streaming support
Juice10 Aug 26, 2022
da14368
Add readme to rrweb canvas webrtc plugin
Juice10 Aug 26, 2022
9d950fa
Reference canvas-webrtc plugin in documentation
Juice10 Aug 26, 2022
39b6d22
Forbidden non-null assertion
Juice10 Aug 26, 2022
bc0bf13
Remove linting of each project, yarn lint:report will do this
Juice10 Aug 26, 2022
29964f5
Remove test code
Juice10 Aug 26, 2022
28c4744
Cut down line length
Juice10 Aug 26, 2022
fb0be78
Merge branch 'master' into live-stream
YunFeng0817 Sep 13, 2022
2919a20
fix CI failure and improve the zh_CN doc
YunFeng0817 Sep 13, 2022
c65bef0
Update packages/rrweb/src/plugins/canvas-webrtc/replay/index.ts
Juice10 Sep 14, 2022
0fbecb9
Cleaner styling of replay
Juice10 Sep 14, 2022
1e83835
Clean up stream.js based on @Mark-Fenng's feedback
Juice10 Sep 14, 2022
20f5f62
Remove duplicate send
Juice10 Sep 14, 2022
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Prev Previous commit
Next Next commit
Merge branch 'master' into live-stream
  • Loading branch information
YunFeng0817 committed Sep 13, 2022
commit fb0be7833b7976663bd201349a15e95c5b4c410e
50 changes: 0 additions & 50 deletions .github/workflows/eslint.yml

This file was deleted.

95 changes: 95 additions & 0 deletions .github/workflows/style-check.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,95 @@
name: Code Style Check

on: [push, pull_request_target]

jobs:
eslint_check_upload:
runs-on: ubuntu-latest
name: ESLint Check and Report Upload

steps:
- uses: actions/checkout@v3
with:
repository: ${{ github.event.pull_request.head.repo.full_name }}
ref: ${{ github.head_ref }}
- name: Setup Node
uses: actions/setup-node@v3
with:
node-version: 16
cache: 'yarn'
- name: Install Dependencies
run: yarn
- name: Build Packages
run: yarn build:all
- name: Eslint Check
run: yarn turbo run lint
- name: Save Code Linting Report JSON
run: yarn lint:report
# Continue to the next step even if this fails
continue-on-error: true
- name: Upload ESLint report
uses: actions/upload-artifact@v3
with:
name: eslint_report.json
path: eslint_report.json

annotation:
# Skip the annotation action in push events
if: github.event_name == 'pull_request_target'
needs: eslint_check_upload
runs-on: ubuntu-latest
name: ESLint Annotation
steps:
- uses: actions/download-artifact@v3
with:
name: eslint_report.json
- name: Annotate Code Linting Results
uses: ataylorme/eslint-annotate-action@v2
with:
repo-token: '${{ secrets.GITHUB_TOKEN }}'
report-json: 'eslint_report.json'

prettier_check:
# In the forked PR, it's hard to format code and push to the branch directly.
if: github.event_name != 'push' && github.event.pull_request.head.repo.full_name != 'rrweb-io/rrweb'
runs-on: ubuntu-latest
name: Format Check
steps:
- uses: actions/checkout@v3
with:
repository: ${{ github.event.pull_request.head.repo.full_name }}
ref: ${{ github.head_ref }}
- name: Setup Node
uses: actions/setup-node@v3
with:
node-version: 16
cache: 'yarn'
- name: Install Dependencies
run: yarn
- name: Prettify code
run: yarn prettier --check '**/*.{ts,md}'

prettier:
# Skip the format code action in forked PRs
if: github.event_name == 'push' || github.event.pull_request.head.repo.full_name == 'rrweb-io/rrweb'
runs-on: ubuntu-latest
name: Format Code
steps:
- uses: actions/checkout@v3
with:
repository: ${{ github.event.pull_request.head.repo.full_name }}
ref: ${{ github.head_ref }}
- name: Setup Node
uses: actions/setup-node@v3
with:
node-version: 16
cache: 'yarn'
- name: Install Dependencies
run: yarn
- name: Prettify code
run: yarn prettier --write '**/*.{ts,md}'
- name: Commit changes
uses: stefanzweifel/git-auto-commit-action@v4
with:
commit_message: Apply formatting changes
branch: ${{ github.head_ref }}
2 changes: 1 addition & 1 deletion .release-it.json
Original file line number Diff line number Diff line change
Expand Up @@ -12,4 +12,4 @@
"release": true,
"releaseName": "Release ${version}"
}
}
}
22 changes: 11 additions & 11 deletions CODE_OF_CONDUCT.md
Original file line number Diff line number Diff line change
Expand Up @@ -17,23 +17,23 @@ diverse, inclusive, and healthy community.
Examples of behavior that contributes to a positive environment for our
community include:

* Demonstrating empathy and kindness toward other people
* Being respectful of differing opinions, viewpoints, and experiences
* Giving and gracefully accepting constructive feedback
* Accepting responsibility and apologizing to those affected by our mistakes,
- Demonstrating empathy and kindness toward other people
- Being respectful of differing opinions, viewpoints, and experiences
- Giving and gracefully accepting constructive feedback
- Accepting responsibility and apologizing to those affected by our mistakes,
and learning from the experience
* Focusing on what is best not just for us as individuals, but for the
- Focusing on what is best not just for us as individuals, but for the
overall community

Examples of unacceptable behavior include:

* The use of sexualized language or imagery, and sexual attention or
- The use of sexualized language or imagery, and sexual attention or
advances of any kind
* Trolling, insulting or derogatory comments, and personal or political attacks
* Public or private harassment
* Publishing others' private information, such as a physical or email
- Trolling, insulting or derogatory comments, and personal or political attacks
- Public or private harassment
- Publishing others' private information, such as a physical or email
address, without their explicit permission
* Other conduct which could reasonably be considered inappropriate in a
- Other conduct which could reasonably be considered inappropriate in a
professional setting

## Enforcement Responsibilities
Expand Down Expand Up @@ -106,7 +106,7 @@ Violating these terms may lead to a permanent ban.
### 4. Permanent Ban

**Community Impact**: Demonstrating a pattern of violation of community
standards, including sustained inappropriate behavior, harassment of an
standards, including sustained inappropriate behavior, harassment of an
individual, or aggression toward or disparagement of classes of individuals.

**Consequence**: A permanent ban from any sort of public interaction within
Expand Down
6 changes: 6 additions & 0 deletions CONTRIBUTING.md
Original file line number Diff line number Diff line change
@@ -1,24 +1,30 @@
# Contributing to rrweb

We want to make contributing to this project as easy and transparent as
possible.

## Our Development Process

The majority of development on rrweb will occur through GitHub. Accordingly,
the process for contributing will follow standard GitHub protocol.

## Pull Requests

We actively welcome your pull requests.

1. Fork the repo and create your branch from `master`.
2. If you've added code that should be tested, add tests
3. If you've changed APIs, update the documentation.
4. Ensure the test suite passes.
5. Make sure your code lints and typechecks.

## Issues

We use GitHub issues to track public bugs. Please ensure your description is
clear and has sufficient instructions to be able to reproduce the issue.

## License

rrweb is [MIT licensed](https://github.com/rrweb-io/rrweb/blob/master/LICENSE).

By contributing to rrweb, you agree that your contributions will be licensed
Expand Down
6 changes: 3 additions & 3 deletions docs/observer.zh_CN.md
Original file line number Diff line number Diff line change
Expand Up @@ -57,8 +57,8 @@ body

在[序列化设计](./serialization.zh_CN.md)中已经介绍了我们需要维护一个 `id -> Node` 的映射,因此当出现新增节点时,我们需要将新节点序列化并加入映射中。但由于我们为了去重新增节点,选择在所有 mutation 记录遍历完毕之后才进行序列化,在以下示例中就会出现问题:

1. mutation 记录1,新增节点 n1。我们暂不处理,等待最终去重后序列化。
2. mutation 记录2,n1 新增属性 a1。我们试图将它记录成一次增量快照,但会发现无法从映射中找到 n1 对应的 id,因为此时它还未被序列化。
1. mutation 记录 1,新增节点 n1。我们暂不处理,等待最终去重后序列化。
2. mutation 记录 2,n1 新增属性 a1。我们试图将它记录成一次增量快照,但会发现无法从映射中找到 n1 对应的 id,因为此时它还未被序列化。

由此可见,由于我们对新增节点进行了延迟序列化的处理,所有 mutation 记录也都需要先收集,再新增节点去重并序列化之后再做处理。

Expand Down Expand Up @@ -119,4 +119,4 @@ function hookSetter<T>(
}
```

注意为了避免我们在 setter 中的逻辑阻塞被录制页面的正常交互,我们应该把逻辑放入 event loop 中异步执行。
注意为了避免我们在 setter 中的逻辑阻塞被录制页面的正常交互,我们应该把逻辑放入 event loop 中异步执行。
7 changes: 3 additions & 4 deletions docs/recipes/record-and-replay.zh_CN.md
Original file line number Diff line number Diff line change
Expand Up @@ -8,8 +8,8 @@
const stopFn = rrweb.record({
emit(event) {
// 保存获取到的 event 数据
}
})
},
});
```

你可以使用任何方式保存录制的数据,例如通过网络请求将数据传入至后端持久化保存,但请确保:
Expand All @@ -22,9 +22,8 @@ const stopFn = rrweb.record({
回放时只需要获取一段录制数据,并传入 rrweb 提供的 Replayer:

```js
const events = GET_YOUR_EVENTS
const events = GET_YOUR_EVENTS;

const replayer = new rrweb.Replayer(events);
replayer.play();
```

5 changes: 5 additions & 0 deletions docs/replay.md
Original file line number Diff line number Diff line change
@@ -1,7 +1,9 @@
# Replay

A design principle of rrweb is to process as little as possible on the recording side, minimizing the impact on the recorded page. This means we need to do some special processing on the replay side.

## High precision timer

During replay, we will get the complete snapshot chain at one time. If all the snapshots are executed in sequence, we can directly get the last state of the recorded page, but what we need is to synchronously initialize the first full snapshot, and then apply the remaining incremental snapshots asynchronously. Using a time interval we replay each incremental snapshot one after the other, which requires a high-precision timer.

The reason why **high precision** is emphasized is because the native `setTimeout` does not guarantee accurate execution after the set delay time, for example, when the main thread is blocked.
Expand All @@ -11,6 +13,7 @@ For our replay function, this imprecise delay is unacceptable and can lead to va
At the same time, the custom timer is also the basis for our "fast forward" function.

## Completing missing nodes

The delay serialization strategy when rrweb uses MutationObserver is mentioned in the [incremental snapshot design](./observer.md), which may result in the following scenarios where we cannot record a full incremental snapshot:

```
Expand All @@ -29,6 +32,7 @@ During replay, when we process the incremental snapshot of the new `foo`, we kno
After processing the incremental snapshot of the new n1, we normally process and insert `bar`. After the replay is completed, we check whether the neighbor node id of `foo` points to a node which is in the missing node pool. If it matches, then it will be removed from the pool and be inserted into the DOM tree.

## Simulation Hover

CSS styles for the `:hover` selector are present in many web pages, but we can't trigger the hover state via JavaScript. So when playing back we need to simulate the hover state to make the style display correctly.

The specific method includes two parts:
Expand All @@ -37,6 +41,7 @@ The specific method includes two parts:
2. When playing back the mouse up mouse interaction event, add the `.:hover` class name to the event target and all its ancestors, and remove it when the mouse moves away again.

## Play from any point in time

In addition to the basic replay features, we also want players like `rrweb-player` to provide similar functionality to video players, such as dragging and dropping to the progress bar to any point in time.

In actual implementation, we pass a start time to the method. We can then divide the snapshot chain into two parts: The parts before and the part after the start time. Then, the snapshot chain before the start time is executed synchronously, and then the snapshot chain after the starting times uses the normal asynchronous execution. This way we can achieve starting replay from any point in time.
3 changes: 3 additions & 0 deletions docs/sandbox.md
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ In the [serialization design](./serialization.md) we mentioned the "de-scripting
There are many kinds of scripting behaviors. A filtering approach to getting rid of these scripts will never be a complete solution, and once a script slips through and is executed, it may cause irreversible unintended consequences. So we use the iframe sandbox feature provided by HTML for browser-level restrictions.

## iframe sandbox

We reconstruct the recorded DOM in an `iframe` element when we rebuild the snapshot. By setting its `sandbox` attribute, we can disable the following behavior:

- Form submission
Expand All @@ -14,13 +15,15 @@ We reconstruct the recorded DOM in an `iframe` element when we rebuild the snaps
This is in line with our expectations, especially when dealing with JS scripts is safer and more reliable than implementing this security ourselves.

## Avoid link jumps

When you click the a element link, the default event is to jump to the URL corresponding to its href attribute. During replay, we will ensure visually correct replay by rebuilding the page DOM after the jump, and the original jump should be prohibited.

Usually we will capture all an elements click events through the event handler proxy and disable the default event via `event.preventDefault()`. But when we put the replay page in the sandbox, all the event handlers will not be executed, and we will not be able to implement the event delegation.

When replaying interactive events, note that replaying the JS `click` event is not nessecary because click events do not have any impact when JS is disabled. However, in order to optimize the replay effect, we can add special animation effects to visualize elements being clicked with the mouse, to clearly show the viewer that a click has occurred.

## iframe style settings

Since we're rebuilding the DOM in an iframe, we can't affect the elements in the iframe through the CSS stylesheet of the parent page. But if JS scripts are not allowed to execute, the `noscript` tag will be displayed, and we want to hide it. So we need to dynamically add styles to the iframe. The sample code is as follows:

```typescript
Expand Down
2 changes: 1 addition & 1 deletion docs/sandbox.zh_CN.md
Original file line number Diff line number Diff line change
Expand Up @@ -42,4 +42,4 @@ for (let idx = 0; idx < injectStyleRules.length; idx++) {
}
```

需要注意的是这个插入的 style 元素在被录制页面中并不存在,所以我们不能将其序列化,否则 `id -> Node` 的映射将出现错误。
需要注意的是这个插入的 style 元素在被录制页面中并不存在,所以我们不能将其序列化,否则 `id -> Node` 的映射将出现错误。
12 changes: 7 additions & 5 deletions docs/serialization.md
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
# Serialization

If you only need to record and replay changes within the browser locally, then we can simply save the current view by deep copying the DOM object. For example, the following code implementation (simplified example with jQuery, saves only the body part):

```javascript
Expand All @@ -18,6 +19,7 @@ We do not use an existing open source solutions such as [parse5](https://github.
2. This part of the code needs to run on the recorded page, and we want to control the amount of code as much as possible, only retaining the necessary functions.

## Special handling in serialization

The reason why our serialization method is non-standard is because we still need to do the following parts:

1. Output needs to be descriptive. All JavaScript in the original recorded page should not be executed on replay. In rrweb we do this by replacing `script` tags with placeholder `noscript` tags in snapshots. The content inside the script is no longer important. We instead record any changes to the DOM that scripts cause, and we ​​do not need to fully record large amounts of script content that may be present on the original web page.
Expand All @@ -26,15 +28,15 @@ The reason why our serialization method is non-standard is because we still need
4. We want to record the contents of the CSS style sheet. If the recorded page links to external style sheets, we can get its parsed CSS rules from the browser, generate an inline style sheet containing all these rules. This way stylesheets that are not always accessible (for example, because they are located on an intranet or localhost) are included in the recording and can be replayed correctly.

## Uniquely identifies

At the same time, our serialization should also include both full and incremental types. Full serialization can transform a DOM tree into a corresponding tree data structure.

For example, the following DOM tree:

```html
<html>
<body>
<header>
</header>
<header></header>
</body>
</html>
```
Expand Down Expand Up @@ -98,12 +100,12 @@ There are two things to note in this serialization result:

Imagine if we recorded the click of a button on the same page and played it back, we can record the operation in the following format (that is what we call an incremental snapshot):

```javascript
```typescript
type clickSnapshot = {
source: 'MouseInteraction';
type: 'Click';
node: HTMLButtonElement;
}
};
```

The operation can be executed again by `snapshot.node.click()`.
Expand All @@ -119,5 +121,5 @@ type clickSnapshot = {
source: 'MouseInteraction';
type: 'Click';
id: Number;
}
};
```
Loading
You are viewing a condensed version of this merge commit. You can view the full changes here.