From 2a809499480ae4f7118432f09871c5f75fda06d7 Mon Sep 17 00:00:00 2001
From: Justin Halsall
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 |
-| blockSelector | null | Use a string to configure which selector 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 |
-| ignoreCSSAttributes | null | array of CSS attributes that should be ignored |
-| maskTextClass | 'rr-mask' | Use a string or RegExp to configure which elements should be masked, refer to the [privacy](#privacy) chapter |
-| maskTextSelector | null | Use a string to configure which selector should be masked, refer to the [privacy](#privacy) chapter |
-| maskAllInputs | false | mask all input content as \* |
-| maskInputOptions | { password: true } | mask some kinds of input \*
refer to the [list](https://github.com/rrweb-io/rrweb/blob/588164aa12f1d94576f89ae0210b98f6e971c895/packages/rrweb-snapshot/src/types.ts#L77-L95) |
-| maskInputFn | - | customize mask input content recording logic |
-| maskTextFn | - | customize mask text content recording logic |
-| slimDOMOptions | {} | remove unnecessary parts of the DOM
refer to the [list](https://github.com/rrweb-io/rrweb/blob/588164aa12f1d94576f89ae0210b98f6e971c895/packages/rrweb-snapshot/src/types.ts#L97-L108) |
-| dataURLOptions | {} | Canvas image format and quality ,This parameter will be passed to the OffscreenCanvas.convertToBlob(),Using this parameter effectively reduces the size of the recorded data |
-| 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. Available options:
`false`,
`true` |
-| inlineImages | false | whether to record the image content |
-| collectFonts | false | whether to collect fonts in the website |
-| userTriggeredOnInput | false | whether to add `userTriggered` on input events that indicates if this event was triggered directly by the user or not. [What is `userTriggered`?](https://github.com/rrweb-io/rrweb/pull/495) |
-| plugins | [] | load plugins to provide extended record functions. [What is plugins?](./docs/recipes/plugin.md) |
+| 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 |
+| blockSelector | null | Use a string to configure which selector 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 |
+| ignoreCSSAttributes | null | array of CSS attributes that should be ignored |
+| maskTextClass | 'rr-mask' | Use a string or RegExp to configure which elements should be masked, refer to the [privacy](#privacy) chapter |
+| maskTextSelector | null | Use a string to configure which selector should be masked, refer to the [privacy](#privacy) chapter |
+| maskAllInputs | false | mask all input content as \* |
+| maskInputOptions | { password: true } | mask some kinds of input \*
refer to the [list](https://github.com/rrweb-io/rrweb/blob/588164aa12f1d94576f89ae0210b98f6e971c895/packages/rrweb-snapshot/src/types.ts#L77-L95) |
+| maskInputFn | - | customize mask input content recording logic |
+| maskTextFn | - | customize mask text content recording logic |
+| slimDOMOptions | {} | remove unnecessary parts of the DOM
refer to the [list](https://github.com/rrweb-io/rrweb/blob/588164aa12f1d94576f89ae0210b98f6e971c895/packages/rrweb-snapshot/src/types.ts#L97-L108) |
+| dataURLOptions | {} | Canvas image format and quality ,This parameter will be passed to the OffscreenCanvas.convertToBlob(),Using this parameter effectively reduces the size of the recorded data |
+| 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. Available options:
`false`,
`true` |
+| recordCrossOriginIframes | false | Whether to record cross origin iframes. rrweb has to be injected in each child iframe for this to work. Available options:
`false`,
`true` |
+| inlineImages | false | whether to record the image content |
+| collectFonts | false | whether to collect fonts in the website |
+| userTriggeredOnInput | false | whether to add `userTriggered` on input events that indicates if this event was triggered directly by the user or not. [What is `userTriggered`?](https://github.com/rrweb-io/rrweb/pull/495) |
+| plugins | [] | load plugins to provide extended record functions. [What is plugins?](./docs/recipes/plugin.md) |
#### Privacy
diff --git a/guide.zh_CN.md b/guide.zh_CN.md
index e867c93d..1093dbb3 100644
--- a/guide.zh_CN.md
+++ b/guide.zh_CN.md
@@ -131,32 +131,33 @@ setInterval(save, 10 * 1000);
`rrweb.record(config)` 的 config 部分接受以下参数
-| key | 默认值 | 功能 |
-| -------------------- | ------------------ | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
-| emit | 必填 | 获取当前录制的数据 |
-| checkoutEveryNth | - | 每 N 次事件重新制作一次全量快照
详见[“重新制作快照”](#重新制作快照)章节 |
-| checkoutEveryNms | - | 每 N 毫秒重新制作一次全量快照
详见[“重新制作快照”](#重新制作快照)章节 |
-| blockClass | 'rr-block' | 字符串或正则表达式,可用于自定义屏蔽元素的类名,详见[“隐私”](#隐私)章节 |
-| blockSelector | null | 所有 element.matches(blockSelector)为 true 的元素都不会被录制,回放时取而代之的是一个同等宽高的占位元素 |
-| ignoreClass | 'rr-ignore' | 字符串或正则表达式,可用于自定义忽略元素的类名,详见[“隐私”](#隐私)章节 |
-| ignoreCSSAttributes | null | 应该被忽略的 CSS 属性数组 |
-| maskTextClass | 'rr-mask' | 字符串或正则表达式,可用于自定义忽略元素 text 内容的类名,详见[“隐私”](#隐私)章节 |
-| maskTextSelector | null | 所有 element.matches(maskTextSelector)为 true 的元素及其子元素的 text 内容将会被屏蔽 |
-| maskAllInputs | false | 将所有输入内容记录为 \* |
-| maskInputOptions | { password: true } | 选择将特定类型的输入框内容记录为 \*
类型详见[列表](https://github.com/rrweb-io/rrweb/blob/588164aa12f1d94576f89ae0210b98f6e971c895/packages/rrweb-snapshot/src/types.ts#L77-L95) |
-| maskInputFn | - | 自定义特定类型的输入框内容记录逻辑 |
-| maskTextFn | - | 自定义文字内容的记录逻辑 |
-| slimDOMOptions | {} | 去除 DOM 中不必要的部分
类型详见[列表](https://github.com/rrweb-io/rrweb/blob/588164aa12f1d94576f89ae0210b98f6e971c895/packages/rrweb-snapshot/src/types.ts#L97-L108) |
-| inlineStylesheet | true | 是否将样式表内联 |
-| hooks | {} | 各类事件的回调
类型详见[列表](https://github.com/rrweb-io/rrweb/blob/9488deb6d54a5f04350c063d942da5e96ab74075/src/types.ts#L207) |
-| packFn | - | 数据压缩函数,详见[优化存储策略](./docs/recipes/optimize-storage.zh_CN.md) |
-| sampling | - | 数据抽样策略,详见[优化存储策略](./docs/recipes/optimize-storage.zh_CN.md) |
-| dataURLOptions | {} | Canvas 图像快照的格式和质量,这个参数将传递给 OffscreenCanvas.convertToBlob(),使用这个参数能有效减小录制数据的大小 |
-| recordCanvas | false | 是否记录 canvas 内容, 可用选项:false, true |
-| inlineImages | false | 是否将图片内容记内联录制 |
-| collectFonts | false | 是否记录页面中的字体文件 |
-| userTriggeredOnInput | false | [什么是 `userTriggered`](https://github.com/rrweb-io/rrweb/pull/495) |
-| plugins | [] | 加载插件以获得额外的录制功能. [什么是插件?](./docs/recipes/plugin.zh_CN.md) |
+| key | 默认值 | 功能 |
+| ------------------------ | ------------------ | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
+| emit | 必填 | 获取当前录制的数据 |
+| checkoutEveryNth | - | 每 N 次事件重新制作一次全量快照
详见[“重新制作快照”](#重新制作快照)章节 |
+| checkoutEveryNms | - | 每 N 毫秒重新制作一次全量快照
详见[“重新制作快照”](#重新制作快照)章节 |
+| blockClass | 'rr-block' | 字符串或正则表达式,可用于自定义屏蔽元素的类名,详见[“隐私”](#隐私)章节 |
+| blockSelector | null | 所有 element.matches(blockSelector)为 true 的元素都不会被录制,回放时取而代之的是一个同等宽高的占位元素 |
+| ignoreClass | 'rr-ignore' | 字符串或正则表达式,可用于自定义忽略元素的类名,详见[“隐私”](#隐私)章节 |
+| ignoreCSSAttributes | null | 应该被忽略的 CSS 属性数组 |
+| maskTextClass | 'rr-mask' | 字符串或正则表达式,可用于自定义忽略元素 text 内容的类名,详见[“隐私”](#隐私)章节 |
+| maskTextSelector | null | 所有 element.matches(maskTextSelector)为 true 的元素及其子元素的 text 内容将会被屏蔽 |
+| maskAllInputs | false | 将所有输入内容记录为 \* |
+| maskInputOptions | { password: true } | 选择将特定类型的输入框内容记录为 \*
类型详见[列表](https://github.com/rrweb-io/rrweb/blob/588164aa12f1d94576f89ae0210b98f6e971c895/packages/rrweb-snapshot/src/types.ts#L77-L95) |
+| maskInputFn | - | 自定义特定类型的输入框内容记录逻辑 |
+| maskTextFn | - | 自定义文字内容的记录逻辑 |
+| slimDOMOptions | {} | 去除 DOM 中不必要的部分
类型详见[列表](https://github.com/rrweb-io/rrweb/blob/588164aa12f1d94576f89ae0210b98f6e971c895/packages/rrweb-snapshot/src/types.ts#L97-L108) |
+| inlineStylesheet | true | 是否将样式表内联 |
+| hooks | {} | 各类事件的回调
类型详见[列表](https://github.com/rrweb-io/rrweb/blob/9488deb6d54a5f04350c063d942da5e96ab74075/src/types.ts#L207) |
+| packFn | - | 数据压缩函数,详见[优化存储策略](./docs/recipes/optimize-storage.zh_CN.md) |
+| sampling | - | 数据抽样策略,详见[优化存储策略](./docs/recipes/optimize-storage.zh_CN.md) |
+| dataURLOptions | {} | Canvas 图像快照的格式和质量,这个参数将传递给 OffscreenCanvas.convertToBlob(),使用这个参数能有效减小录制数据的大小 |
+| recordCanvas | false | 是否记录 canvas 内容, 可用选项:`false`, `true` |
+| recordCrossOriginIframes | false | 是否记录 cross origin iframes。 必须在每个子 iframe 中注入 rrweb 才能使其工作。 可用选项:`false`, `true` |
+| inlineImages | false | 是否将图片内容记内联录制 |
+| collectFonts | false | 是否记录页面中的字体文件 |
+| userTriggeredOnInput | false | [什么是 `userTriggered`](https://github.com/rrweb-io/rrweb/pull/495) |
+| plugins | [] | 加载插件以获得额外的录制功能. [什么是插件?](./docs/recipes/plugin.zh_CN.md) |
#### 隐私
diff --git a/package.json b/package.json
index 66ae51cc..71921302 100644
--- a/package.json
+++ b/package.json
@@ -25,7 +25,7 @@
"concurrently": "^7.1.0",
"eslint": "^8.19.0",
"eslint-plugin-compat": "^4.0.2",
- "eslint-plugin-jest": "^26.5.3",
+ "eslint-plugin-jest": "^27.1.3",
"eslint-plugin-tsdoc": "^0.2.16",
"lerna": "^4.0.0",
"markdownlint": "^0.25.1",
diff --git a/packages/rrweb-player/typings/index.d.ts b/packages/rrweb-player/typings/index.d.ts
index c3c3b802..b27799aa 100755
--- a/packages/rrweb-player/typings/index.d.ts
+++ b/packages/rrweb-player/typings/index.d.ts
@@ -1,5 +1,5 @@
import { playerConfig } from 'rrweb/typings/types';
-import type { eventWithTime } from '@rrweb/types';
+import { eventWithTime } from '@rrweb/types';
import { Replayer, mirror } from 'rrweb';
import { SvelteComponent } from 'svelte';
diff --git a/packages/rrweb-snapshot/src/index.ts b/packages/rrweb-snapshot/src/index.ts
index 82dd6a42..b2417187 100644
--- a/packages/rrweb-snapshot/src/index.ts
+++ b/packages/rrweb-snapshot/src/index.ts
@@ -6,6 +6,7 @@ import snapshot, {
needMaskingText,
classMatchesRegex,
IGNORED_NODE,
+ genId,
} from './snapshot';
import rebuild, {
buildNodeWithSN,
@@ -28,4 +29,5 @@ export {
needMaskingText,
classMatchesRegex,
IGNORED_NODE,
+ genId,
};
diff --git a/packages/rrweb-snapshot/src/snapshot.ts b/packages/rrweb-snapshot/src/snapshot.ts
index 37080015..99a23ff7 100644
--- a/packages/rrweb-snapshot/src/snapshot.ts
+++ b/packages/rrweb-snapshot/src/snapshot.ts
@@ -27,7 +27,7 @@ const tagNameRegex = new RegExp('[^a-z0-9-_:]');
export const IGNORED_NODE = -2;
-function genId(): number {
+export function genId(): number {
return _id++;
}
diff --git a/packages/rrweb/package.json b/packages/rrweb/package.json
index a51c2af1..8e09e593 100644
--- a/packages/rrweb/package.json
+++ b/packages/rrweb/package.json
@@ -50,7 +50,7 @@
"@types/dom-mediacapture-transform": "^0.1.3",
"@types/inquirer": "^8.2.1",
"@types/jest": "^27.4.1",
- "@types/jest-image-snapshot": "^4.3.1",
+ "@types/jest-image-snapshot": "^5.1.0",
"@types/node": "^17.0.21",
"@types/offscreencanvas": "^2019.6.4",
"@types/prettier": "^2.3.2",
@@ -63,10 +63,10 @@
"ignore-styles": "^5.0.1",
"inquirer": "^9.0.0",
"jest": "^27.5.1",
- "jest-image-snapshot": "^4.5.1",
+ "jest-image-snapshot": "^5.2.0",
"jest-snapshot": "^23.6.0",
"prettier": "2.2.1",
- "puppeteer": "^9.1.1",
+ "puppeteer": "^11.0.0",
"rollup": "^2.68.0",
"rollup-plugin-esbuild": "^4.9.1",
"rollup-plugin-postcss": "^3.1.1",
diff --git a/packages/rrweb/scripts/repl.js b/packages/rrweb/scripts/repl.js
index 4edb07a3..0bf4a7de 100644
--- a/packages/rrweb/scripts/repl.js
+++ b/packages/rrweb/scripts/repl.js
@@ -21,6 +21,43 @@ void (async () => {
const code = getCode();
let events = [];
+ async function injectRecording(frame) {
+ await frame.evaluate((rrwebCode) => {
+ const win = window;
+ if (win.__IS_RECORDING__) return;
+ win.__IS_RECORDING__ = true;
+
+ (async () => {
+ function loadScript(code) {
+ const s = document.createElement('script');
+ let r = false;
+ s.type = 'text/javascript';
+ s.innerHTML = code;
+ if (document.head) {
+ document.head.append(s);
+ } else {
+ requestAnimationFrame(() => {
+ document.head.append(s);
+ });
+ }
+ }
+ loadScript(rrwebCode);
+
+ win.events = [];
+ rrweb.record({
+ emit: (event) => {
+ win.events.push(event);
+ win._replLog(event);
+ },
+ plugins: [],
+ recordCanvas: true,
+ recordCrossOriginIframes: true,
+ collectFonts: true,
+ });
+ })();
+ }, code);
+ }
+
await start('https://react-redux.realworld.io');
const fakeGoto = async (page, url) => {
@@ -44,8 +81,7 @@ void (async () => {
{
type: 'input',
name: 'url',
- message:
- `Enter the url you want to record, e.g [${defaultURL}]: `,
+ message: `Enter the url you want to record, e.g [${defaultURL}]: `,
},
]);
@@ -116,34 +152,18 @@ void (async () => {
],
});
const page = await browser.newPage();
- await page.goto(url, {
- waitUntil: 'domcontentloaded',
- timeout: 300000,
- });
await page.exposeFunction('_replLog', (event) => {
events.push(event);
});
- await page.evaluate(`;${code}
- window.__IS_RECORDING__ = true
- rrweb.record({
- emit: event => window._replLog(event),
- recordCanvas: true,
- collectFonts: true
- });
- `);
- page.on('framenavigated', async () => {
- const isRecording = await page.evaluate('window.__IS_RECORDING__');
- if (!isRecording) {
- await page.evaluate(`;${code}
- window.__IS_RECORDING__ = true
- rrweb.record({
- emit: event => window._replLog(event),
- recordCanvas: true,
- collectFonts: true
- });
- `);
- }
+
+ page.on('framenavigated', async (frame) => {
+ await injectRecording(frame);
+ });
+
+ await page.goto(url, {
+ waitUntil: 'domcontentloaded',
+ timeout: 300000,
});
emitter.once('done', async (shouldReplay) => {
@@ -211,9 +231,9 @@ void (async () => {
-
-
- Verify that block class bugs are fixed
-
-
+
+ Verify that block class bugs are fixed
+
+
+
+
+
+
diff --git a/packages/rrweb/test/html/hello-world.html b/packages/rrweb/test/html/hello-world.html new file mode 100644 index 00000000..04c1907d --- /dev/null +++ b/packages/rrweb/test/html/hello-world.html @@ -0,0 +1,12 @@ + + +
+ + + +
+ +
+