⚗️ Capture dirty canvas images - #4951
Conversation
Bundles Sizes Evolution
|
|
|
@codex review |
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: b471339357
ℹ️ About Codex in GitHub
Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".
|
|
||
| export async function computeCanvasImageHash(blob: Blob): Promise<string> { | ||
| const imageBytes = await readBlobAsArrayBuffer(blob) | ||
| const digest = await crypto.subtle.digest('SHA-256', imageBytes) |
There was a problem hiding this comment.
Provide a fallback when SubtleCrypto is unavailable
issue: When canvas recording runs on a non-secure HTTP origin or another context without SubtleCrypto, crypto.subtle is unavailable and every hash attempt rejects. startCanvasCapture swallows that rejection after the canvas has already been marked clean, so canvasImageObservable never emits the frame and it is not retried until another mutation. Guard the API and use a supported fallback, or explicitly disable canvas capture before clearing dirty frames.
Useful? React with 👍 / 👎.
| const canvasManager = createCanvasManager() | ||
| trackers.push(trackCanvas2DMutations(canvasManager.markCanvasDirty)) | ||
| trackers.push( | ||
| trackCanvas2DMutations(canvasManager.markCanvasDirty), |
There was a problem hiding this comment.
Seed already-rendered canvases when recording starts
issue: If a canvas is painted before record() starts—particularly when startSessionReplayRecordingManually is enabled—and is not painted again, none of its drawing calls pass through this newly installed instrumentation. The manager starts empty, and full-snapshot serialization has no path that marks existing canvas elements dirty, so the canvas image is never emitted and the replay remains blank for that element. Seed canvases encountered by the initial snapshot, or otherwise capture their current contents when recording begins.
Useful? React with 👍 / 👎.
| const captureIntervalId = setInterval(captureDirtyCanvases, ONE_SECOND / maxFramesPerSecond) | ||
|
|
||
| function captureDirtyCanvases() { | ||
| canvasManager.getDirtyCanvases().forEach((canvas) => { |
There was a problem hiding this comment.
Skip canvases that are not part of the replay DOM
issue: In applications that use detached canvases for image processing or as scratch buffers, the global 2D-context instrumentation marks those canvases dirty too, and this loop encodes and hashes every one of them even though they have no serialized replay node and cannot be displayed in the replay. Repeated drawing on such buffers can therefore add expensive PNG encoding and SHA-256 work at every sampling interval. Gate capture on the canvas being represented in the recording scope, while deferring newly drawn canvases until they are serialized.
Useful? React with 👍 / 👎.
b471339 to
6a43e13
Compare
Motivation
Session Replay canvas support needs to capture changed canvas contents at the configured frame rate without repeatedly processing identical images. This stacked PR adds the image-capture and in-memory frame-deduplication stage after the canvas dirty-state pre-filter introduced in #4949.
Design references:
Changes
canvasImageObservablefor the resource-upload and replay-record follow-ups.Resource upload and canvas-to-resource replay records are intentionally left for follow-up PRs.
Test instructions
yarn test:unit --spec packages/browser-rum/src/domain/record/canvas/canvasCapture.spec.ts --spec packages/browser-rum/src/domain/record/canvas/canvasManager.spec.ts --spec packages/browser-rum/src/domain/record/trackers/trackCanvas.spec.ts --spec packages/browser-rum/src/domain/record/record.spec.ts yarn typecheck yarn eslint packages/browser-rum/src/domain/record/canvas/canvasCapture.ts packages/browser-rum/src/domain/record/canvas/canvasCapture.spec.ts packages/browser-rum/src/domain/record/canvas/canvasManager.ts packages/browser-rum/src/domain/record/canvas/canvasManager.spec.ts packages/browser-rum/src/domain/record/record.ts packages/browser-rum/src/domain/record/record.spec.ts test/e2e/scenario/recorder/canvas.scenario.ts yarn build:apps --app vanilla yarn test:e2e -g "captures dirty canvases periodically"Checklist