@rrweb/types 包解析:rrweb 2.0 事件类型契约的共享枢纽与版本演进指南
2026/9/20 13:35:23 网站建设 项目流程
  • 前端
  • 可观测性
  • 开发工具

【免费下载链接】rrweb

record and replay the web

项目地址:https://gitcode.com/gh_mirrors/rr/rrweb
点击查看免费下载

@rrweb/types是 rrweb 在 2.0 时代从核心仓库中拆分出的共享类型包,集中定义了录制与回放所依赖的事件契约、增量数据类型与插件接口。本篇文章以 packages/types/CHANGELOG.md 为主线,结合仓库源码,系统梳理该包的诞生背景、事件契约全景、2.0 大版本的破坏性变更,以及 2.1.x 阶段的关键能力演进,帮助读者理解 rrweb 事件格式的来龙去脉,并掌握升级与迁移的要点。

一、包的定位:为什么需要一个独立的共享类型包

在 rrweb 2.0 之前,事件类型(event types)与录制类型(recorder types)散落在各个包中,跨包引用类型时常常需要深挖内部路径。2.0 版本通过 PR #1031(对应 changelog 2.0.0 的 Major Changes)将共享的 rrweb 事件类型和录制类型集中迁移到新的@rrweb/types中,从而:

  • rrwebrrweb-snapshotrrweb-replayrrdom以及各类插件包都能从同一处导入类型,避免重复定义和循环依赖;
  • 为第三方插件作者提供稳定的类型契约(如RecordPlugin、各增量源的数据结构);
  • 让类型与运行时代码解耦,@rrweb/types本身几乎不包含运行时逻辑,从 packages/types/src/index.ts 的源码结构看,该文件从头到尾都是类型与枚举的导出,这也解释了为什么它可以在type: "module"下以极小的体积被任何包引用。

从仓库的依赖关系可以印证这一地位:rrwebrrweb-snapshotrrweb-replayrrdomrrdom-nodejspackerbrowser-clientall以及网络插件包均在其 package.json 中以"@rrweb/types": "^2.1.5"或相近版本声明依赖。而在 packages/rrweb/src/index.ts 中,主包会从@rrweb/types导入并重新导出大量公开类型,使用者通过import rrweb from 'rrweb'即可获得类型与实现,无需单独安装类型包即可获得类型提示。

二、事件类型契约全景:从源码看 types 包的核心资产

@rrweb/types的核心价值在于它完整定义了 rrweb 的事件序列化格式。以当前仓库 packages/types/src/index.ts 为证,契约主要分为以下几层。

1. 顶层事件枚举与事件结构

EventType枚举(packages/types/src/index.ts#L1-L10)定义了八类顶层事件:

export enum EventType { DomContentLoaded, Load, FullSnapshot, IncrementalSnapshot, Meta, Custom, Plugin, Asset, }

每类事件对应一个带type判别字段的结构体,最终通过eventWithoutTime联合类型统一,再叠加timestamp与可选delay形成带时间戳的eventWithTime(packages/types/src/index.ts#L247-L250):

export type eventWithTime = eventWithoutTime & { timestamp: number; delay?: number; };

eventWithTime是录制端输出的标准单位,也是回放端、@rrweb/packer(见 packages/packer/src/pack.ts 的PackFn = (event: eventWithTime) => string)与存储层共同依赖的数据形状。

2. 增量事件源:IncrementalSource 与 incrementalData

页面交互过程中的动态变化通过IncrementalSnapshot事件承载,其dataincrementalData联合类型定义(packages/types/src/index.ts#L215-L229),包含 15 种来源,枚举IncrementalSource(packages/types/src/index.ts#L134-L152)覆盖了 DOM 变更、鼠标/触摸/拖拽、滚动、视口缩放、输入、媒体交互、样式表规则与声明、Canvas 变更、字体、选区、AdoptedStyleSheet、自定义元素等全部录制维度。每种来源都定义了独立的xxxData结构,例如:

  • mutationData(DOM 增删改)
  • mouseInteractionData(点击、聚焦、上下文菜单等)
  • mediaInteractionData(播放、暂停、音量、倍速等)
  • canvasMutationData(2D/WebGL 绘制调用)
  • styleSheetRuleData/styleDeclarationData(CSSOM 变更)

3. 录制回调与采样配置

hooksParam(packages/types/src/index.ts#L330-L344)定义了录制端向外部暴露的各类回调钩子;SamplingStrategy(packages/types/src/index.ts#L261-L295)则规定了采样策略的类型形状(如mousemove的节流阈值、input: 'all' | 'last'canvas: 'all' | number等),是rrweb.record()配置项的类型来源。这些类型正是 2.0 拆分时从主包迁入@rrweb/types的"录制类型"主体。

三、2.0.0 大版本:破坏性变更与产物分发体系重构

changelog 的 2.0.0 条目集中记录了两个 Major Changes,这是理解该包(乃至整个 rrweb 2.0 生态)升级成本的关键。

1. 产物文件命名、路径与扩展名全面调整(PR #1497)

这是 rrweb 2.0 最容易被忽略的破坏性变更:分布式文件的文件名、路径和扩展名都变了。changelog 原文明确提示:

  • 如果直接引用分布式文件或类型,必须更新路径/文件名,例如从rrweb/typings/...rrdom/es导入的写法不再有效;
  • 若通过import rrweb from 'rrweb'使用,则感知不到这一变化;
  • 若通过<script>标签直接引入,需要改用.umd.cjs文件;
  • 所有.js文件现在都是 ES 模块,适用于现代浏览器、Node.js 及支持 ESM 的打包器;
  • 所有 npm 包同时提供.cjs.umd.cjs.umd.cjs是打包为单文件的 CommonJS 产物(类似旧版.js的浏览器用法);.cjs供旧版 Node.js 使用。

从当前 packages/types/package.json 可以清晰看到这套体系的落地形态:

{ "type": "module", "main": "./dist/types.umd.cjs", "module": "./dist/types.js", "unpkg": "./dist/types.umd.cjs", "jsdelivr": "./umd/types.js", "typings": "dist/index.d.ts", "exports": { ".": { "import": { "types": "./dist/index.d.ts", "default": "./dist/types.js" }, "require": { "types": "./dist/index.d.cts", "default": "./dist/types.umd.cjs" } } }, "files": ["umd", "dist", "package.json"] }

要点解读:

  • import条件对应 ESM 产物dist/types.jsrequire条件对应 CommonJS 单文件产物dist/types.umd.cjs,并分别提供.d.ts.d.cts类型声明;
  • exports字段锁定了包的唯一入口,禁止深路径导入(如@rrweb/types/dist/xxx),这也是 PR #1497 所说的"package.json 的mainexports字段决定了可用文件";
  • files只发布umddistpackage.json,其中umd目录是 PR #1704 补充的:在dist之外额外提供带.js扩展名的 UMD 文件(jsdelivr指向./umd/types.js),避免"package.json 声明dist下所有.js都是模块"的预期被 UMD 文件破坏。

升级提示:如果你的构建链路或 CDN 直接引用了旧路径(如rrweb/typings/...),升级 2.0 后必须按上述exports映射调整;如果只是import rrweb from 'rrweb',则无需改动。

2. 类型归属调整:特定类型迁移到其他包(PR #1031 / #1497)

changelog 明确提到,部分特定类型被导出到新的包中,例如PlayerMachineStateSpeedMachineState现在从@rrweb/replay导出。这意味着:

  • 回放相关状态机类型不再属于@rrweb/types,需要从回放包引入;
  • 使用@rrweb/types时应只引用事件与录制契约相关类型,避免继续依赖旧的集中式 typings 入口。

3. 工程细节:TypeScript 4.9.5 与 NodeNext 兼容(PR #1287 / #1369)

  • PR #1287 将仓库全部项目升级到 TypeScript 4.9.5,@rrweb/types的类型声明也随之上限对齐;
  • PR #1369 修复了"moduleResolution": "NodeNext"下的类型错误,这一点对使用 Node.js 原生 ESM 解析策略(NodeNext/Node16)的消费者尤为重要——如果升级后出现类型解析错误,请检查是否已使用包含exports字段映射的较新版本(2.0.0 正式版起已修复)。

四、事件契约的关键能力演进(2.0 系列 Minor 变更)

除了破坏性重构,2.0 阶段还通过多个 Minor 变更扩充了事件契约本身,这些都可以在当前源码中得到印证。

1. pointerType:区分鼠标、触控笔与触摸(PR #1129)

点击类事件新增.pointerType属性,用于区分penmousetouch三类指针来源(对应 PointerEvent.pointerType 的取值)。changelog 特别说明:没有新增 PenDown/PenUp 事件,笔事件可以通过MouseDown/MouseUp + pointerType=pen组合识别。

在类型层,packages/types/src/index.ts#L446-L450 定义了PointerTypes枚举(MousePenTouch),而mouseInteractionParam(packages/types/src/index.ts#L496-L502)将pointerType?: PointerTypes声明为可选字段,以保持向后兼容。

在实现层,packages/rrweb/src/record/observer.ts#L219-L275 展示了完整的映射逻辑:从原生事件读取pointerType字符串,映射到PointerTypes枚举;对触摸事件还会维护"当前指针类型"状态,在后续移动/交互事件中沿用该状态,最后仅在pointerType !== null时写入事件对象。这条链路说明:录制端生成的增量事件中,pointerType是"可选但尽量填充"的增强字段,回放端消费时需做空值兼容。

2. 顶层<dialog>组件支持(PR #1503)

PR #1503 为顶层<dialog>组件提供支持,修复了 #1381。其类型落点在快照侧: packages/rrweb-snapshot/src/types.ts#L7-L22 定义了DialogAttributes

export type DialogAttributes = { open: string; rr_open_mode: 'modal' | 'non-modal'; // rr_open_mode_index?: number; // 预留,用于按顺序回放多次 showModal() };

rr_open_mode区分showModal()(modal)与show()/添加open属性(non-modal)两种打开方式;注释中还预留了rr_open_mode_index字段,用于未来按打开顺序回放多个 dialog。这与仓库中 dialog 相关的回放测试(如 packages/rrweb/test/replay/dialog.test.ts 及其 图片快照 目录)相互印证:回放端会依据该属性重建 dialog 的打开状态与层级。

3. 跨域 iframe 录制类型(PR #1035)

PR #1035 为跨域 iframe 录制支持补充了类型定义。核心是ICrossOriginIframeMirror接口(packages/types/src/index.ts#L297-L312),它定义了父页面与跨域 iframe 之间节点 ID 的映射能力:

  • getId(iframe, remoteId, ...):将 iframe 内的远端节点 ID 映射为主文档 ID;
  • getRemoteId(iframe, parentId, ...):反向映射回 iframe 内的 ID;
  • 支持批量映射(getIds/getRemoteIds)与按 iframe 重置(reset(iframe?))。

实现侧,packages/rrweb/src/record/cross-origin-iframe-mirror.ts 直接以import type { ICrossOriginIframeMirror } from '@rrweb/types'引用该接口;RecordPlugin.getMirror回调(packages/types/src/index.ts#L322-L326)也会向插件注入包含nodeMirrorcrossOriginIframeMirrorcrossOriginIframeStyleMirror三个镜像实例,其中后两个即为跨域 iframe 场景而设。测试见 packages/rrweb/test/record/cross-origin-iframes.test.ts。

4. mediaInteractionParam 新增 loop(PR #1432)

PR #1432 为媒体交互参数补充loop字段。当前类型定义(packages/types/src/index.ts#L649-L657):

export type mediaInteractionParam = { type: MediaInteractions; id: number; currentTime?: number; volume?: number; muted?: boolean; loop?: boolean; playbackRate?: number; };

录制端在 packages/rrweb/src/record/observer.ts#L1036-L1045 中从媒体元素解构currentTime, volume, muted, playbackRate, loop并写入事件;对应地,快照侧mediaAttributes(packages/types/src/index.ts#L846-L865)也声明了rr_mediaLoop?: boolean等序列化属性。这使得回放时可以精确还原"循环播放"的媒体状态。

五、2.1.x 阶段:插件契约与资产事件

1. 网络插件类型进入共享包(2.1.0,PR #1689)

@rrweb/types2.1.0 的核心变更是"Add the network-plugin"。从此版本起,网络录制相关的类型正式纳入共享包,当前源码(packages/types/src/index.ts#L63-L123)包含一整套网络事件契约:

  • NetworkInitiatorType:资源发起类型联合,涵盖audiobeaconfetchiframeimgscriptxmlhttprequest等 21 种取值;
  • NetworkRequest:基于PerformanceEntry派生并补充methodstatusrequestHeadersrequestBodyresponseHeadersresponseBodyisInitial等字段的网络请求结构;
  • NetworkRecordOptions:插件的配置类型,支持initiatorTypes(按发起类型过滤)、transformRequestFn(请求转换)、recordHeaders/recordBody(布尔或分请求/响应细粒度控制)、recordInitialRequests等;
  • NetworkEvent = pluginEvent<NetworkData>:网络事件以插件事件(EventType.Plugin)的形式承载requests数组。

实际插件 packages/plugins/rrweb-plugin-network-record 与 packages/plugins/rrweb-plugin-network-replay 均直接依赖@rrweb/types(见各自 package.json),印证了"共享类型为插件生态服务"的设计意图。

2. Asset 事件类型别名(2.0.0 Patch,PR #1833)

PR #1833 为 2.0 事件契约补充公开的 Asset 事件类型别名。源码中对应:

export type assetEvent = { type: EventType.Asset; data: assetParam }; export type assetEventWithTime = assetEvent & { timestamp: number };

assetParam(packages/types/src/index.ts#L691-L703)支持两种形态:成功时携带urlpayload(如 Canvas 序列化参数或SerializedCssTextArg),失败时携带failed: { status?, message }EventType.Asset在 EventType 枚举 中同样可见,用于承载全快照阶段资源(图片、样式等)的序列化结果或加载失败信息。

3. 紧凑样式变更修复(2.0.0 Patch,PR #1268)

PR #1268 修复并优化了紧凑(compact)样式变更:

  • 修复样式更新中包含作用于简写属性(shorthand property)的var()时的问题(issue #1246);
  • 进一步保证样式变更保持紧凑:若字符串形式更短则回退到字符串方法记录。

这一改动作用于styleSheetRuleParam/styleDeclarationParam相关的事件生成逻辑,目标是控制增量事件体积,属于不影响外部类型形状的内部优化。

六、版本发布节奏与依赖联动

从 changelog 可以还原@rrweb/types的发布节奏:

版本类型主要内容
2.0.0-alpha.5–7Patch仅跟随rrweb-snapshot变更
2.0.0-alpha.8Minor新增pointerType
2.0.0-alpha.9–12Patch跟随rrweb-snapshot
2.0.0-alpha.13PatchmediaInteractionParam.loop、NodeNext 修复
2.0.0-alpha.14–16Patch跟随rrweb-snapshot
2.0.0-alpha.17Minor顶层<dialog>支持
2.0.0-alpha.15/2.0.0Major产物分发体系重构、类型归属调整
2.0.0 正式版Major包拆分落地、Asset 别名、样式压缩修复、TS 4.9.5、UMD 目录
2.1.0Minor网络插件类型
2.1.1–2.1.5版本同步(2.0.1 明确说明"仅版本号提升以与其他包保持同步")

两个值得注意的规律:

  1. alpha 阶段大量 Patch 版本只是"跟随rrweb-snapshot"——因为事件契约中的序列化节点类型(serializedNodeWithId等)定义在rrweb-snapshot中,@rrweb/types需要与之保持版本联动(如 2.0.0 条目中的 "Updated dependencies: rrweb-snapshot@2.0.0-alpha.4");
  2. 2.1.1–2.1.5 之间无实质变更,属于 monorepo 内的版本对齐(changesets批量发布机制所致),网络插件相关类型在 2.1.0 已就位,因此当前各包统一依赖^2.1.5是安全的。

七、实践指南:如何消费 @rrweb/types

安装与导入

@rrweb/types通常是作为rrweb等包的传递依赖被安装的,一般无需显式安装;若插件开发或自定义事件处理需要直接使用其类型,可显式安装:

npm install --save-dev @rrweb/types # 或 yarn add --dev @rrweb/types

导入方式(ESM / 类型导入):

import type { eventWithTime, IncrementalSource, EventType } from '@rrweb/types'; import { EventType, IncrementalSource } from '@rrweb/types'; // 枚举可直接导入

注意:由于exports字段的限制,不应使用@rrweb/types/dist/...之类的深路径导入;且event类型在源码中已被标记为@deprecated(packages/types/src/index.ts#L241-L245),它是eventWithoutTime的同义词,仅供内部使用,新代码应直接使用eventWithoutTimeeventWithTime

典型使用场景

  1. 自定义事件:使用customEvent<T>类型约束event.data.tagpayload
  2. 插件开发:基于RecordPlugin<TOptions>(packages/types/src/index.ts#L314-L328)编写录制插件,实现observereventProcessorgetMirror等钩子,类型契约保证插件与主包解耦;
  3. 事件处理管道:以eventWithTime为输入,编写存储、加密、压缩(如 @rrweb/packer)或实时转发逻辑;
  4. 跨包类型复用:在rrwebrrweb-snapshot、回放包之间传递serializedNodeWithId等节点类型时,统一从@rrweb/types引入。

升级到 2.x 的检查清单

  1. 检查是否有直接引用rrweb/typings/...rrdom/es等旧路径的代码,按新版exports映射调整;
  2. <script>直引场景改用.umd.cjs文件,注意dist.js均为 ESM;
  3. PlayerMachineStateSpeedMachineState等回放状态类型改从@rrweb/replay导入;
  4. "moduleResolution": "NodeNext"项目请升级到 2.0.0 及以上(已修复类型解析);
  5. 消费增量事件时,对新增的可选字段(pointerTypeloop等)保持空值兼容,以支持新旧录制数据并存。

结语

@rrweb/types虽是一个"只有类型、没有逻辑"的包,却是 rrweb 2.0 生态正常运转的契约基石:它承载了从EventType/IncrementalSource到插件接口的完整事件模型,其版本演进史(packages/types/CHANGELOG.md)浓缩了 rrweb 2.0 在分发体系、指针事件、dialog、跨域 iframe、媒体状态与插件生态上的全部关键变化。理解这个包,就等于拿到了读懂 rrweb 事件流与进行二次开发的类型地图。

  • 前端
  • 可观测性
  • 开发工具

【免费下载链接】rrweb

record and replay the web

项目地址:https://gitcode.com/gh_mirrors/rr/rrweb
点击查看免费下载

相关推荐

创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询