From 87560305ec271fee51fd1afcf9238a7e31767a54 Mon Sep 17 00:00:00 2001 From: Eoghan Murray Date: Fri, 29 Nov 2024 20:20:10 +0000 Subject: [PATCH] Apply adaption even if split is within something that needs to be adapted --- .changeset/fix-adapt-css.md | 6 ++ packages/rrweb-snapshot/src/rebuild.ts | 82 ++++++++---------------- packages/rrweb-snapshot/test/css.test.ts | 7 +- 3 files changed, 38 insertions(+), 57 deletions(-) create mode 100644 .changeset/fix-adapt-css.md diff --git a/.changeset/fix-adapt-css.md b/.changeset/fix-adapt-css.md new file mode 100644 index 0000000000..3564086a8c --- /dev/null +++ b/.changeset/fix-adapt-css.md @@ -0,0 +1,6 @@ +--- +'rrweb': patch +'rrweb-snapshot': patch +--- + +#1575 Fix that postcss could fall over when trying to process css content split arbitrarily diff --git a/packages/rrweb-snapshot/src/rebuild.ts b/packages/rrweb-snapshot/src/rebuild.ts index 7d92ba8199..74cae08d55 100644 --- a/packages/rrweb-snapshot/src/rebuild.ts +++ b/packages/rrweb-snapshot/src/rebuild.ts @@ -104,65 +104,39 @@ export function applyCssSplits( // unexpected: remerge the last two so that we don't discard any css cssTextSplits.splice(-2, 2, cssTextSplits.slice(-2).join('')); } - let adaptionFailures = []; + let adaptedCss = ''; + if (hackCss) { + adaptedCss = adaptCssForReplay(cssTextSplits.join(''), cache); + } + let ix_start = 0; for (let i = 0; i < childTextNodes.length; i++) { const childTextNode = childTextNodes[i]; - let cssTextSection = cssTextSplits[i]; - if (childTextNode && cssTextSection) { - // id will be assigned when these child nodes are - // iterated over in buildNodeWithSN - if (hackCss) { - try { - cssTextSection = adaptCssForReplay(cssTextSection, cache); - } catch (e) { - // css section might not have been valid on it's own - adaptionFailures.push(i); - } + if (!hackCss) { + if (i === cssTextSplits.length) { + break; } - childTextNode.textContent = cssTextSection; - } - } - if (adaptionFailures.length) { - // this time, can throw an exception - const fullAdaptedCss = adaptCssForReplay(cssTextSplits.join(''), cache); - let ix_start = 0; - for (let i = 0; i < childTextNodes.length; i++) { - const childTextNode = childTextNodes[i]; - if (adaptionFailures.includes(i)) { - if (i === childTextNodes.length - 1) { - console.log('he' + i, ix_start, fullAdaptedCss.substring(ix_start)); - childTextNode.textContent = fullAdaptedCss.substring(ix_start); - } else { - let ix_end = -1; - let end_search = childTextNodes[i + 1].textContent.length; - while (ix_end === -1) { - let search_bit = childTextNodes[i + 1].textContent.substring( - 0, - end_search, - ); - ix_end = - ix_start + fullAdaptedCss.substring(ix_start).indexOf(search_bit); - end_search -= 1; - if (end_search <= 2) { - break; - } - } - console.log( - 're' + i, - ix_start, - ix_end, - fullAdaptedCss.substring(ix_start, ix_end), - ); - if (ix_end !== -1) { - childTextNode.textContent = fullAdaptedCss.substring( - ix_start, - ix_end, - ); - } else { - } + childTextNode.textContent = cssTextSplits[i]; + } else if (i < childTextNodes.length - 1) { + let ix_end = -1; + let end_search = cssTextSplits[i + 1].length; + while (ix_end === -1) { + let search_bit = cssTextSplits[i + 1].substring(0, end_search); + ix_end = ix_start + adaptedCss.substring(ix_start).indexOf(search_bit); + if (ix_end === -1) { + end_search -= 1; + continue; + } else if (ix_end <= 2) { + break; } } - ix_start += childTextNode.textContent.length; + if (ix_end === -1) { + // something went wrong, put a similar sized chunk in the right place + ix_end = ix_start + cssTextSplits[i].length; + } + childTextNode.textContent = adaptedCss.substring(ix_start, ix_end); + ix_start = ix_end; + } else { + childTextNode.textContent = adaptedCss.substring(ix_start); } } } diff --git a/packages/rrweb-snapshot/test/css.test.ts b/packages/rrweb-snapshot/test/css.test.ts index 0909e2161c..d4bf522949 100644 --- a/packages/rrweb-snapshot/test/css.test.ts +++ b/packages/rrweb-snapshot/test/css.test.ts @@ -236,9 +236,10 @@ describe('applyCssSplits css rejoiner', function () { const badSecondHalf = 'er { color: red; }'; const markedCssText = [badFirstHalf, badSecondHalf].join('/* rr_split */'); applyCssSplits(sn, markedCssText, true, mockLastUnusedArg); - expect((sn.childNodes[1] as textNode).textContent).toEqual( - 'er,\na.\\:hover { color: red; }', - ); + expect( + (sn.childNodes[0] as textNode).textContent + + (sn.childNodes[1] as textNode).textContent, + ).toEqual('a:hover,\na.\\:hover { color: red; }'); }); it('applies css splits correctly when split parts are invalid by themselves x3', () => {