Skip to content

Encode inlineImages as webp instead of default lossless PNG (#44) - #45

Open
SaintPepsi wants to merge 1 commit into
mainfrom
fix/44-webp-inline-images
Open

Encode inlineImages as webp instead of default lossless PNG (#44)#45
SaintPepsi wants to merge 1 commit into
mainfrom
fix/44-webp-inline-images

Conversation

@SaintPepsi

@SaintPepsi SaintPepsi commented Jul 22, 2026

Copy link
Copy Markdown
Owner

Summary

  • rrweb's inlineImages draws each <img> to canvas and re-encodes it; without dataURLOptions that defaults to lossless PNG, which on image-heavy pages is the dominant contributor to export size.
  • The recording linked from File size is way too much #44 was 87.6 MB, almost entirely lossless-PNG data URIs of Village Cinemas' poster/banner images (44 inlined images).
  • REPLAY_DESIGN.md §4 already specced dataURLOptions: { type: 'image/webp', quality: 0.6 } for exactly this reason; it never made it into the actual record() call in src/rrweb-recorder.js. This PR wires it in.

This is fix #1 of the 3 mitigations from my comment on #44 (compression of the event stream via @rrweb/packer/fflate, and the originally-specced sampling/slimDOMOptions, are separate, larger follow-ups — not attempted here).

Test plan

  • npm run build — bundles clean, dist/rrweb-recorder.js unaffected in size class
  • bun test test/ — 88/90 pass; the 2 failures (test/packaging.test.js) are pre-existing on main, unrelated to this change: one is a Windows path-separator artifact in the packaged-file check, the other is docs/STORE_LISTING.md genuinely missing CWS justification blocks for several permissions (a real doc gap, not a path issue) — confirmed by running the same test against unmodified main
  • bun test test/recorder.test.js — 9/9 pass, including a new causal-guard assertion (capturedOpts.dataURLOptions) mirroring the existing inlineImages guard
  • Disconfirming input: manually reverted dataURLOptions and reran test/recorder.test.js — the new assertion goes red as expected, confirming it actually catches a regression

🤖 Generated with Claude Code


Note: #47 (fix/44-sampling-slim-dom) edits the same record({...}) call block in src/rrweb-recorder.js. Both are independent, non-stacked PRs — merging both will hit a textual (not semantic) conflict at that call site that needs manual reconciliation; the options compose fine (inlineImages, dataURLOptions, sampling, slimDOMOptions are all independent keys).

rrweb's inlineImages draws each <img> to canvas and re-encodes it; without
dataURLOptions that defaults to lossless PNG, which on image-heavy pages is
the dominant contributor to export size. The recording linked from #44 was
87.6 MB, almost entirely lossless PNGs of Village Cinemas' poster/banner
images. REPLAY_DESIGN.md §4 specced webp@0.6 for exactly this reason but it
never made it into the actual record() call.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
SaintPepsi added a commit that referenced this pull request Jul 22, 2026
…mment

- docs/feature-set/bug-report.md claimed both the webp image fix (a separate,
  non-stacked PR — #45) and this PR's compression fix were shipped. Since
  these PRs merge independently, that overclaims when #46 lands without #45.
  Scope the wording to what this PR actually does.
- encodeOjData(undefined) previously produced a corrupt blob (JSON.stringify
  returns the *value* undefined, not a string) that would only fail later, at
  decode time, far from the actual cause. Throw at the source instead. Not
  reachable from any current call site — report-builder.js and
  redact-report.mjs always pass real objects — but a latent footgun for
  future callers of what's designed as a reusable codec.
- Corrected the corruption-canary comment in redact-report.mjs: it now bounds
  gzip+base64 output, not raw-JSON token substitution, so the old "output ≈
  input" justification no longer described the actual mechanism.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant