Fix the regexp performance issue
Also move the addHoverClass implementation into the rebuild stage. So if there is still some corner case we have not handled, it will only affect the replayer part of rrweb.
This commit is contained in:
@@ -115,6 +115,22 @@ function getTagName(n: elementNode): string {
|
||||
return tagName;
|
||||
}
|
||||
|
||||
const CSS_SELECTOR = /([^\r\n,{}]+)(,(?=[^}]*{)|\s*{)/g;
|
||||
const HOVER_SELECTOR = /([^\\]):hover/g;
|
||||
export function addHoverClass(cssText: string): string {
|
||||
return cssText.replace(CSS_SELECTOR, (match, p1: string, p2: string) => {
|
||||
if (HOVER_SELECTOR.test(p1)) {
|
||||
const newSelector = p1.replace(HOVER_SELECTOR, '$1.\\:hover');
|
||||
return `${p1.replace(/\s*$/, '')}, ${newSelector.replace(
|
||||
/^\s*/,
|
||||
'',
|
||||
)}${p2}`;
|
||||
} else {
|
||||
return match;
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
function buildNode(n: serializedNodeWithId, doc: Document): Node | null {
|
||||
switch (n.type) {
|
||||
case NodeType.Document:
|
||||
@@ -139,6 +155,9 @@ function buildNode(n: serializedNodeWithId, doc: Document): Node | null {
|
||||
value = typeof value === 'boolean' ? '' : value;
|
||||
const isTextarea = tagName === 'textarea' && name === 'value';
|
||||
const isRemoteCss = tagName === 'style' && name === '_cssText';
|
||||
if (isRemoteCss) {
|
||||
value = addHoverClass(value);
|
||||
}
|
||||
if (isTextarea || isRemoteCss) {
|
||||
const child = doc.createTextNode(value);
|
||||
node.appendChild(child);
|
||||
@@ -152,7 +171,9 @@ function buildNode(n: serializedNodeWithId, doc: Document): Node | null {
|
||||
}
|
||||
return node;
|
||||
case NodeType.Text:
|
||||
return doc.createTextNode(n.textContent);
|
||||
return doc.createTextNode(
|
||||
n.isStyle ? addHoverClass(n.textContent) : n.textContent,
|
||||
);
|
||||
case NodeType.CDATA:
|
||||
return doc.createCDATASection(n.textContent);
|
||||
case NodeType.Comment:
|
||||
|
||||
@@ -17,36 +17,11 @@ export function resetId() {
|
||||
_id = 1;
|
||||
}
|
||||
|
||||
const CSS_RULE = /(([#|\.]{0,1}[a-z0-9\[\]=:]+[\s|,]*)+)\s(\{[\s\S]?[^}]*})/;
|
||||
const CSS_RULE_GLOBAL = /(([#|\.]{0,1}[a-z0-9\[\]=:]+[\s|,]*)+)\s(\{[\s\S]?[^}]*})/g;
|
||||
const HOVER_SELECTOR = /([^\\]):hover/g;
|
||||
export function addHoverClass(cssText: string): string {
|
||||
const matches = cssText.match(CSS_RULE_GLOBAL) || [];
|
||||
for (const match of matches) {
|
||||
const [, selectorText = '', , rules = ''] = match.match(CSS_RULE) || [];
|
||||
const selectors = selectorText
|
||||
.split(',')
|
||||
.map(selector => selector.trim())
|
||||
.map(selector => {
|
||||
if (HOVER_SELECTOR.test(selector)) {
|
||||
const newSelector = selector.replace(HOVER_SELECTOR, '$1.\\:hover');
|
||||
selector += `, ${newSelector}`;
|
||||
}
|
||||
return selector;
|
||||
});
|
||||
cssText = cssText.replace(match, selectors.join(', ') + ' ' + rules);
|
||||
}
|
||||
return cssText;
|
||||
}
|
||||
|
||||
function getCssRulesString(s: CSSStyleSheet): string | null {
|
||||
try {
|
||||
const rules = s.rules || s.cssRules;
|
||||
return rules
|
||||
? Array.from(rules).reduce(
|
||||
(prev, cur) => (prev += addHoverClass(cur.cssText)),
|
||||
'',
|
||||
)
|
||||
? Array.from(rules).reduce((prev, cur) => (prev += cur.cssText), '')
|
||||
: null;
|
||||
} catch (error) {
|
||||
return null;
|
||||
@@ -177,12 +152,10 @@ function serializeNode(n: Node, doc: Document): serializedNode | false {
|
||||
if (parentTagName === 'SCRIPT') {
|
||||
textContent = 'SCRIPT_PLACEHOLDER';
|
||||
}
|
||||
if (parentTagName === 'STYLE') {
|
||||
textContent = addHoverClass(textContent || '');
|
||||
}
|
||||
return {
|
||||
type: NodeType.Text,
|
||||
textContent: textContent || '',
|
||||
isStyle: parentTagName === 'STYLE' ? true : undefined,
|
||||
};
|
||||
case n.CDATA_SECTION_NODE:
|
||||
return {
|
||||
|
||||
@@ -32,6 +32,7 @@ export type elementNode = {
|
||||
export type textNode = {
|
||||
type: NodeType.Text;
|
||||
textContent: string;
|
||||
isStyle?: true;
|
||||
};
|
||||
|
||||
export type cdataNode = {
|
||||
|
||||
Reference in New Issue
Block a user