pick #286, export slim DOM options
This commit is contained in:
@@ -1,4 +1,4 @@
|
|||||||
import { snapshot, MaskInputOptions } from 'rrweb-snapshot';
|
import { snapshot, MaskInputOptions, SlimDOMOptions } from 'rrweb-snapshot';
|
||||||
import { initObservers, mutationBuffer } from './observer';
|
import { initObservers, mutationBuffer } from './observer';
|
||||||
import {
|
import {
|
||||||
mirror,
|
mirror,
|
||||||
@@ -38,6 +38,7 @@ function record<T = eventWithTime>(
|
|||||||
inlineStylesheet = true,
|
inlineStylesheet = true,
|
||||||
maskAllInputs,
|
maskAllInputs,
|
||||||
maskInputOptions: _maskInputOptions,
|
maskInputOptions: _maskInputOptions,
|
||||||
|
slimDOMOptions: _slimDOMOptions,
|
||||||
maskInputFn,
|
maskInputFn,
|
||||||
hooks,
|
hooks,
|
||||||
packFn,
|
packFn,
|
||||||
@@ -78,6 +79,26 @@ function record<T = eventWithTime>(
|
|||||||
? _maskInputOptions
|
? _maskInputOptions
|
||||||
: {};
|
: {};
|
||||||
|
|
||||||
|
const slimDOMOptions: SlimDOMOptions =
|
||||||
|
_slimDOMOptions === true || _slimDOMOptions === 'all'
|
||||||
|
? {
|
||||||
|
script: true,
|
||||||
|
comment: true,
|
||||||
|
headFavicon: true,
|
||||||
|
headWhitespace: true,
|
||||||
|
headMetaSocial: true,
|
||||||
|
headMetaRobots: true,
|
||||||
|
headMetaHttpEquiv: true,
|
||||||
|
headMetaVerification: true,
|
||||||
|
// the following are off for slimDOMOptions === true,
|
||||||
|
// as they destroy some (hidden) info:
|
||||||
|
headMetaAuthorship: _slimDOMOptions === 'all',
|
||||||
|
headMetaDescKeywords: _slimDOMOptions === 'all',
|
||||||
|
}
|
||||||
|
: _slimDOMOptions === false
|
||||||
|
? {}
|
||||||
|
: _slimDOMOptions;
|
||||||
|
|
||||||
polyfill();
|
polyfill();
|
||||||
|
|
||||||
let lastFullSnapshotEvent: eventWithTime;
|
let lastFullSnapshotEvent: eventWithTime;
|
||||||
@@ -134,6 +155,7 @@ function record<T = eventWithTime>(
|
|||||||
blockSelector,
|
blockSelector,
|
||||||
inlineStylesheet,
|
inlineStylesheet,
|
||||||
maskAllInputs: maskInputOptions,
|
maskAllInputs: maskInputOptions,
|
||||||
|
slimDOM: slimDOMOptions,
|
||||||
recordCanvas,
|
recordCanvas,
|
||||||
});
|
});
|
||||||
|
|
||||||
@@ -299,6 +321,7 @@ function record<T = eventWithTime>(
|
|||||||
sampling,
|
sampling,
|
||||||
recordCanvas,
|
recordCanvas,
|
||||||
collectFonts,
|
collectFonts,
|
||||||
|
slimDOMOptions,
|
||||||
},
|
},
|
||||||
hooks,
|
hooks,
|
||||||
),
|
),
|
||||||
|
|||||||
@@ -3,6 +3,8 @@ import {
|
|||||||
serializeNodeWithId,
|
serializeNodeWithId,
|
||||||
transformAttribute,
|
transformAttribute,
|
||||||
MaskInputOptions,
|
MaskInputOptions,
|
||||||
|
SlimDOMOptions,
|
||||||
|
IGNORED_NODE,
|
||||||
} from 'rrweb-snapshot';
|
} from 'rrweb-snapshot';
|
||||||
import {
|
import {
|
||||||
mutationRecord,
|
mutationRecord,
|
||||||
@@ -13,7 +15,7 @@ import {
|
|||||||
removedNodeMutation,
|
removedNodeMutation,
|
||||||
addedNodeMutation,
|
addedNodeMutation,
|
||||||
} from '../types';
|
} from '../types';
|
||||||
import { mirror, isBlocked, isAncestorRemoved } from '../utils';
|
import { mirror, isBlocked, isAncestorRemoved, isIgnored } from '../utils';
|
||||||
|
|
||||||
type DoubleLinkedListNode = {
|
type DoubleLinkedListNode = {
|
||||||
previous: DoubleLinkedListNode | null;
|
previous: DoubleLinkedListNode | null;
|
||||||
@@ -145,6 +147,7 @@ export default class MutationBuffer {
|
|||||||
private inlineStylesheet: boolean;
|
private inlineStylesheet: boolean;
|
||||||
private maskInputOptions: MaskInputOptions;
|
private maskInputOptions: MaskInputOptions;
|
||||||
private recordCanvas: boolean;
|
private recordCanvas: boolean;
|
||||||
|
private slimDOMOptions: SlimDOMOptions;
|
||||||
|
|
||||||
public init(
|
public init(
|
||||||
cb: mutationCallBack,
|
cb: mutationCallBack,
|
||||||
@@ -153,12 +156,14 @@ export default class MutationBuffer {
|
|||||||
inlineStylesheet: boolean,
|
inlineStylesheet: boolean,
|
||||||
maskInputOptions: MaskInputOptions,
|
maskInputOptions: MaskInputOptions,
|
||||||
recordCanvas: boolean,
|
recordCanvas: boolean,
|
||||||
|
slimDOMOptions: SlimDOMOptions,
|
||||||
) {
|
) {
|
||||||
this.blockClass = blockClass;
|
this.blockClass = blockClass;
|
||||||
this.blockSelector = blockSelector;
|
this.blockSelector = blockSelector;
|
||||||
this.inlineStylesheet = inlineStylesheet;
|
this.inlineStylesheet = inlineStylesheet;
|
||||||
this.maskInputOptions = maskInputOptions;
|
this.maskInputOptions = maskInputOptions;
|
||||||
this.recordCanvas = recordCanvas;
|
this.recordCanvas = recordCanvas;
|
||||||
|
this.slimDOMOptions = slimDOMOptions;
|
||||||
this.emissionCallback = cb;
|
this.emissionCallback = cb;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -193,8 +198,12 @@ export default class MutationBuffer {
|
|||||||
*/
|
*/
|
||||||
const addList = new DoubleLinkedList();
|
const addList = new DoubleLinkedList();
|
||||||
const getNextId = (n: Node): number | null => {
|
const getNextId = (n: Node): number | null => {
|
||||||
let nextId =
|
let ns: Node | null = n;
|
||||||
n.nextSibling && mirror.getId((n.nextSibling as unknown) as INode);
|
let nextId: number | null = IGNORED_NODE; // slimDOM: ignored
|
||||||
|
while (nextId === IGNORED_NODE) {
|
||||||
|
ns = ns && ns.nextSibling;
|
||||||
|
nextId = ns && mirror.getId((ns as unknown) as INode);
|
||||||
|
}
|
||||||
if (nextId === -1 && isBlocked(n.nextSibling, this.blockClass)) {
|
if (nextId === -1 && isBlocked(n.nextSibling, this.blockClass)) {
|
||||||
nextId = null;
|
nextId = null;
|
||||||
}
|
}
|
||||||
@@ -209,21 +218,24 @@ export default class MutationBuffer {
|
|||||||
if (parentId === -1 || nextId === -1) {
|
if (parentId === -1 || nextId === -1) {
|
||||||
return addList.addNode(n);
|
return addList.addNode(n);
|
||||||
}
|
}
|
||||||
adds.push({
|
let sn = serializeNodeWithId(n, {
|
||||||
parentId,
|
doc: document,
|
||||||
nextId,
|
map: mirror.map,
|
||||||
node: serializeNodeWithId(n, {
|
blockClass: this.blockClass,
|
||||||
doc: document,
|
blockSelector: this.blockSelector,
|
||||||
map: mirror.map,
|
skipChild: true,
|
||||||
blockClass: this.blockClass,
|
inlineStylesheet: this.inlineStylesheet,
|
||||||
blockSelector: this.blockSelector,
|
maskInputOptions: this.maskInputOptions,
|
||||||
skipChild: true,
|
slimDOMOptions: this.slimDOMOptions,
|
||||||
inlineStylesheet: this.inlineStylesheet,
|
recordCanvas: this.recordCanvas,
|
||||||
maskInputOptions: this.maskInputOptions,
|
|
||||||
slimDOMOptions: {},
|
|
||||||
recordCanvas: this.recordCanvas,
|
|
||||||
})!,
|
|
||||||
});
|
});
|
||||||
|
if (sn) {
|
||||||
|
adds.push({
|
||||||
|
parentId,
|
||||||
|
nextId,
|
||||||
|
node: sn,
|
||||||
|
});
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
while (this.mapRemoves.length) {
|
while (this.mapRemoves.length) {
|
||||||
@@ -332,6 +344,9 @@ export default class MutationBuffer {
|
|||||||
};
|
};
|
||||||
|
|
||||||
private processMutation = (m: mutationRecord) => {
|
private processMutation = (m: mutationRecord) => {
|
||||||
|
if (isIgnored(m.target)) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
switch (m.type) {
|
switch (m.type) {
|
||||||
case 'characterData': {
|
case 'characterData': {
|
||||||
const value = m.target.textContent;
|
const value = m.target.textContent;
|
||||||
@@ -373,7 +388,8 @@ export default class MutationBuffer {
|
|||||||
const parentId = mirror.getId(m.target as INode);
|
const parentId = mirror.getId(m.target as INode);
|
||||||
if (
|
if (
|
||||||
isBlocked(n, this.blockClass) ||
|
isBlocked(n, this.blockClass) ||
|
||||||
isBlocked(m.target, this.blockClass)
|
isBlocked(m.target, this.blockClass) ||
|
||||||
|
isIgnored(n)
|
||||||
) {
|
) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@@ -421,6 +437,9 @@ export default class MutationBuffer {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
if (isINode(n)) {
|
if (isINode(n)) {
|
||||||
|
if (isIgnored(n)) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
this.movedSet.add(n);
|
this.movedSet.add(n);
|
||||||
let targetId: number | null = null;
|
let targetId: number | null = null;
|
||||||
if (target && isINode(target)) {
|
if (target && isINode(target)) {
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
import { INode, MaskInputOptions } from 'rrweb-snapshot';
|
import { INode, MaskInputOptions, SlimDOMOptions } from 'rrweb-snapshot';
|
||||||
import { FontFaceDescriptors, FontFaceSet } from 'css-font-loading-module';
|
import { FontFaceDescriptors, FontFaceSet } from 'css-font-loading-module';
|
||||||
import {
|
import {
|
||||||
mirror,
|
mirror,
|
||||||
@@ -48,6 +48,7 @@ function initMutationObserver(
|
|||||||
inlineStylesheet: boolean,
|
inlineStylesheet: boolean,
|
||||||
maskInputOptions: MaskInputOptions,
|
maskInputOptions: MaskInputOptions,
|
||||||
recordCanvas: boolean,
|
recordCanvas: boolean,
|
||||||
|
slimDOMOptions: SlimDOMOptions,
|
||||||
): MutationObserver {
|
): MutationObserver {
|
||||||
// see mutation.ts for details
|
// see mutation.ts for details
|
||||||
mutationBuffer.init(
|
mutationBuffer.init(
|
||||||
@@ -57,6 +58,7 @@ function initMutationObserver(
|
|||||||
inlineStylesheet,
|
inlineStylesheet,
|
||||||
maskInputOptions,
|
maskInputOptions,
|
||||||
recordCanvas,
|
recordCanvas,
|
||||||
|
slimDOMOptions,
|
||||||
);
|
);
|
||||||
const observer = new MutationObserver(
|
const observer = new MutationObserver(
|
||||||
mutationBuffer.processMutations.bind(mutationBuffer),
|
mutationBuffer.processMutations.bind(mutationBuffer),
|
||||||
@@ -584,6 +586,7 @@ export function initObservers(
|
|||||||
o.inlineStylesheet,
|
o.inlineStylesheet,
|
||||||
o.maskInputOptions,
|
o.maskInputOptions,
|
||||||
o.recordCanvas,
|
o.recordCanvas,
|
||||||
|
o.slimDOMOptions,
|
||||||
);
|
);
|
||||||
const mousemoveHandler = initMoveObserver(o.mousemoveCb, o.sampling);
|
const mousemoveHandler = initMoveObserver(o.mousemoveCb, o.sampling);
|
||||||
const mouseInteractionHandler = initMouseInteractionObserver(
|
const mouseInteractionHandler = initMouseInteractionObserver(
|
||||||
|
|||||||
@@ -3,6 +3,7 @@ import {
|
|||||||
idNodeMap,
|
idNodeMap,
|
||||||
INode,
|
INode,
|
||||||
MaskInputOptions,
|
MaskInputOptions,
|
||||||
|
SlimDOMOptions,
|
||||||
} from 'rrweb-snapshot';
|
} from 'rrweb-snapshot';
|
||||||
import { PackFn, UnpackFn } from './packer/base';
|
import { PackFn, UnpackFn } from './packer/base';
|
||||||
import { FontFaceDescriptors } from 'css-font-loading-module';
|
import { FontFaceDescriptors } from 'css-font-loading-module';
|
||||||
@@ -176,6 +177,7 @@ export type recordOptions<T> = {
|
|||||||
maskAllInputs?: boolean;
|
maskAllInputs?: boolean;
|
||||||
maskInputOptions?: MaskInputOptions;
|
maskInputOptions?: MaskInputOptions;
|
||||||
maskInputFn?: MaskInputFn;
|
maskInputFn?: MaskInputFn;
|
||||||
|
slimDOMOptions?: SlimDOMOptions;
|
||||||
inlineStylesheet?: boolean;
|
inlineStylesheet?: boolean;
|
||||||
hooks?: hooksParam;
|
hooks?: hooksParam;
|
||||||
packFn?: PackFn;
|
packFn?: PackFn;
|
||||||
@@ -206,6 +208,7 @@ export type observerParam = {
|
|||||||
sampling: SamplingStrategy;
|
sampling: SamplingStrategy;
|
||||||
recordCanvas: boolean;
|
recordCanvas: boolean;
|
||||||
collectFonts: boolean;
|
collectFonts: boolean;
|
||||||
|
slimDOMOptions: SlimDOMOptions;
|
||||||
};
|
};
|
||||||
|
|
||||||
export type hooksParam = {
|
export type hooksParam = {
|
||||||
|
|||||||
11
src/utils.ts
11
src/utils.ts
@@ -15,7 +15,7 @@ import {
|
|||||||
scrollData,
|
scrollData,
|
||||||
inputData,
|
inputData,
|
||||||
} from './types';
|
} from './types';
|
||||||
import { INode } from 'rrweb-snapshot';
|
import { INode, IGNORED_NODE } from 'rrweb-snapshot';
|
||||||
|
|
||||||
export function on(
|
export function on(
|
||||||
type: string,
|
type: string,
|
||||||
@@ -197,6 +197,15 @@ export function isBlocked(node: Node | null, blockClass: blockClass): boolean {
|
|||||||
return isBlocked(node.parentNode, blockClass);
|
return isBlocked(node.parentNode, blockClass);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export function isIgnored(n: Node | INode): boolean {
|
||||||
|
if ('__sn' in n) {
|
||||||
|
return (n as INode).__sn.id === IGNORED_NODE;
|
||||||
|
}
|
||||||
|
// The main part of the slimDOM check happens in
|
||||||
|
// rrweb-snapshot::serializeNodeWithId
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
export function isAncestorRemoved(target: INode): boolean {
|
export function isAncestorRemoved(target: INode): boolean {
|
||||||
const id = mirror.getId(target);
|
const id = mirror.getId(target);
|
||||||
if (!mirror.has(id)) {
|
if (!mirror.has(id)) {
|
||||||
|
|||||||
Reference in New Issue
Block a user