From 2305946aed9fda36cd23f860d6cfef05e9cdec2d Mon Sep 17 00:00:00 2001 From: Eoghan Murray Date: Wed, 1 Apr 2026 12:00:00 +0800 Subject: [PATCH] Umd folder (#1704) * Don't allow video autoplay to automatically unfreeze page. If it's a 'real' playback, there should be a mount or a keyboard event which will serve to unfreeze the page. Also add other non-user events to the list (we really should have an `isUserEvent` function) * Apply formatting changes * Create a new `umd` folder alongside `dist` for output of UMD files with a plain `.js` instead of `.cjs` extension, as the latter won't be served with the correct mime type by jsdelivr - #1687 (just rename `.cjs` to `.js`) was rejected due to the the 'dual package hazard' [1], and produces a warning when run through publint.dev (which was the original motivation for changing to \.cjs) - jsdelivr won't be serving `.cjs` with the correct mime type: https://github.com/jsdelivr/jsdelivr/issues/18584 [1] https://nodejs.org/en/learn/modules/publishing-a-package#the-dual-package-hazard * Update to point to alpha.19 as presumably that's when the umd folder will be available after the changes in this PR * Apply formatting changes * Don't try to create the same directory twice (was failing on packages/packer/umd) * Create thirty-shirts-grow.md * Revert something that shouldn't have gotten into the UMD branch folder * Apply formatting changes * Update vite.config.default.ts * Apply formatting changes * build: include umd builds in published packages Add umd directory to the files array in package.json for all packages to include UMD builds in npm publications. Also update .gitignore to exclude umd folders from version control. * Docs: point to correct file * Remove unused code * docs: update rrweb cdn urls to umd bundles Align README and guide examples with published UMD file locations for rrweb, @rrweb/record, and @rrweb/replay. Update versioned rrweb script examples from 2.0.0-alpha.19 to 2.0.0-alpha.21 in both English and Chinese guides. * build(all): include umd folder in package files --------- Co-authored-by: eoghanmurray Co-authored-by: Justin Halsall --- .changeset/thirty-shirts-grow.md | 16 ++ .gitignore | 1 + README.md | 4 +- README.zh_CN.md | 4 +- guide.md | 10 +- guide.zh_CN.md | 10 +- packages/all/package.json | 1 + .../package.json | 1 + .../package.json | 1 + .../rrweb-plugin-console-record/package.json | 1 + .../rrweb-plugin-console-replay/package.json | 1 + .../package.json | 1 + .../package.json | 1 + packages/record/package.json | 1 + packages/replay/package.json | 1 + packages/rrdom-nodejs/package.json | 1 + packages/rrdom/package.json | 1 + packages/rrweb-player/README.md | 2 +- packages/rrweb-player/package.json | 1 + packages/rrweb-snapshot/package.json | 1 + packages/rrweb/package.json | 1 + packages/rrweb/rollup.config.js | 261 ------------------ packages/types/package.json | 1 + packages/utils/package.json | 1 + vite.config.default.ts | 24 +- 25 files changed, 68 insertions(+), 280 deletions(-) create mode 100644 .changeset/thirty-shirts-grow.md delete mode 100644 packages/rrweb/rollup.config.js diff --git a/.changeset/thirty-shirts-grow.md b/.changeset/thirty-shirts-grow.md new file mode 100644 index 00000000..9281088e --- /dev/null +++ b/.changeset/thirty-shirts-grow.md @@ -0,0 +1,16 @@ +--- +"all": patch +"packer": patch +"plugins": patch +"record": patch +"replay": patch +"rrdom": patch +"rrdom-nodejs": patch +"rrweb": patch +"rrweb-player": patch +"rrweb-snapshot": patch +"types": patch +"utils": patch +--- + +Provide a /umd/ output folder alongside the /dist/ one so that we can serve UMD (Universal Module Definition) files with a .js extension, without upsetting expectations set by package.json that all .js files in /dist/ are modules diff --git a/.gitignore b/.gitignore index 42662613..f5fee78e 100644 --- a/.gitignore +++ b/.gitignore @@ -16,6 +16,7 @@ temp # output of `yarn build` build dist +umd # turbo cache .turbo diff --git a/README.md b/README.md index 856d8b90..01e54198 100644 --- a/README.md +++ b/README.md @@ -12,8 +12,8 @@ [![Join the chat at slack](https://img.shields.io/badge/slack-@rrweb-teal.svg?logo=slack)](https://join.slack.com/t/rrweb/shared_invite/zt-siwoc6hx-uWay3s2wyG8t5GpZVb8rWg) [![Twitter Follow](https://img.shields.io/badge/twitter-@rrweb__io-teal.svg?logo=twitter)](https://twitter.com/rrweb_io) [![Reddit](https://img.shields.io/badge/reddit-r/rrweb-teal.svg?logo=reddit)](https://www.reddit.com/r/rrweb) -![recorder gzip size](https://img.badgesize.io/https://cdn.jsdelivr.net/npm/@rrweb/record@latest/dist/record.min.js?compression=gzip&label=recorder%20gzip%20size&max=200000&softmax=100000) -![replayer gzip size](https://img.badgesize.io/https://cdn.jsdelivr.net/npm/@rrweb/replay@latest/dist/replay.min.js?compression=gzip&label=replayer%20gzip%20size&max=200000&softmax=100000) +![recorder gzip size](https://img.badgesize.io/https://cdn.jsdelivr.net/npm/@rrweb/record@latest/umd/record.min.js?compression=gzip&label=recorder%20gzip%20size&max=200000&softmax=100000) +![replayer gzip size](https://img.badgesize.io/https://cdn.jsdelivr.net/npm/@rrweb/replay@latest/umd/replay.min.js?compression=gzip&label=replayer%20gzip%20size&max=200000&softmax=100000) [![](https://data.jsdelivr.com/v1/package/npm/rrweb/badge)](https://www.jsdelivr.com/package/npm/rrweb) [中文文档](./README.zh_CN.md) diff --git a/README.zh_CN.md b/README.zh_CN.md index 7e49f0ee..7f250b24 100644 --- a/README.zh_CN.md +++ b/README.zh_CN.md @@ -11,8 +11,8 @@ [![Join the chat at slack](https://img.shields.io/badge/slack-@rrweb-teal.svg?logo=slack)](https://join.slack.com/t/rrweb/shared_invite/zt-siwoc6hx-uWay3s2wyG8t5GpZVb8rWg) [![Reddit](https://img.shields.io/badge/reddit-r/rrweb-teal.svg?logo=reddit)](https://www.reddit.com/r/rrweb) -![total gzip size](https://img.badgesize.io/https://cdn.jsdelivr.net/npm/rrweb@latest/dist/rrweb.min.cjs?compression=gzip&label=total%20gzip%20size) -![recorder gzip size](https://img.badgesize.io/https://cdn.jsdelivr.net/npm/rrweb@latest/dist/record/rrweb-record.min.cjs?compression=gzip&label=recorder%20gzip%20size) +![total gzip size](https://img.badgesize.io/https://cdn.jsdelivr.net/npm/rrweb@latest/umd/rrweb.min.js?compression=gzip&label=total%20gzip%20size) +![recorder gzip size](https://img.badgesize.io/https://cdn.jsdelivr.net/npm/@rrweb/record@latest/umd/record.min.js?compression=gzip&label=recorder%20gzip%20size) [![](https://data.jsdelivr.com/v1/package/npm/rrweb/badge)](https://www.jsdelivr.com/package/npm/rrweb) > 我已开通 Github Sponsor, 您可以通过赞助的形式帮助 rrweb 的开发。 diff --git a/guide.md b/guide.md index 887382a0..96727a49 100644 --- a/guide.md +++ b/guide.md @@ -15,13 +15,13 @@ You are recommended to install rrweb via jsdelivr's CDN service: rel="stylesheet" href="https://cdn.jsdelivr.net/npm/rrweb@latest/dist/style.css" /> - + ``` Also, you can link to a specific version number that you can update manually: ```html - + ``` #### Only include the recorder code @@ -30,7 +30,7 @@ rrweb's code includes both the record and the replay parts. Most of the time you This also can be done by using the `@rrweb/record` package and the CDN service: ```html - + ``` The recorder UMD build exposes a global named `rrwebRecord`. @@ -42,7 +42,7 @@ The recorder UMD build exposes a global named `rrwebRecord`. rel="stylesheet" href="https://cdn.jsdelivr.net/npm/@rrweb/replay@latest/dist/style.css" /> - + ``` The replayer UMD build exposes a global named `rrwebReplay`. @@ -340,7 +340,7 @@ rrweb-player can also be included with ` + ``` Or installed by using NPM: diff --git a/guide.zh_CN.md b/guide.zh_CN.md index aa7ee438..8786e03a 100644 --- a/guide.zh_CN.md +++ b/guide.zh_CN.md @@ -13,13 +13,13 @@ rel="stylesheet" href="https://cdn.jsdelivr.net/npm/rrweb@latest/dist/style.css" /> - + ``` 也可以在 URL 中指定具体的版本号,例如: ```html - + ``` #### 仅引入录制部分 @@ -27,7 +27,7 @@ rrweb 代码分为录制和回放两部分,大多数时候用户在被录制的应用中只需要引入录制部分代码。同样可以通过使用 @rrweb/record 包和 CDN 服务来实现: ```html - + ``` 录制端的 UMD build 会暴露全局变量 `rrwebRecord`。 @@ -39,7 +39,7 @@ rrweb 代码分为录制和回放两部分,大多数时候用户在被录制 rel="stylesheet" href="https://cdn.jsdelivr.net/npm/@rrweb/replay@latest/dist/style.css" /> - + ``` 回放端的 UMD build 会暴露全局变量 `rrwebReplay`。 @@ -334,7 +334,7 @@ rrweb-player 同样可以使用 CDN 方式安装: rel="stylesheet" href="https://cdn.jsdelivr.net/npm/rrweb-player@latest/dist/style.css" /> - + ``` 或者通过 npm 安装: diff --git a/packages/all/package.json b/packages/all/package.json index 1c82ec37..9807b7ff 100644 --- a/packages/all/package.json +++ b/packages/all/package.json @@ -44,6 +44,7 @@ } }, "files": [ + "umd", "build", "dist", "package.json" diff --git a/packages/plugins/rrweb-plugin-canvas-webrtc-record/package.json b/packages/plugins/rrweb-plugin-canvas-webrtc-record/package.json index 3507a881..b31c9d16 100644 --- a/packages/plugins/rrweb-plugin-canvas-webrtc-record/package.json +++ b/packages/plugins/rrweb-plugin-canvas-webrtc-record/package.json @@ -20,6 +20,7 @@ } }, "files": [ + "umd", "dist", "package.json" ], diff --git a/packages/plugins/rrweb-plugin-canvas-webrtc-replay/package.json b/packages/plugins/rrweb-plugin-canvas-webrtc-replay/package.json index 8c11d607..6c15c3cc 100644 --- a/packages/plugins/rrweb-plugin-canvas-webrtc-replay/package.json +++ b/packages/plugins/rrweb-plugin-canvas-webrtc-replay/package.json @@ -20,6 +20,7 @@ } }, "files": [ + "umd", "dist", "package.json" ], diff --git a/packages/plugins/rrweb-plugin-console-record/package.json b/packages/plugins/rrweb-plugin-console-record/package.json index a5d98992..a7803d3d 100644 --- a/packages/plugins/rrweb-plugin-console-record/package.json +++ b/packages/plugins/rrweb-plugin-console-record/package.json @@ -20,6 +20,7 @@ } }, "files": [ + "umd", "dist", "package.json" ], diff --git a/packages/plugins/rrweb-plugin-console-replay/package.json b/packages/plugins/rrweb-plugin-console-replay/package.json index 0f7d9038..8442d7f9 100644 --- a/packages/plugins/rrweb-plugin-console-replay/package.json +++ b/packages/plugins/rrweb-plugin-console-replay/package.json @@ -20,6 +20,7 @@ } }, "files": [ + "umd", "dist", "package.json" ], diff --git a/packages/plugins/rrweb-plugin-sequential-id-record/package.json b/packages/plugins/rrweb-plugin-sequential-id-record/package.json index 25128478..fb0a8207 100644 --- a/packages/plugins/rrweb-plugin-sequential-id-record/package.json +++ b/packages/plugins/rrweb-plugin-sequential-id-record/package.json @@ -20,6 +20,7 @@ } }, "files": [ + "umd", "dist", "package.json" ], diff --git a/packages/plugins/rrweb-plugin-sequential-id-replay/package.json b/packages/plugins/rrweb-plugin-sequential-id-replay/package.json index 3228f84c..4bd951a1 100644 --- a/packages/plugins/rrweb-plugin-sequential-id-replay/package.json +++ b/packages/plugins/rrweb-plugin-sequential-id-replay/package.json @@ -20,6 +20,7 @@ } }, "files": [ + "umd", "dist", "package.json" ], diff --git a/packages/record/package.json b/packages/record/package.json index 0bc9ebfd..d6d1afaf 100644 --- a/packages/record/package.json +++ b/packages/record/package.json @@ -44,6 +44,7 @@ } }, "files": [ + "umd", "dist", "package.json" ], diff --git a/packages/replay/package.json b/packages/replay/package.json index 8c821627..a73dce8b 100644 --- a/packages/replay/package.json +++ b/packages/replay/package.json @@ -45,6 +45,7 @@ "./dist/style.css": "./dist/style.css" }, "files": [ + "umd", "dist", "package.json" ], diff --git a/packages/rrdom-nodejs/package.json b/packages/rrdom-nodejs/package.json index b58b0d88..bc5ab3f9 100644 --- a/packages/rrdom-nodejs/package.json +++ b/packages/rrdom-nodejs/package.json @@ -33,6 +33,7 @@ } }, "files": [ + "umd", "dist", "package.json" ], diff --git a/packages/rrdom/package.json b/packages/rrdom/package.json index dbd14207..f82b48e1 100644 --- a/packages/rrdom/package.json +++ b/packages/rrdom/package.json @@ -21,6 +21,7 @@ } }, "files": [ + "umd", "dist", "package.json" ], diff --git a/packages/rrweb-player/README.md b/packages/rrweb-player/README.md index e80d2007..15fcf4c8 100644 --- a/packages/rrweb-player/README.md +++ b/packages/rrweb-player/README.md @@ -19,7 +19,7 @@ rrweb-player can also be included with ` + ``` Or installed by using NPM: diff --git a/packages/rrweb-player/package.json b/packages/rrweb-player/package.json index bd061db0..a15adea2 100644 --- a/packages/rrweb-player/package.json +++ b/packages/rrweb-player/package.json @@ -51,6 +51,7 @@ "./dist/style.css": "./dist/style.css" }, "files": [ + "umd", "dist", "package.json" ], diff --git a/packages/rrweb-snapshot/package.json b/packages/rrweb-snapshot/package.json index 209705da..39e4b35e 100644 --- a/packages/rrweb-snapshot/package.json +++ b/packages/rrweb-snapshot/package.json @@ -44,6 +44,7 @@ } }, "files": [ + "umd", "dist", "package.json" ], diff --git a/packages/rrweb/package.json b/packages/rrweb/package.json index 4e8474c5..b3f8a425 100644 --- a/packages/rrweb/package.json +++ b/packages/rrweb/package.json @@ -49,6 +49,7 @@ "./dist/style.css": "./dist/style.css" }, "files": [ + "umd", "dist", "package.json" ], diff --git a/packages/rrweb/rollup.config.js b/packages/rrweb/rollup.config.js deleted file mode 100644 index 998433bd..00000000 --- a/packages/rrweb/rollup.config.js +++ /dev/null @@ -1,261 +0,0 @@ -import typescript from 'rollup-plugin-typescript2'; -import esbuild from 'rollup-plugin-esbuild'; -import resolve from '@rollup/plugin-node-resolve'; -import postcss from 'rollup-plugin-postcss'; -import renameNodeModules from 'rollup-plugin-rename-node-modules'; -import webWorkerLoader from 'rollup-plugin-web-worker-loader'; -import pkg from './package.json'; - -function toRecordPath(path) { - return path - .replace(/^([\w]+)\//, '$1/record/') - .replace('rrweb', 'rrweb-record'); -} - -function toRecordPackPath(path) { - return path - .replace(/^([\w]+)\//, '$1/record/') - .replace('rrweb', 'rrweb-record-pack'); -} - -function toReplayPath(path) { - return path - .replace(/^([\w]+)\//, '$1/replay/') - .replace('rrweb', 'rrweb-replay'); -} - -function toReplayUnpackPath(path) { - return path - .replace(/^([\w]+)\//, '$1/replay/') - .replace('rrweb', 'rrweb-replay-unpack'); -} - -function toAllPath(path) { - return path.replace('rrweb', 'rrweb-all'); -} - -function toPluginPath(pluginName, stage) { - return (path) => - path - .replace(/^([\w]+)\//, '$1/plugins/') - .replace('rrweb', `${pluginName}-${stage}`); -} - -function toMinPath(path) { - return path.replace(/\.js$/, '.min.js'); -} - -const baseConfigs = [ - // all in one - { - input: './src/entries/all.ts', - name: 'rrweb', - pathFn: toAllPath, - esm: true, - }, - // record only - { - input: './src/record/index.ts', - name: 'rrwebRecord', - pathFn: toRecordPath, - }, - // record and pack - { - input: './src/entries/record-pack.ts', - name: 'rrwebRecord', - pathFn: toRecordPackPath, - }, - // replay only - { - input: './src/replay/index.ts', - name: 'rrwebReplay', - pathFn: toReplayPath, - }, - // replay and unpack - { - input: './src/entries/replay-unpack.ts', - name: 'rrwebReplay', - pathFn: toReplayUnpackPath, - }, - // record and replay - { - input: './src/index.ts', - name: 'rrweb', - pathFn: (p) => p, - }, - // plugins - { - input: './src/plugins/console/record/index.ts', - name: 'rrwebConsoleRecord', - pathFn: toPluginPath('console', 'record'), - }, - { - input: './src/plugins/canvas-webrtc/record/index.ts', - name: 'rrwebCanvasWebRTCRecord', - pathFn: toPluginPath('canvas-webrtc', 'record'), - }, - { - input: './src/plugins/canvas-webrtc/replay/index.ts', - name: 'rrwebCanvasWebRTCReplay', - pathFn: toPluginPath('canvas-webrtc', 'replay'), - }, - { - input: './src/plugins/console/replay/index.ts', - name: 'rrwebConsoleReplay', - pathFn: toPluginPath('console', 'replay'), - }, - { - input: './src/plugins/sequential-id/record/index.ts', - name: 'rrwebSequentialIdRecord', - pathFn: toPluginPath('sequential-id', 'record'), - }, - { - input: './src/plugins/sequential-id/replay/index.ts', - name: 'rrwebSequentialIdReplay', - pathFn: toPluginPath('sequential-id', 'replay'), - }, -]; - -let configs = []; - -function getPlugins(options = {}) { - const { minify = false, sourceMap = false } = options; - return [ - resolve({ browser: true }), - webWorkerLoader({ - targetPlatform: 'browser', - inline: true, - preserveSource: true, - sourceMap, - }), - esbuild({ - minify, - }), - postcss({ - extract: true, - inject: false, - minimize: minify, - sourceMap, - }), - ]; -} - -for (const c of baseConfigs) { - const basePlugins = [ - resolve({ browser: true }), - - // supports bundling `web-worker:..filename` - webWorkerLoader({ - targetPlatform: 'browser', - inline: true, - preserveSource: true, - }), - - typescript(), - ]; - const plugins = basePlugins.concat( - postcss({ - extract: false, - inject: false, - }), - ); - // browser - configs.push({ - input: c.input, - plugins: getPlugins(), - output: [ - { - name: c.name, - format: 'iife', - file: c.pathFn(pkg.unpkg), - }, - ], - }); - // browser + minify - configs.push({ - input: c.input, - plugins: getPlugins({ minify: true, sourceMap: true }), - output: [ - { - name: c.name, - format: 'iife', - file: toMinPath(c.pathFn(pkg.unpkg)), - sourcemap: true, - }, - ], - }); - // CommonJS - configs.push({ - input: c.input, - plugins, - output: [ - { - format: 'cjs', - file: c.pathFn('lib/rrweb.cjs'), - }, - ], - }); - if (c.esm) { - // ES module - configs.push({ - input: c.input, - plugins, - preserveModules: true, - output: [ - { - format: 'esm', - dir: 'es/rrweb', - plugins: [renameNodeModules('ext')], - }, - ], - }); - } -} - -if (process.env.BROWSER_ONLY) { - const browserOnlyBaseConfigs = [ - { - input: './src/index.ts', - name: 'rrweb', - pathFn: (p) => p, - }, - { - input: './src/entries/all.ts', - name: 'rrweb', - pathFn: toAllPath, - }, - { - input: './src/plugins/console/record/index.ts', - name: 'rrwebConsoleRecord', - pathFn: toPluginPath('console', 'record'), - }, - { - input: './src/plugins/canvas-webrtc/record/index.ts', - name: 'rrwebCanvasWebRTCRecord', - pathFn: toPluginPath('canvas-webrtc', 'record'), - }, - { - input: './src/plugins/canvas-webrtc/replay/index.ts', - name: 'rrwebCanvasWebRTCReplay', - pathFn: toPluginPath('canvas-webrtc', 'replay'), - }, - ]; - - configs = []; - - for (const c of browserOnlyBaseConfigs) { - configs.push({ - input: c.input, - plugins: getPlugins(), - output: [ - { - name: c.name, - format: 'iife', - file: c.pathFn(pkg.unpkg), - }, - ], - }); - } -} - -export default configs; diff --git a/packages/types/package.json b/packages/types/package.json index 7d1b1adb..0c7ebbf7 100644 --- a/packages/types/package.json +++ b/packages/types/package.json @@ -42,6 +42,7 @@ } }, "files": [ + "umd", "dist", "package.json" ], diff --git a/packages/utils/package.json b/packages/utils/package.json index 50e8556f..e94d031b 100644 --- a/packages/utils/package.json +++ b/packages/utils/package.json @@ -42,6 +42,7 @@ } }, "files": [ + "umd", "dist", "package.json" ], diff --git a/vite.config.default.ts b/vite.config.default.ts index dabc56ed..fe6d6d6c 100644 --- a/vite.config.default.ts +++ b/vite.config.default.ts @@ -1,9 +1,9 @@ /// import dts from 'vite-plugin-dts'; -import { copyFileSync } from 'node:fs'; +import { copyFileSync, mkdirSync, existsSync } from 'node:fs'; import { defineConfig, LibraryOptions, LibraryFormats, Plugin } from 'vite'; import { build, Format } from 'esbuild'; -import { resolve } from 'path'; +import { resolve, dirname } from 'path'; import { umdWrapper } from 'esbuild-plugin-umd-wrapper'; import * as fs from 'node:fs'; import { visualizer } from 'rollup-plugin-visualizer'; @@ -51,22 +51,38 @@ function minifyAndUMDPlugin({ outDir, }); } else { + const umdDir = dirname(outputFilePath).replace('/dist', '/umd'); + if (!existsSync(umdDir)) { + mkdirSync(umdDir); + } + const outUmd = `${outputFilePath}.umd.cjs`; await buildFile({ name, input: inputFilePath, - output: `${outputFilePath}.umd.cjs`, + output: outUmd, minify: false, isCss: false, outDir, }); + // Workaround because jsdelivr does use correct mime types for .umd.cjs + // More info: https://github.com/jsdelivr/jsdelivr/issues/18584 https://github.com/rrweb-io/rrweb/pull/1704 + copyFileSync( + outUmd, + `${outputFilePath.replace('/dist/', '/umd/')}.js`, + ); + const outUmdMin = `${outputFilePath}.umd.min.cjs`; await buildFile({ name, input: inputFilePath, - output: `${outputFilePath}.umd.min.cjs`, + output: outUmdMin, minify: true, isCss: false, outDir, }); + copyFileSync( + outUmdMin, + `${outputFilePath.replace('/dist/', '/umd/')}.min.js`, + ); } } }