Decrease embedded img size for inlineImages (#836)
* Decrease embedded img size for inlineImages * Fix the test * Use webp for image snapshots * Implemented optional param dataURLOptions
This commit is contained in:
committed by
GitHub
parent
24202d2486
commit
4c06535309
@@ -7,6 +7,7 @@ import {
|
|||||||
idNodeMap,
|
idNodeMap,
|
||||||
MaskInputOptions,
|
MaskInputOptions,
|
||||||
SlimDOMOptions,
|
SlimDOMOptions,
|
||||||
|
DataURLOptions,
|
||||||
MaskTextFn,
|
MaskTextFn,
|
||||||
MaskInputFn,
|
MaskInputFn,
|
||||||
KeepIframeSrcFn,
|
KeepIframeSrcFn,
|
||||||
@@ -378,6 +379,7 @@ function serializeNode(
|
|||||||
maskInputOptions: MaskInputOptions;
|
maskInputOptions: MaskInputOptions;
|
||||||
maskTextFn: MaskTextFn | undefined;
|
maskTextFn: MaskTextFn | undefined;
|
||||||
maskInputFn: MaskInputFn | undefined;
|
maskInputFn: MaskInputFn | undefined;
|
||||||
|
dataURLOptions?: DataURLOptions,
|
||||||
inlineImages: boolean;
|
inlineImages: boolean;
|
||||||
recordCanvas: boolean;
|
recordCanvas: boolean;
|
||||||
keepIframeSrcFn: KeepIframeSrcFn;
|
keepIframeSrcFn: KeepIframeSrcFn;
|
||||||
@@ -393,6 +395,7 @@ function serializeNode(
|
|||||||
maskInputOptions = {},
|
maskInputOptions = {},
|
||||||
maskTextFn,
|
maskTextFn,
|
||||||
maskInputFn,
|
maskInputFn,
|
||||||
|
dataURLOptions = {},
|
||||||
inlineImages,
|
inlineImages,
|
||||||
recordCanvas,
|
recordCanvas,
|
||||||
keepIframeSrcFn,
|
keepIframeSrcFn,
|
||||||
@@ -513,17 +516,17 @@ function serializeNode(
|
|||||||
if ((n as ICanvas).__context === '2d') {
|
if ((n as ICanvas).__context === '2d') {
|
||||||
// only record this on 2d canvas
|
// only record this on 2d canvas
|
||||||
if (!is2DCanvasBlank(n as HTMLCanvasElement)) {
|
if (!is2DCanvasBlank(n as HTMLCanvasElement)) {
|
||||||
attributes.rr_dataURL = (n as HTMLCanvasElement).toDataURL();
|
attributes.rr_dataURL = (n as HTMLCanvasElement).toDataURL(dataURLOptions.type, dataURLOptions.quality);
|
||||||
}
|
}
|
||||||
} else if (!('__context' in n)) {
|
} else if (!('__context' in n)) {
|
||||||
// context is unknown, better not call getContext to trigger it
|
// context is unknown, better not call getContext to trigger it
|
||||||
const canvasDataURL = (n as HTMLCanvasElement).toDataURL();
|
const canvasDataURL = (n as HTMLCanvasElement).toDataURL(dataURLOptions.type, dataURLOptions.quality);
|
||||||
|
|
||||||
// create blank canvas of same dimensions
|
// create blank canvas of same dimensions
|
||||||
const blankCanvas = document.createElement('canvas');
|
const blankCanvas = document.createElement('canvas');
|
||||||
blankCanvas.width = (n as HTMLCanvasElement).width;
|
blankCanvas.width = (n as HTMLCanvasElement).width;
|
||||||
blankCanvas.height = (n as HTMLCanvasElement).height;
|
blankCanvas.height = (n as HTMLCanvasElement).height;
|
||||||
const blankCanvasDataURL = blankCanvas.toDataURL();
|
const blankCanvasDataURL = blankCanvas.toDataURL(dataURLOptions.type, dataURLOptions.quality);
|
||||||
|
|
||||||
// no need to save dataURL if it's the same as blank canvas
|
// no need to save dataURL if it's the same as blank canvas
|
||||||
if (canvasDataURL !== blankCanvasDataURL) {
|
if (canvasDataURL !== blankCanvasDataURL) {
|
||||||
@@ -545,7 +548,7 @@ function serializeNode(
|
|||||||
canvasService!.width = image.naturalWidth;
|
canvasService!.width = image.naturalWidth;
|
||||||
canvasService!.height = image.naturalHeight;
|
canvasService!.height = image.naturalHeight;
|
||||||
canvasCtx!.drawImage(image, 0, 0);
|
canvasCtx!.drawImage(image, 0, 0);
|
||||||
attributes.rr_dataURL = canvasService!.toDataURL();
|
attributes.rr_dataURL = canvasService!.toDataURL(dataURLOptions.type, dataURLOptions.quality);
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
console.warn(
|
console.warn(
|
||||||
`Cannot inline img src=${image.currentSrc}! Error: ${err}`,
|
`Cannot inline img src=${image.currentSrc}! Error: ${err}`,
|
||||||
@@ -774,6 +777,7 @@ export function serializeNodeWithId(
|
|||||||
maskTextFn: MaskTextFn | undefined;
|
maskTextFn: MaskTextFn | undefined;
|
||||||
maskInputFn: MaskInputFn | undefined;
|
maskInputFn: MaskInputFn | undefined;
|
||||||
slimDOMOptions: SlimDOMOptions;
|
slimDOMOptions: SlimDOMOptions;
|
||||||
|
dataURLOptions?: DataURLOptions;
|
||||||
keepIframeSrcFn?: KeepIframeSrcFn;
|
keepIframeSrcFn?: KeepIframeSrcFn;
|
||||||
inlineImages?: boolean;
|
inlineImages?: boolean;
|
||||||
recordCanvas?: boolean;
|
recordCanvas?: boolean;
|
||||||
@@ -796,6 +800,7 @@ export function serializeNodeWithId(
|
|||||||
maskTextFn,
|
maskTextFn,
|
||||||
maskInputFn,
|
maskInputFn,
|
||||||
slimDOMOptions,
|
slimDOMOptions,
|
||||||
|
dataURLOptions = {},
|
||||||
inlineImages = false,
|
inlineImages = false,
|
||||||
recordCanvas = false,
|
recordCanvas = false,
|
||||||
onSerialize,
|
onSerialize,
|
||||||
@@ -814,6 +819,7 @@ export function serializeNodeWithId(
|
|||||||
maskInputOptions,
|
maskInputOptions,
|
||||||
maskTextFn,
|
maskTextFn,
|
||||||
maskInputFn,
|
maskInputFn,
|
||||||
|
dataURLOptions,
|
||||||
inlineImages,
|
inlineImages,
|
||||||
recordCanvas,
|
recordCanvas,
|
||||||
keepIframeSrcFn,
|
keepIframeSrcFn,
|
||||||
@@ -880,6 +886,7 @@ export function serializeNodeWithId(
|
|||||||
maskTextFn,
|
maskTextFn,
|
||||||
maskInputFn,
|
maskInputFn,
|
||||||
slimDOMOptions,
|
slimDOMOptions,
|
||||||
|
dataURLOptions,
|
||||||
inlineImages,
|
inlineImages,
|
||||||
recordCanvas,
|
recordCanvas,
|
||||||
preserveWhiteSpace,
|
preserveWhiteSpace,
|
||||||
@@ -933,6 +940,7 @@ export function serializeNodeWithId(
|
|||||||
maskTextFn,
|
maskTextFn,
|
||||||
maskInputFn,
|
maskInputFn,
|
||||||
slimDOMOptions,
|
slimDOMOptions,
|
||||||
|
dataURLOptions,
|
||||||
inlineImages,
|
inlineImages,
|
||||||
recordCanvas,
|
recordCanvas,
|
||||||
preserveWhiteSpace,
|
preserveWhiteSpace,
|
||||||
@@ -966,6 +974,7 @@ function snapshot(
|
|||||||
maskTextFn?: MaskTextFn;
|
maskTextFn?: MaskTextFn;
|
||||||
maskInputFn?: MaskTextFn;
|
maskInputFn?: MaskTextFn;
|
||||||
slimDOM?: boolean | SlimDOMOptions;
|
slimDOM?: boolean | SlimDOMOptions;
|
||||||
|
dataURLOptions?: DataURLOptions,
|
||||||
inlineImages?: boolean;
|
inlineImages?: boolean;
|
||||||
recordCanvas?: boolean;
|
recordCanvas?: boolean;
|
||||||
preserveWhiteSpace?: boolean;
|
preserveWhiteSpace?: boolean;
|
||||||
@@ -987,6 +996,7 @@ function snapshot(
|
|||||||
maskTextFn,
|
maskTextFn,
|
||||||
maskInputFn,
|
maskInputFn,
|
||||||
slimDOM = false,
|
slimDOM = false,
|
||||||
|
dataURLOptions,
|
||||||
preserveWhiteSpace,
|
preserveWhiteSpace,
|
||||||
onSerialize,
|
onSerialize,
|
||||||
onIframeLoad,
|
onIframeLoad,
|
||||||
@@ -1051,6 +1061,7 @@ function snapshot(
|
|||||||
maskTextFn,
|
maskTextFn,
|
||||||
maskInputFn,
|
maskInputFn,
|
||||||
slimDOMOptions,
|
slimDOMOptions,
|
||||||
|
dataURLOptions,
|
||||||
inlineImages,
|
inlineImages,
|
||||||
recordCanvas,
|
recordCanvas,
|
||||||
preserveWhiteSpace,
|
preserveWhiteSpace,
|
||||||
|
|||||||
@@ -112,6 +112,11 @@ export type SlimDOMOptions = Partial<{
|
|||||||
headMetaVerification: boolean;
|
headMetaVerification: boolean;
|
||||||
}>;
|
}>;
|
||||||
|
|
||||||
|
export type DataURLOptions = Partial<{
|
||||||
|
type: string;
|
||||||
|
quality: number;
|
||||||
|
}>;
|
||||||
|
|
||||||
export type MaskTextFn = (text: string) => string;
|
export type MaskTextFn = (text: string) => string;
|
||||||
export type MaskInputFn = (text: string) => string;
|
export type MaskInputFn = (text: string) => string;
|
||||||
|
|
||||||
|
|||||||
@@ -199,14 +199,17 @@ iframe.contentDocument.querySelector('center').clientHeight
|
|||||||
waitUntil: 'load',
|
waitUntil: 'load',
|
||||||
});
|
});
|
||||||
await page.waitForSelector('img', { timeout: 1000 });
|
await page.waitForSelector('img', { timeout: 1000 });
|
||||||
await page.evaluate(`${code}var snapshot = rrweb.snapshot(document, {inlineImages: true, inlineStylesheet: false});
|
await page.evaluate(`${code}var snapshot = rrweb.snapshot(document, {
|
||||||
`);
|
dataURLOptions: { type: "image/webp", quality: 0.8 },
|
||||||
|
inlineImages: true,
|
||||||
|
inlineStylesheet: false
|
||||||
|
})`);
|
||||||
await page.waitFor(100);
|
await page.waitFor(100);
|
||||||
const snapshot = await page.evaluate(
|
const snapshot = await page.evaluate(
|
||||||
'JSON.stringify(snapshot[0], null, 2);',
|
'JSON.stringify(snapshot[0], null, 2);',
|
||||||
);
|
);
|
||||||
assert(snapshot.includes('"rr_dataURL"'));
|
assert(snapshot.includes('"rr_dataURL"'));
|
||||||
assert(snapshot.includes('data:image/png;base64,'));
|
assert(snapshot.includes('data:image/webp;base64,'));
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
import { serializedNodeWithId, INode, idNodeMap, MaskInputOptions, SlimDOMOptions, MaskTextFn, MaskInputFn, KeepIframeSrcFn } from './types';
|
import { serializedNodeWithId, INode, idNodeMap, MaskInputOptions, SlimDOMOptions, DataURLOptions, MaskTextFn, MaskInputFn, KeepIframeSrcFn } from './types';
|
||||||
export declare const IGNORED_NODE = -2;
|
export declare const IGNORED_NODE = -2;
|
||||||
export declare function absoluteToStylesheet(cssText: string | null, href: string): string;
|
export declare function absoluteToStylesheet(cssText: string | null, href: string): string;
|
||||||
export declare function absoluteToDoc(doc: Document, attributeValue: string): string;
|
export declare function absoluteToDoc(doc: Document, attributeValue: string): string;
|
||||||
@@ -18,6 +18,7 @@ export declare function serializeNodeWithId(n: Node | INode, options: {
|
|||||||
maskTextFn: MaskTextFn | undefined;
|
maskTextFn: MaskTextFn | undefined;
|
||||||
maskInputFn: MaskInputFn | undefined;
|
maskInputFn: MaskInputFn | undefined;
|
||||||
slimDOMOptions: SlimDOMOptions;
|
slimDOMOptions: SlimDOMOptions;
|
||||||
|
dataURLOptions?: DataURLOptions;
|
||||||
keepIframeSrcFn?: KeepIframeSrcFn;
|
keepIframeSrcFn?: KeepIframeSrcFn;
|
||||||
inlineImages?: boolean;
|
inlineImages?: boolean;
|
||||||
recordCanvas?: boolean;
|
recordCanvas?: boolean;
|
||||||
@@ -36,6 +37,7 @@ declare function snapshot(n: Document, options?: {
|
|||||||
maskTextFn?: MaskTextFn;
|
maskTextFn?: MaskTextFn;
|
||||||
maskInputFn?: MaskTextFn;
|
maskInputFn?: MaskTextFn;
|
||||||
slimDOM?: boolean | SlimDOMOptions;
|
slimDOM?: boolean | SlimDOMOptions;
|
||||||
|
dataURLOptions?: DataURLOptions;
|
||||||
inlineImages?: boolean;
|
inlineImages?: boolean;
|
||||||
recordCanvas?: boolean;
|
recordCanvas?: boolean;
|
||||||
preserveWhiteSpace?: boolean;
|
preserveWhiteSpace?: boolean;
|
||||||
|
|||||||
4
packages/rrweb-snapshot/typings/types.d.ts
vendored
4
packages/rrweb-snapshot/typings/types.d.ts
vendored
@@ -91,6 +91,10 @@ export declare type SlimDOMOptions = Partial<{
|
|||||||
headMetaAuthorship: boolean;
|
headMetaAuthorship: boolean;
|
||||||
headMetaVerification: boolean;
|
headMetaVerification: boolean;
|
||||||
}>;
|
}>;
|
||||||
|
export declare type DataURLOptions = Partial<{
|
||||||
|
type: string;
|
||||||
|
quality: number;
|
||||||
|
}>;
|
||||||
export declare type MaskTextFn = (text: string) => string;
|
export declare type MaskTextFn = (text: string) => string;
|
||||||
export declare type MaskInputFn = (text: string) => string;
|
export declare type MaskInputFn = (text: string) => string;
|
||||||
export declare type KeepIframeSrcFn = (src: string) => boolean;
|
export declare type KeepIframeSrcFn = (src: string) => boolean;
|
||||||
|
|||||||
Reference in New Issue
Block a user