news 2026/9/20 12:03:49

@rrweb/record 记录包全解:从 2.0 重大变更到 2.1 性能优化的演进指南

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
@rrweb/record 记录包全解:从 2.0 重大变更到 2.1 性能优化的演进指南

@rrweb/record 记录包全解:从 2.0 重大变更到 2.1 性能优化的演进指南

【免费下载链接】rrwebrecord and replay the web项目地址: https://gitcode.com/gh_mirrors/rr/rrweb

@rrweb/record是 rrweb 生态中专用于"录制端"的独立 npm 包,面向需要在浏览器中采集页面事件的前端应用。本文以该包的 CHANGELOG.md 为主线,结合包内源码与测试,逐版本解读从 2.0.0 到 2.1.5 的关键变更——包括破坏性的产物命名与 UMD 全局名调整、打包体积治理、录制性能优化等,并给出可直接落地的安装、引入与迁移方案。读完本文,你将掌握@rrweb/record的包结构与发布节奏,理解每次升级对既有接入代码的实际影响,并能写出与 2.x 版本兼容的录制接入代码。

一、包定位:录制逻辑的唯一出口

@rrweb/record在 rrweb 生态中的职责非常清晰:只暴露录制能力。它的核心实现其实是一个极简包装层:

// packages/record/src/index.ts import { record } from 'rrweb'; export { record };

从 src/index.ts 可以看到,包本身只是把主rrweb包中的record函数重新导出(re-export)。在 packages/record/README.md 中作者也明确说明:"Currently this package is really just a wrapper around therecordfunction in the mainrrwebpackage. Allrecordrelated code will get moved here in the future."(当前该包只是主包record函数的包装,未来所有录制相关代码会迁移到这里。)

因此,@rrweb/record承担的是一个"面向未来"的包边界:对使用方来说,它提供了稳定的录制 API 入口;对项目来说,它把录制代码与回放代码在包级别彻底隔离,为后续 tree-shaking(摇树优化)与按需加载奠定基础。

record函数的真实实现在主包中,位于 packages/rrweb/src/record/index.ts,其签名结构为:

function record<T = eventWithTime>( options: recordOptions<T> = {}, ): listenerHandler | undefined { const { emit, checkoutEveryNms, // ... 其余录制选项 } = options; // ... return stopHandler; // 返回用于停止录制的函数 }

它接收可选的recordOptions<T>配置对象,返回一个"停止录制"的监听处理器(listenerHandler),并且record.mirror = mirror挂载了内部节点镜像。完整的recordOptions说明可参见仓库根目录的 guide.md 中的record-options一节。

二、安装与三种引入方式

根据 package.json,@rrweb/record当前版本为2.1.5,声明了如下依赖:

{ "dependencies": { "@rrweb/types": "^2.1.5", "rrweb": "^2.1.5", "@rrweb/utils": "^2.1.5" } }

包的类型声明位于dist/index.d.ts,浏览器兼容目标为supports es6-class(支持 ES6 class 的现代浏览器)。

方式一:通过 npm / bundler 引入(推荐)

npm install @rrweb/record
import { record } from '@rrweb/record'; record({ emit(event) { // 将事件发送到服务端 }, });

这是 README.md 推荐的接入方式,构建产物兼容现代浏览器、Node.js 以及支持 ES Modules 的打包器。

方式二:浏览器直接加载(ESM)

不使用打包器时,可以直接在浏览器中以 ES Module 方式加载 CDN 资源:

<script type="module"> import { record } from 'https://cdn.rrweb.com/record/current/dist/record.js'; </script>

其中current指向最新稳定版;生产环境建议锁定具体版本以保证不可变 URL,例如:

<script type="module"> import { record } from 'https://cdn.rrweb.com/record/2.0.0/dist/record.js'; </script>

方式三:传统<script>直接引入(UMD 兜底)

仅用于不支持 ES Module 的旧环境:

<script src="https://cdn.rrweb.com/record/current/dist/record.umd.cjs"></script>

注意:此方式暴露的全局变量名为rrwebRecord(而非旧版的rrweb),这正是 2.0.0 版本的一项破坏性变更,详见下文。

三、2.0.0 重大变更:升级前必须了解的三件事

2.0.0 是该包历史上最大的一次重构(对应 CHANGELOG.md 中的2.0.0一节),涉及三个破坏性变更与一批功能性补丁。如果你正在从 1.x 升级,以下内容直接决定你的代码是否需要改动。

3.1 UMD 全局名从rrweb改为rrwebRecord

为避免录制器与回放器同时加载在同一页面时发生全局命名冲突,2.0.0 将 UMD 全局名拆分:

  • 录制器(recorder)全局名:rrwebRecord
  • 回放器(replayer)全局名:rrwebReplay

这意味着所有通过<script>标签直接引用 UMD 产物的老代码,都需要把全局变量的引用从rrweb改为rrwebRecord

3.2 分发产物文件名、路径与扩展名全面调整

2.0.0 重做了构建产物规范(对应 PR #1497),核心变化如下:

  • 所有.js文件现在都是ES Modules,可用于现代浏览器、Node.js 以及支持 ESM 的打包器;
  • 所有 npm 包同时附带.cjs.umd.cjs文件:
    • .umd.cjs:CommonJS 格式且内联打包所有依赖,便于在浏览器环境用一个文件直接引入(类似旧版.js文件);
    • .cjs:CommonJS 格式,用于较老的 Node.js 环境;
  • 新增/umd/输出目录,与/dist/并存,从而可以以.js扩展名提供 UMD 文件,而不破坏 package.json 中"/dist/下所有.js均为模块"的约定;
  • 类型导出更规范:如果需要特定类型(例如PlayerMachineStateSpeedMachineState),它们现在从@rrweb/replay等新包导出;具体可用文件以各包package.jsonmainexports字段为准。

从当前 package.json 可以直观看到这套新规范:

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

迁移建议:如果你的代码通过import rrweb from 'rrweb'方式使用,则本次变更对你几乎无感;但如果你直接引用了分发文件(例如rrweb/typings/...rrdom/es),或在<script>标签中直接引入旧版rrweb-all.jsrrweb-record.jsrrweb-replay.js,则必须更新路径——改为引用.umd.cjs文件,或改用新包。

3.3 移除rrweb-all.js/rrweb-record.js/rrweb-replay.js

这三个文件从rrweb主包中彻底移除,取而代之的是按职责拆分的独立包:

  • @rrweb/all:聚合导出(录制 + 回放 + 打包器)
  • @rrweb/record:仅录制
  • @rrweb/replay:仅回放

从 packages/all/src/index.ts 可以看到@rrweb/all的聚合方式:

export * from 'rrweb'; export * from '@rrweb/packer'; import 'rrweb/dist/style.css';

它重新导出主包全部 API 与打包器,并附带引入回放所需的样式文件。如果你以前用rrweb-all.js一把梭,现在应当按需拆分引入,只加载自己需要的部分。

3.4 2.0.0 的功能性补丁

除破坏性变更外,2.0.0 还包含一系列稳定性与兼容性修复:

变更点说明
移除各 bundle 中 base64 内联的 worker 源码减小产物体积,worker 改为独立文件加载
支持已废弃的addRule/removeRule方法兼容仍在使用旧 CSSOM API 的页面(PR #1515)
捕获WebGLRenderingContext前先校验其是否存在避免在不支持 WebGL 的环境抛错(PR #1777)
patch函数迁移至@rrweb/utils提升打包复用性,减少重复代码(PR #1631)
正确识别 Angular 包装后的 MutationObserver修复 Angular 框架下录制失效的问题(PR #1597)
@rrweb/recordbundle 中摇树掉回放专用的postcss代码录制包不再携带回放才需要的 CSS 处理逻辑(PR #1837)
新增/umd/输出目录见 3.2 节说明

四、打包体积治理:一条有测试约束的硬红线

@rrweb/record的体积不是靠自觉维护的,而是被自动化测试强制约束。在 packages/record/test/record.test.ts 中可以看到两个关键断言:

// 修复前 ESM bundle 大小:397373 字节 // 修复后 ESM bundle 大小:161287 字节 // 修复后的 ESM bundle 必须比基线至少小 200 KiB const BASELINE_RECORD_JS_BYTES = 397373; const MAX_RECORD_JS_BYTES = BASELINE_RECORD_JS_BYTES - 200 * 1024;

测试逻辑分三层:

  1. 导出可用性typeof record === 'function',保证 API 形态稳定;
  2. 无回放代码泄漏:遍历dist/下所有.js/.cjs产物,断言内容中不包含postcss字样——这就是 3.4 节"摇树掉回放专用 postcss"的回归防线,防止未来重构又把回放依赖带进录制包;
  3. 体积上限dist/record.js的大小必须小于等于397373 - 200 * 1024 ≈ 192765字节。实测摇树修复后为 161287 字节,比 2.0.0 基线瘦身约 236 KB(近 60%)。

这一设计思路值得借鉴:把"体积"当作与"功能正确性"同等重要的非功能需求,用单测持续守护。也正因为此,@rrweb/record才能以极小的包体承载完整录制能力。

五、2.1.x 增量演进:性能与健壮性打磨

进入 2.1 系列后,@rrweb/record没有再做破坏性变更,而是聚焦性能与细节。逐版本梳理如下:

2.1.5:录制热路径性能优化

这是 2.1 系列最重要的一次性能更新,包含两点:

  • 未受污染的 DOM 访问器性能提升:自 #1509 起,为绕开某些库对parentNode等访问器的篡改,代码改为使用dom.parentNode(el)这类封装调用。2.1.5 进一步优化,避免每次调用时分配字符串——这些调用位于所有录制热路径上,字符串分配开销会被放大到每次 DOM 变更;
  • 录制期 mutation 处理效率提升:重排了 mutation 处理顺序,录制效率显著改善,同时新的 mutation 排序还带来更快的回放性能。该问题此前被多位社区成员反复报告,是录制侧公认的痛点。

对应地,packages/rrweb/src/record/下的 mutation.ts 与 observer.ts 就是这些优化的落点所在——DOM 变更观察与序列化在每次用户交互时都会被触发,属于典型的热路径。

2.1.0:绝对 URL 转相对 URL 的 hash 修复

修复了一个边界 bug:当 URL 中包含 hash(#...)时,绝对 URL 转相对 URL 的转换逻辑会产生错误结果。这影响的是录制事件中资源 URL 的归一化处理,修复后带 hash 的链接也能被正确转为相对地址。

2.1.1 / 2.1.2 / 2.1.3 / 2.1.4:纯依赖同步

这几个版本没有@rrweb/record自身的代码变更,只是随主包与类型包一起同步版本(rrweb@rrweb/types@rrweb/utils同版本对齐)。这正是 rrweb monorepo 采用的changesets 统一版本管理策略:所有包保持相同版本号,通过turbo工作流协调构建与发布。

2.0.1:补丁同步

同样为依赖同步版本,未包含本包独立变更。

六、版本发布节奏与全版本一览

@rrweb/record的发布遵循 changesets 规范:所有相关包(rrweb@rrweb/types@rrweb/utils)保持版本同步。从 CHANGELOG.md 整理的完整版本时间线如下:

版本类型核心内容
2.1.5Patch未污染 DOM 访问器性能优化;mutation 处理效率提升
2.1.4Patch依赖同步
2.1.3Patch依赖同步
2.1.2Patch依赖同步
2.1.1Patch依赖同步
2.1.0Patch修复含 hash 的绝对 URL 转相对 URL
2.0.1Patch依赖同步
2.0.0MajorUMD 全局名改名;产物路径/命名/扩展名重构;移除rrweb-*.js独立文件;若干兼容性补丁
2.0.0-alpha.15 ~ 2.0.0-alpha.20Major/Alpha2.0.0 的预发布迭代(含addRule/removeRule支持、patch函数迁移等)

需要注意的是,2.0.0-alpha.x 系列属于预发布版本,其中出现的变更(如db20184"保持包版本与其他包同步")最终都汇总进了 2.0.0 正式版。

七、包内工程配置速查

如果你要本地开发或调试@rrweb/record,package.json 中几个常用脚本值得关注:

{ "scripts": { "dev": "vite build --watch", "build": "yarn turbo run prepublish", "test": "yarn build && vitest run", "test:watch": "vitest watch", "check-types": "tsc -noEmit", "prepublish": "tsc -noEmit && vite build", "lint": "yarn eslint src/**/*.ts" } }
  • yarn workspace @rrweb/record build:通过 turbo 触发prepublish,先做类型检查再走 vite 构建(体积测试要求先执行此步,否则 record.test.ts 会因缺少dist/record.js而报错);
  • yarn workspace @rrweb/record test:构建后运行 vitest,即上文所述的三项体积/内容断言;
  • 构建工具链:vite + vite-plugin-dts(生成.d.ts类型)、vitest(单测)、puppeteer(浏览器相关测试)。

八、迁移检查清单

综合以上分析,从旧版本升级到@rrweb/record2.x 时,建议逐项核对:

  1. 全局变量引用:UMD 方式使用的全局名是否已从rrweb改为rrwebRecord
  2. 脚本标签路径:直接引入的rrweb-record.js等文件路径是否已替换为.umd.cjs或新包 CDN 地址;
  3. 产物导入:若通过import使用,确认打包器正确解析exports字段(importdist/record.jsrequiredist/record.cjs);
  4. 类型引用:需要回放侧状态机类型(如PlayerMachineState)时,改从@rrweb/replay导入;
  5. 浏览器兼容:包目标环境为supports es6-class,不支持 ES6 class 的老浏览器需自行引入 polyfill 或使用 UMD 产物;
  6. 体积预期:ESM 产物约 161 KB(摇树修复后),若接入方同时打包主包,可进一步通过 tree-shaking 获益——录制场景应优先选择@rrweb/record而非@rrweb/all,以规避回放专用代码(如 postcss)被带入产物。

结语

@rrweb/record虽然当前仍以"薄包装"形态存在,但它的出现标志着 rrweb 在包边界、构建规范与体积治理上的系统性演进:2.0.0 用一套破坏性变更换来了清晰的模块划分与现代化的产物矩阵,2.1.x 则把优化火力集中在录制热路径的性能上,并用自动化测试锁住"录制包绝不携带回放代码"的底线。对于接入方而言,理解 CHANGELOG.md 中的每一次版本变化,就是理解录制端 API 稳定性与性能边界的最佳入口——从 2.1.x 开始,你可以放心地把record作为长期稳定的录制入口来依赖。

【免费下载链接】rrwebrecord and replay the web项目地址: https://gitcode.com/gh_mirrors/rr/rrweb

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

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/9/20 12:03:34

Protege 5.5.0实战:从零构建可推理的智慧农业知识图谱

1. 为什么我劝你先别急着打开软件很多人第一次接触知识图谱&#xff0c;脑子里想的都是“我要建一个超酷的图谱&#xff0c;把公司所有数据都连起来”。结果打开 Protege 5.5.0 之后&#xff0c;面对满屏的标签页和按钮&#xff0c;瞬间就懵了——Classes、Object Properties、…

作者头像 李华
网站建设 2026/9/20 12:01:46

ArcGIS Engine 要素更新卡在 Store()?让走 TaoToken 的 Codex 查 UpdateRow

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

作者头像 李华
网站建设 2026/9/20 12:00:29

PDF转Word全攻略:工具选型、实操步骤与避坑指南

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

作者头像 李华