Skip to content

Commit

Permalink
improve robustness of inlineImages feature (rrweb-io#812)
Browse files Browse the repository at this point in the history
* fix: add inlineImages option to rrrweb recorder and try to make the code more robust

* Improve robustness
  • Loading branch information
YunFeng0817 authored Jan 25, 2022
1 parent ca5ecba commit 0c27ad2
Show file tree
Hide file tree
Showing 3 changed files with 33 additions and 33 deletions.
9 changes: 6 additions & 3 deletions packages/rrweb-snapshot/src/rebuild.ts
Original file line number Diff line number Diff line change
Expand Up @@ -227,10 +227,13 @@ function buildNode(
}
};
} else if (tagName === 'img' && name === 'rr_dataURL') {
const image = (node as HTMLImageElement);
const image = node as HTMLImageElement;
if (!image.currentSrc.startsWith('data:')) {
// backup original img src
image.setAttribute('data-rrweb-src', image.currentSrc);
// Backup original img src. It may not have been set yet.
image.setAttribute(
'rrweb-original-src',
n.attributes['src'] as string,
);
image.src = value;
}
image.removeAttribute(name);
Expand Down
39 changes: 19 additions & 20 deletions packages/rrweb-snapshot/src/snapshot.ts
Original file line number Diff line number Diff line change
Expand Up @@ -78,17 +78,6 @@ function extractOrigin(url: string): string {
let canvasService: HTMLCanvasElement | null;
let canvasCtx: CanvasRenderingContext2D | null;

function initCanvasService(doc: Document) {
if (!canvasService) {
canvasService = doc.createElement('canvas');
}
if (!canvasCtx) {
canvasCtx = canvasService.getContext('2d');
}
canvasService.width = 0;
canvasService.height = 0;
}

const URL_IN_CSS_REF = /url\((?:(')([^']*)'|(")(.*?)"|([^)]*))\)/gm;
const RELATIVE_PATH = /^(?!www\.|(?:http|ftp)s?:\/\/|[A-Za-z]:\\|\/\/|#).*/;
const DATA_URI = /^(data:)([^,]*),(.*)/i;
Expand Down Expand Up @@ -515,14 +504,27 @@ function serializeNode(
attributes.rr_dataURL = (n as HTMLCanvasElement).toDataURL();
}
// save image offline
if (tagName === 'img' && inlineImages && canvasService && canvasCtx) {
const image = (n as HTMLImageElement);
if (tagName === 'img' && inlineImages) {
if (!canvasService) {
canvasService = doc.createElement('canvas');
canvasCtx = canvasService.getContext('2d');
}
const image = n as HTMLImageElement;
const oldValue = image.crossOrigin;
image.crossOrigin = 'anonymous';
try {
canvasService.width = image.naturalWidth;
canvasService.height = image.naturalHeight;
canvasCtx.drawImage(image, 0, 0);
attributes.rr_dataURL = canvasService.toDataURL();
const recordInlineImage = () => {
canvasService!.width = image.naturalWidth;
canvasService!.height = image.naturalHeight;
canvasCtx!.drawImage(image, 0, 0);
attributes.rr_dataURL = canvasService!.toDataURL();
oldValue
? (attributes.crossOrigin = oldValue)
: delete attributes.crossOrigin;
};
// The image content may not have finished loading yet.
if (image.complete && image.naturalWidth !== 0) recordInlineImage();
else image.onload = recordInlineImage;
} catch {
// ignore error
}
Expand Down Expand Up @@ -832,9 +834,6 @@ export function serializeNodeWithId(
) {
preserveWhiteSpace = false;
}
if (inlineImages) {
initCanvasService(doc);
}
const bypassOptions = {
doc,
map,
Expand Down
18 changes: 8 additions & 10 deletions packages/rrweb-snapshot/test/integration.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -194,22 +194,20 @@ iframe.contentDocument.querySelector('center').clientHeight

it('correctly saves images offline', async () => {
const page: puppeteer.Page = await browser.newPage();
// console for debug
// tslint:disable-next-line: no-console
page.on('console', (msg) => console.log(msg.text()));

await page.goto('http://localhost:3030/html/picture.html', { waitUntil: 'load' });
await page.goto('http://localhost:3030/html/picture.html', {
waitUntil: 'load',
});
await page.waitForSelector('img', { timeout: 1000 });

const snapshot = await page.evaluate(`${code}
const [snap] = rrweb.snapshot(document, {inlineImages: true, inlineStylesheet: false});
JSON.stringify(snap, null, 2);
await page.evaluate(`${code}var snapshot = rrweb.snapshot(document, {inlineImages: true, inlineStylesheet: false});
`);

await page.waitFor(100);
const snapshot = await page.evaluate(
'JSON.stringify(snapshot[0], null, 2);',
);
assert(snapshot.includes('"rr_dataURL"'));
assert(snapshot.includes('data:image/png;base64,'));
});

});

describe('iframe integration tests', function (this: ISuite) {
Expand Down

0 comments on commit 0c27ad2

Please sign in to comment.