-
-
Notifications
You must be signed in to change notification settings - Fork 1.6k
Open
Description
Problem
UMD usage is inconsistent across packages today. Some packages use a shared global (window.rrweb), while others use package-specific globals. This causes API confusion and load-order instability.
Why this matters
- Script-tag consumers can get different behavior depending on bundle load order.
- Docs and examples become hard to keep consistent.
- It is unclear whether UMD should optimize for shared namespace ergonomics or package isolation.
Current behavior (verified, post-PR #1762)
- Core modular packages currently use the same UMD global name:
@rrweb/all->rrweb
- Many other packages use package-specific globals:
rrweb-player->rrwebPlayerrrdom->rrdomrrdom-nodejs->rrdomNodejsrrweb-snapshot->rrwebSnapshot@rrweb/record->rrwebRecord@rrweb/replay->rrwebReplay@rrweb/types->rrwebTypes@rrweb/utils->rrwebUtils- plugins ->
rrwebPlugin...
Timeline relative to PR #1762
Reference: #1762
Before PR #1762:
- UMD behavior was already mixed across packages.
- Strategy 1 (see below) was effectively used for
@rrweb/all,@rrweb/record,@rrweb/replay. - Strategy 2 (see below) was effectively used for most other packages.
- Shared-global overwrite happens in practice:
- Load
@rrweb/recordUMD first ->rrweb.recordexists. - Load
@rrweb/replayUMD second ->rrweb.Replayerexists, andrrweb.recordis gone. - This is effectively “last one wins” for shared-global bundles.
- Load
After PR #1762 (current state):
- Directionally, the project is moving toward package-specific globals for modular packages.
- Mixed behavior/config still exists in practice.
- See the
Current behaviorsection above for the exact verified package matrix.
Target state:
- One explicit, documented UMD policy across all packages.
- Build config and runtime behavior match that policy consistently.
- Docs/examples and tests enforce the selected behavior.
API matrix discussed
| Package | Strategy 1: Shared-global model | Stategy 2: Package-specific model | Strategy 3: Hybrid model |
|---|---|---|---|
rrweb |
window.rrweb.record, window.rrweb.Replayer |
window.rrweb.record, window.rrweb.Replayer |
window.rrweb.record, window.rrweb.Replayer |
@rrweb/all |
window.rrweb.record, window.rrweb.Replayer, window.rrweb.pack, window.rrweb.unpack |
window.rrwebAll.record, window.rrwebAll.Replayer, window.rrwebAll.pack, window.rrwebAll.unpack |
window.rrweb.record, window.rrweb.Replayer, window.rrweb.pack, window.rrweb.unpack |
@rrweb/record |
window.rrweb.record, window.rrweb.record.addCustomEvent, window.rrweb.record.freezePage, window.rrweb.record.takeFullSnapshot |
window.rrwebRecord.record, window.rrwebRecord.addCustomEvent, window.rrwebRecord.freezePage, window.rrwebRecord.takeFullSnapshot |
window.rrwebRecord.record, window.rrwebRecord.addCustomEvent, window.rrwebRecord.freezePage, window.rrwebRecord.takeFullSnapshot |
@rrweb/replay |
window.rrweb.Replayer |
window.rrwebReplay.Replayer |
window.rrwebReplay.Replayer |
@rrweb/packer |
window.rrweb.pack, window.rrweb.unpack |
window.rrwebPacker.pack, window.rrwebPacker.unpack |
window.rrwebPacker.pack, window.rrwebPacker.unpack |
rrweb-player |
window.rrweb.Player |
window.rrwebPlayer.Player |
window.rrwebPlayer.Player |
rrweb-snapshot |
window.rrweb.snapshot, window.rrweb.rebuild |
window.rrwebSnapshot.snapshot, window.rrwebSnapshot.rebuild |
window.rrwebSnapshot.snapshot, window.rrwebSnapshot.rebuild |
rrdom |
window.rrweb.RRDocument, window.rrweb.diff |
window.rrdom.RRDocument, window.rrdom.diff |
window.rrdom.RRDocument, window.rrdom.diff |
rrdom-nodejs |
n/a (node-focused) | window.rrdomNodejs.* (mostly not browser usage) |
n/a (node-focused) |
rrvideo |
n/a (node-focused) | n/a (node-focused) | n/a (node-focused) |
@rrweb/types |
window.rrweb.EventType, window.rrweb.IncrementalSource, etc. |
window.rrwebTypes.EventType, window.rrwebTypes.IncrementalSource, etc. |
window.rrwebTypes.EventType, window.rrwebTypes.IncrementalSource, etc. |
@rrweb/utils |
window.rrweb.utils.patch |
window.rrwebUtils.patch |
window.rrwebUtils.patch |
@rrweb/web-extension |
n/a (extension package) | n/a (extension package) | n/a (extension package) |
@rrweb/rrweb-plugin-console-record |
window.rrweb.plugins.getRecordConsolePlugin |
window.rrwebPluginConsoleRecord.getRecordConsolePlugin |
window.rrwebPluginConsoleRecord.getRecordConsolePlugin |
@rrweb/rrweb-plugin-console-replay |
window.rrweb.plugins.getReplayConsolePlugin |
window.rrwebPluginConsoleReplay.getReplayConsolePlugin |
window.rrwebPluginConsoleReplay.getReplayConsolePlugin |
@rrweb/rrweb-plugin-sequential-id-record |
window.rrweb.plugins.getRecordSequentialIdPlugin |
window.rrwebPluginSequentialIdRecord.getRecordSequentialIdPlugin |
window.rrwebPluginSequentialIdRecord.getRecordSequentialIdPlugin |
@rrweb/rrweb-plugin-sequential-id-replay |
window.rrweb.plugins.getReplaySequentialIdPlugin |
window.rrwebPluginSequentialIdReplay.getReplaySequentialIdPlugin |
window.rrwebPluginSequentialIdReplay.getReplaySequentialIdPlugin |
@rrweb/rrweb-plugin-canvas-webrtc-record |
window.rrweb.plugins.RRWebPluginCanvasWebRTCRecord |
window.rrwebPluginCanvasWebRTCRecord.RRWebPluginCanvasWebRTCRecord |
window.rrwebPluginCanvasWebRTCRecord.RRWebPluginCanvasWebRTCRecord |
@rrweb/rrweb-plugin-canvas-webrtc-replay |
window.rrweb.plugins.RRWebPluginCanvasWebRTCReplay |
window.rrwebPluginCanvasWebRTCReplay.RRWebPluginCanvasWebRTCReplay |
window.rrwebPluginCanvasWebRTCReplay.RRWebPluginCanvasWebRTCReplay |
Strategy options
Strategy 1: Shared global (window.rrweb) for all packages.
- Pros: concise UMD API, familiar namespace, old v1 docs mostly apply to new packages
- Cons: collisions
- Without build tool changes: last import overwrites the earlier imports
- eg. @rrweb/record + @rrweb/replay:
rrweb.recordis overwritten by replay'swindow.rrweb = ...
- eg. @rrweb/record + @rrweb/replay:
- With build tool changes: collisions still possible on method name when multiple packages are imported
- eg. @rrweb/all + @rrweb/pack both define
rrweb.pack - quite hard to detect
- eg. @rrweb/all + @rrweb/pack both define
- We've been using strategy 2 for most packages since (apart from 3) since the .alphas were introduced a while ago. We can still change it because it is marked as alpha but it will break some people's setups.
- Without build tool changes: last import overwrites the earlier imports
Stategy 2: Package-specific globals for modular packages.
- Pros: package isolation, clearer ownership, no collision risk.
- Cons: more verbose UMD API, documentation not 1:1 with rrweb v1 (eg.
rrwebRecord.recordinstead ofrrweb.record)
Strategy 3: Package-specific globals - except for @rrweb/all and rrweb
- Keep
rrwebglobal for monolithic bundle only (@rrweb/allandrrweb). - Use package-specific globals for all other packages.
- Define compatibility behavior explicitly.
Decision requested
Pick one strategy and document it as the official UMD contract.
Acceptance criteria
- One documented UMD/global policy for all packages.
- Build config aligned with that policy.
- Docs/examples aligned with that policy.
- Load-order tests covering shared-global conflict cases.
- Clear migration notes for any breaking UMD/global changes.
Reactions are currently unavailable
Metadata
Metadata
Assignees
Labels
No labels