fix: remote CSS does not get rebuilt properly (#1618)
* fix: remote CSS does not get rebuilt properly This fixes an issue where inlined CSS from a remotely loaded `<link>` does not get applied properly due to object reference mutation. * add changeset * ci-cd on ubuntu-22.04 instead of latest * keep mirror meta synced
This commit is contained in:
5
.changeset/red-peaches-explode.md
Normal file
5
.changeset/red-peaches-explode.md
Normal file
@@ -0,0 +1,5 @@
|
||||
---
|
||||
"rrweb": patch
|
||||
---
|
||||
|
||||
This fixes an issue where inlined CSS from a remotely loaded `<link>` does not get applied properly due to object reference mutation.
|
||||
@@ -1792,17 +1792,27 @@ export class Replayer {
|
||||
const newSn = mirror.getMeta(
|
||||
target as Node & RRNode,
|
||||
) as serializedElementNodeWithId;
|
||||
const newNode = buildNodeWithSN(
|
||||
{
|
||||
...newSn,
|
||||
attributes: {
|
||||
...newSn.attributes,
|
||||
...(mutation.attributes as attributes),
|
||||
},
|
||||
},
|
||||
{
|
||||
doc: target.ownerDocument as Document, // can be Document or RRDocument
|
||||
mirror: mirror as Mirror,
|
||||
skipChild: true,
|
||||
hackCss: true,
|
||||
cache: this.cache,
|
||||
},
|
||||
);
|
||||
// Update mirror meta's attributes
|
||||
Object.assign(
|
||||
newSn.attributes,
|
||||
mutation.attributes as attributes,
|
||||
);
|
||||
const newNode = buildNodeWithSN(newSn, {
|
||||
doc: target.ownerDocument as Document, // can be Document or RRDocument
|
||||
mirror: mirror as Mirror,
|
||||
skipChild: true,
|
||||
hackCss: true,
|
||||
cache: this.cache,
|
||||
});
|
||||
const siblingNode = target.nextSibling;
|
||||
const parentNode = target.parentNode;
|
||||
if (newNode && parentNode) {
|
||||
|
||||
@@ -158,6 +158,73 @@ file-cid-3
|
||||
"
|
||||
`;
|
||||
|
||||
exports[`replayer > can handle remote stylesheets 1`] = `
|
||||
"file-frame-2
|
||||
<html>
|
||||
<head>
|
||||
<meta http-equiv=\\"Content-Type\\" content=\\"text/html; charset=UTF-8\\" />
|
||||
</head>
|
||||
<body>
|
||||
<div class=\\"replayer-wrapper\\">
|
||||
<div class=\\"replayer-mouse\\"></div>
|
||||
<canvas
|
||||
class=\\"replayer-mouse-tail\\"
|
||||
width=\\"1000\\"
|
||||
height=\\"800\\"
|
||||
style=\\"display: inherit\\"
|
||||
></canvas
|
||||
><iframe
|
||||
sandbox=\\"allow-same-origin\\"
|
||||
scrolling=\\"no\\"
|
||||
width=\\"1000\\"
|
||||
height=\\"800\\"
|
||||
style=\\"display: inherit; pointer-events: none\\"
|
||||
></iframe>
|
||||
</div>
|
||||
</body>
|
||||
</html>
|
||||
|
||||
|
||||
file-frame-3
|
||||
<html>
|
||||
<head>
|
||||
<meta http-equiv=\\"Content-Type\\" content=\\"text/html; charset=UTF-8\\" />
|
||||
<link rel=\\"stylesheet\\" type=\\"text/css\\" href=\\"file-cid-0\\" />
|
||||
<link rel=\\"stylesheet\\" type=\\"text/css\\" href=\\"file-cid-1\\" />
|
||||
</head>
|
||||
<body></body>
|
||||
</html>
|
||||
|
||||
|
||||
file-cid-0
|
||||
@charset \\"utf-8\\";
|
||||
|
||||
.rr-block { background: currentcolor; }
|
||||
|
||||
noscript { display: none !important; }
|
||||
|
||||
html.rrweb-paused *, html.rrweb-paused ::before, html.rrweb-paused ::after { animation-play-state: paused !important; }
|
||||
|
||||
|
||||
file-cid-1
|
||||
@charset \\"utf-8\\";
|
||||
|
||||
.OverlayDrawer-modal-187 { }
|
||||
|
||||
.OverlayDrawer-paper-188 { width: 100%; }
|
||||
|
||||
@media (min-width: 48em) {
|
||||
.OverlayDrawer-paper-188 { width: 38rem; }
|
||||
}
|
||||
|
||||
@media (min-width: 48em) {
|
||||
}
|
||||
|
||||
@media (min-width: 48em) {
|
||||
}
|
||||
"
|
||||
`;
|
||||
|
||||
exports[`replayer > can handle removing style elements 1`] = `
|
||||
"file-frame-1
|
||||
<html>
|
||||
|
||||
@@ -8,6 +8,7 @@ import {
|
||||
launchPuppeteer,
|
||||
sampleEvents as events,
|
||||
sampleStyleSheetRemoveEvents as stylesheetRemoveEvents,
|
||||
sampleRemoteStyleSheetEvents as remoteStyleSheetEvents,
|
||||
waitForRAF,
|
||||
} from './utils';
|
||||
import styleSheetRuleEvents from './events/style-sheet-rule-events';
|
||||
@@ -209,6 +210,23 @@ describe('replayer', function () {
|
||||
await assertDomSnapshot(page);
|
||||
});
|
||||
|
||||
it('can handle remote stylesheets', async () => {
|
||||
await page.evaluate(`events = ${JSON.stringify(remoteStyleSheetEvents)}`);
|
||||
const actionLength = await page.evaluate(`
|
||||
const { Replayer } = rrweb;
|
||||
const replayer = new Replayer(events);
|
||||
replayer.play(2500);
|
||||
replayer['timer']['actions'].length;
|
||||
`);
|
||||
expect(actionLength).toEqual(
|
||||
remoteStyleSheetEvents.filter(
|
||||
(e) => e.timestamp - remoteStyleSheetEvents[0].timestamp >= 2500,
|
||||
).length,
|
||||
);
|
||||
|
||||
await assertDomSnapshot(page);
|
||||
});
|
||||
|
||||
it('can fast forward selection events', async () => {
|
||||
await page.evaluate(`events = ${JSON.stringify(selectionEvents)}`);
|
||||
|
||||
|
||||
@@ -561,6 +561,98 @@ export const sampleStyleSheetRemoveEvents: eventWithTime[] = [
|
||||
},
|
||||
];
|
||||
|
||||
export const sampleRemoteStyleSheetEvents: eventWithTime[] = [
|
||||
{
|
||||
type: EventType.DomContentLoaded,
|
||||
data: {},
|
||||
timestamp: now,
|
||||
},
|
||||
{
|
||||
type: EventType.Load,
|
||||
data: {},
|
||||
timestamp: now + 1000,
|
||||
},
|
||||
{
|
||||
type: EventType.Meta,
|
||||
data: {
|
||||
href: 'http://localhost',
|
||||
width: 1000,
|
||||
height: 800,
|
||||
},
|
||||
timestamp: now + 1000,
|
||||
},
|
||||
{
|
||||
type: EventType.FullSnapshot,
|
||||
data: {
|
||||
node: {
|
||||
type: 0,
|
||||
childNodes: [
|
||||
{
|
||||
type: 2,
|
||||
tagName: 'html',
|
||||
attributes: {},
|
||||
childNodes: [
|
||||
{
|
||||
type: 2,
|
||||
tagName: 'head',
|
||||
attributes: {},
|
||||
childNodes: [
|
||||
{
|
||||
type: 2,
|
||||
tagName: 'link',
|
||||
attributes: {
|
||||
rel: 'stylesheet',
|
||||
href: '',
|
||||
},
|
||||
childNodes: [],
|
||||
id: 4,
|
||||
},
|
||||
],
|
||||
id: 3,
|
||||
},
|
||||
{
|
||||
type: 2,
|
||||
tagName: 'body',
|
||||
attributes: {},
|
||||
childNodes: [],
|
||||
id: 6,
|
||||
},
|
||||
],
|
||||
id: 2,
|
||||
},
|
||||
],
|
||||
id: 1,
|
||||
},
|
||||
initialOffset: {
|
||||
top: 0,
|
||||
left: 0,
|
||||
},
|
||||
},
|
||||
timestamp: now + 1000,
|
||||
},
|
||||
{
|
||||
type: EventType.IncrementalSnapshot,
|
||||
data: {
|
||||
source: IncrementalSource.Mutation,
|
||||
texts: [],
|
||||
attributes: [
|
||||
{
|
||||
id: 4,
|
||||
attributes: {
|
||||
href: null,
|
||||
rel: null,
|
||||
_cssText:
|
||||
'.OverlayDrawer-modal-187 { }.OverlayDrawer-paper-188 { width: 100%; }@media (min-width: 48em) {\n .OverlayDrawer-paper-188 { width: 38rem; }\n}@media (min-width: 48em) {\n}@media (min-width: 48em) {\n}',
|
||||
},
|
||||
},
|
||||
],
|
||||
removes: [],
|
||||
adds: [],
|
||||
},
|
||||
timestamp: now + 2000,
|
||||
},
|
||||
];
|
||||
|
||||
export const polyfillWebGLGlobals = () => {
|
||||
// polyfill as jsdom does not have support for these classes
|
||||
// consider replacing with https://www.npmjs.com/package/canvas
|
||||
|
||||
Reference in New Issue
Block a user