diff --git a/.changeset/breezy-cats-heal.md b/.changeset/breezy-cats-heal.md new file mode 100644 index 0000000000..6e1bc2fa46 --- /dev/null +++ b/.changeset/breezy-cats-heal.md @@ -0,0 +1,5 @@ +--- +'rrweb': patch +--- + +fix: createImageBitmap throws DOMException if source is 0 width or height diff --git a/.changeset/light-fireants-exercise.md b/.changeset/light-fireants-exercise.md new file mode 100644 index 0000000000..a845151cc8 --- /dev/null +++ b/.changeset/light-fireants-exercise.md @@ -0,0 +1,2 @@ +--- +--- diff --git a/packages/rrweb/scripts/repl.js b/packages/rrweb/scripts/repl.js index 0bf4a7de62..a36f34a285 100644 --- a/packages/rrweb/scripts/repl.js +++ b/packages/rrweb/scripts/repl.js @@ -22,40 +22,44 @@ void (async () => { let events = []; async function injectRecording(frame) { - await frame.evaluate((rrwebCode) => { - const win = window; - if (win.__IS_RECORDING__) return; - win.__IS_RECORDING__ = true; + try { + await frame.evaluate((rrwebCode) => { + const win = window; + if (win.__IS_RECORDING__) return; + win.__IS_RECORDING__ = true; - (async () => { - function loadScript(code) { - const s = document.createElement('script'); - let r = false; - s.type = 'text/javascript'; - s.innerHTML = code; - if (document.head) { - document.head.append(s); - } else { - requestAnimationFrame(() => { + (async () => { + function loadScript(code) { + const s = document.createElement('script'); + let r = false; + s.type = 'text/javascript'; + s.innerHTML = code; + if (document.head) { document.head.append(s); - }); + } else { + requestAnimationFrame(() => { + document.head.append(s); + }); + } } - } - loadScript(rrwebCode); + loadScript(rrwebCode); - win.events = []; - rrweb.record({ - emit: (event) => { - win.events.push(event); - win._replLog(event); - }, - plugins: [], - recordCanvas: true, - recordCrossOriginIframes: true, - collectFonts: true, - }); - })(); - }, code); + win.events = []; + rrweb.record({ + emit: (event) => { + win.events.push(event); + win._replLog(event); + }, + plugins: [], + recordCanvas: true, + recordCrossOriginIframes: true, + collectFonts: true, + }); + })(); + }, code); + } catch (e) { + console.error('failed to inject recording script:', e); + } } await start('https://react-redux.realworld.io'); diff --git a/packages/rrweb/scripts/stream.js b/packages/rrweb/scripts/stream.js index bf9a3b2cab..5f838908f1 100644 --- a/packages/rrweb/scripts/stream.js +++ b/packages/rrweb/scripts/stream.js @@ -24,57 +24,61 @@ const pluginCode = fs.readFileSync( ); async function injectRecording(frame) { - await frame.evaluate( - (rrwebCode, pluginCode) => { - const win = window; - if (win.__IS_RECORDING__) return; - win.__IS_RECORDING__ = true; - - (async () => { - function loadScript(code) { - const s = document.createElement('script'); - s.type = 'text/javascript'; - s.innerHTML = code; - if (document.head) { - document.head.append(s); - } else { - requestAnimationFrame(() => { + try { + await frame.evaluate( + (rrwebCode, pluginCode) => { + const win = window; + if (win.__IS_RECORDING__) return; + win.__IS_RECORDING__ = true; + + (async () => { + function loadScript(code) { + const s = document.createElement('script'); + s.type = 'text/javascript'; + s.innerHTML = code; + if (document.head) { document.head.append(s); - }); + } else { + requestAnimationFrame(() => { + document.head.append(s); + }); + } } - } - loadScript(rrwebCode); - loadScript(pluginCode); - - win.events = []; - window.record = win.rrweb.record; - window.plugin = - new rrwebCanvasWebRTCRecord.RRWebPluginCanvasWebRTCRecord({ - signalSendCallback: (msg) => { - // [record#callback] provides canvas id, stream, and webrtc sdpOffer signal & connect message - _signal(msg); + loadScript(rrwebCode); + loadScript(pluginCode); + + win.events = []; + window.record = win.rrweb.record; + window.plugin = + new rrwebCanvasWebRTCRecord.RRWebPluginCanvasWebRTCRecord({ + signalSendCallback: (msg) => { + // [record#callback] provides canvas id, stream, and webrtc sdpOffer signal & connect message + _signal(msg); + }, + }); + + window.record({ + emit: (event) => { + win.events.push(event); + win._captureEvent(event); + }, + plugins: [window.plugin.initPlugin()], + recordCanvas: false, + recordCrossOriginIframes: true, + collectFonts: true, + captureAssets: { + objectURLs: true, + origins: true, }, }); - - window.record({ - emit: (event) => { - win.events.push(event); - win._captureEvent(event); - }, - plugins: [window.plugin.initPlugin()], - recordCanvas: false, - recordCrossOriginIframes: true, - collectFonts: true, - captureAssets: { - objectURLs: true, - origins: true, - }, - }); - })(); - }, - code, - pluginCode, - ); + })(); + }, + code, + pluginCode, + ); + } catch (e) { + console.error('failed to inject script, error:', e); + } } async function startReplay(page, serverURL, recordedPage) { diff --git a/packages/rrweb/src/record/observers/canvas/canvas-manager.ts b/packages/rrweb/src/record/observers/canvas/canvas-manager.ts index 38dfd8fa8e..6e367ed970 100644 --- a/packages/rrweb/src/record/observers/canvas/canvas-manager.ts +++ b/packages/rrweb/src/record/observers/canvas/canvas-manager.ts @@ -185,6 +185,12 @@ export class CanvasManager { .forEach(async (canvas: HTMLCanvasElement) => { const id = this.mirror.getId(canvas); if (snapshotInProgressMap.get(id)) return; + + // The browser throws if the canvas is 0 in size + // Uncaught (in promise) DOMException: Failed to execute 'createImageBitmap' on 'Window': The source image width is 0. + // Assuming the same happens with height + if (canvas.width === 0 || canvas.height === 0) return; + snapshotInProgressMap.set(id, true); if (['webgl', 'webgl2'].includes((canvas as ICanvas).__context)) { // if the canvas hasn't been modified recently,