From 8c17ef02ec479354a95df03556e79d49e59937ed Mon Sep 17 00:00:00 2001 From: Yanzhen Yu Date: Wed, 1 Apr 2026 12:00:00 +0800 Subject: [PATCH] add plugin API recipe --- docs/recipes/index.md | 10 +++- docs/recipes/index.zh_CN.md | 12 +++-- docs/recipes/plugin.md | 99 ++++++++++++++++++++++++++++++++++++ docs/recipes/plugin.zh_CN.md | 99 ++++++++++++++++++++++++++++++++++++ 4 files changed, 215 insertions(+), 5 deletions(-) create mode 100644 docs/recipes/plugin.md create mode 100644 docs/recipes/plugin.zh_CN.md diff --git a/docs/recipes/index.md b/docs/recipes/index.md index 4aefd08d..aab31d0d 100644 --- a/docs/recipes/index.md +++ b/docs/recipes/index.md @@ -68,7 +68,13 @@ Canvas is a special HTML element, which will not be recorded by rrweb by default ### Console Recorder and Replayer -Starting with a later version of v0.9.11, we add the ability to record and play back console output. +Starting with a later version of v0.9.11, we add the ability to record and play back console output. This feature aims to provide developers with more information about the bug scene. There are some options for recording and replaying console output. -[link](./console.md) \ No newline at end of file +[link](./console.md) + +### Plugin + +The plugin API is designed to extend the function of rrweb without bump the size and complexity of rrweb's core part. + +[link](./plugin.md) diff --git a/docs/recipes/index.zh_CN.md b/docs/recipes/index.zh_CN.md index 76c1d150..bc07dd5f 100644 --- a/docs/recipes/index.zh_CN.md +++ b/docs/recipes/index.zh_CN.md @@ -64,8 +64,14 @@ Canvas 是一种特殊的 HTML 元素,默认情况下其内容不会被 rrweb [链接](./canvas.zh_CN.md) -### console录制和播放 +### console 录制和播放 -从v0.9.11的下一个版本开始,我们增加了录制和播放控制台输出的功能。这个功能旨在为开发者提供更多的bug信息。对这项功能我们还提供了一些设置选项。 +从 v0.9.11 的下一个版本开始,我们增加了录制和播放控制台输出的功能。这个功能旨在为开发者提供更多的 bug 信息。对这项功能我们还提供了一些设置选项。 -[链接](./console.zh_CN.md) \ No newline at end of file +[链接](./console.zh_CN.md) + +### 插件 + +插件 API 的设计目标是在不增加 rrweb 核心部分大小和复杂性的前提下,扩展 rrweb 的功能。 + +[链接](./plugin.zh_CN.md) diff --git a/docs/recipes/plugin.md b/docs/recipes/plugin.md new file mode 100644 index 00000000..b3fea119 --- /dev/null +++ b/docs/recipes/plugin.md @@ -0,0 +1,99 @@ +# Plugin + +The plugin API is designed to extend the function of rrweb without bump the size and complexity of rrweb's core part. + +## Interface + +Same to with other functionality in rrweb, a plugin can implement record or replay or both features. + +```ts +export type RecordPlugin = { + name: string; + observer: (cb: Function, options: TOptions) => listenerHandler; + options: TOptions; +}; + +export type ReplayPlugin = { + handler: ( + event: eventWithTime, + isSync: boolean, + context: { replayer: Replayer }, + ) => void; +}; +``` + +Both record and replay plugins have a type interface. + +### example + +#### record plugin + +```ts +const exampleRecordPlugin: RecordPlugin<{ foo: string }> = { + name: 'my-scope/example@1', + observer(cb, options) { + const timer = setInterval(() => { + cb({ + foo: options.foo, + timestamp: Date.now(), + }); + }, 1000); + return () => clearInterval(timer); + }, + options: { + foo: 'bar', + }, +}; + +rrweb.record({ + emit: emit(event) {}, + plugins: [exampleRecordPlugin], +}); +``` + +In this example, the record plugin will emit events like this: + +```js +{ + type: 6, + data: { + plugin: 'my-scope/example@1', + payload: { + foo: 'bar', + timestamp: 1624693882345, + }, + }, + timestamp: 1624693882345, +} +``` + +#### replay plugin + +```ts +const exampleReplayPlugin: ReplayPlugin = { + handler(event, isSync, context) { + if (event.type === EventType.Plugin) { + // do something with event.data.payload + if (event.data.plugin === 'my-scope/example@1') { + // handle example plugin data + } + } + }, +}; + +const replayer = new rrweb.Replayer(events, { + plugins: [exampleReplayPlugin], +}); +``` + +A replay plugin can interact with the replayer by using `context.replayer`. + +## naming a plugin + +A record plugin should have a unique name, and it will be stored in the event it emits. + +**Since we will have both plugins in the rrweb repo and plugins in users' own codebase, which may cause naming conflicts in the future, we strongly recommended users naming their own plugins in this way:** + +> scope/name@version + +For example `rrweb/console@1` or `github/pr@2`. diff --git a/docs/recipes/plugin.zh_CN.md b/docs/recipes/plugin.zh_CN.md new file mode 100644 index 00000000..6918ab71 --- /dev/null +++ b/docs/recipes/plugin.zh_CN.md @@ -0,0 +1,99 @@ +# 插件 + +插件 API 的设计目标是在不增加 rrweb 核心部分大小和复杂性的前提下,扩展 rrweb 的功能。 + +## 接口 + +与 rrweb 其它功能相似,插件可以包含同时包含录制、回放侧的功能,也可以只实现其中任一。 + +```ts +export type RecordPlugin = { + name: string; + observer: (cb: Function, options: TOptions) => listenerHandler; + options: TOptions; +}; + +export type ReplayPlugin = { + handler: ( + event: eventWithTime, + isSync: boolean, + context: { replayer: Replayer }, + ) => void; +}; +``` + +以上是录制和回放插件的接口类型。 + +### 示例 + +#### 录制侧插件 + +```ts +const exampleRecordPlugin: RecordPlugin<{ foo: string }> = { + name: 'my-scope/example@1', + observer(cb, options) { + const timer = setInterval(() => { + cb({ + foo: options.foo, + timestamp: Date.now(), + }); + }, 1000); + return () => clearInterval(timer); + }, + options: { + foo: 'bar', + }, +}; + +rrweb.record({ + emit: emit(event) {}, + plugins: [exampleRecordPlugin], +}); +``` + +在这个示例中,录制侧插件将会输出这样的事件: + +```js +{ + type: 6, + data: { + plugin: 'my-scope/example@1', + payload: { + foo: 'bar', + timestamp: 1624693882345, + }, + }, + timestamp: 1624693882345, +} +``` + +#### 回放侧插件 + +```ts +const exampleReplayPlugin: ReplayPlugin = { + handler(event, isSync, context) { + if (event.type === EventType.Plugin) { + // 使用 event.data.payload + if (event.data.plugin === 'my-scope/example@1') { + // 处理示例插件录制的数据 + } + } + }, +}; + +const replayer = new rrweb.Replayer(events, { + plugins: [exampleReplayPlugin], +}); +``` + +回放侧插件可以通过 `context.replayer` 与播放器进行交互。 + +## 插件命名 + +录制侧插件应该拥有全局唯一的名称,并且其名称会被记录在输出的事件中。 + +**由于会同时存在 rrweb 仓库中的官方插件与用户自行实现的自定义插件,所以我们推荐使用统一的命名规则避免冲突,命名方式如下:** + +> scope/name@version + +例如: `rrweb/console@1` 或 `github/pr@2`。