Skip to content

Commit 51a5376

Browse files
authored
Merge pull request #49 from pendo-io/meg-fix-stylesheet-href-when-base-tag-present
use document.baseURI for sheetHref when handling inline styles
2 parents 0e48d10 + c0e10ca commit 51a5376

File tree

3 files changed

+56
-1
lines changed

3 files changed

+56
-1
lines changed

.changeset/twelve-nails-occur.md

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
---
2+
"rrweb-snapshot": patch
3+
---
4+
5+
Prefer the <base href> for resolving inline <style> URLs, falling back to document location if not present.

packages/rrweb-snapshot/src/utils.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -149,7 +149,7 @@ export function stringifyStylesheet(s: CSSStyleSheet): string | null {
149149
let sheetHref = s.href;
150150
if (!sheetHref && s.ownerNode && s.ownerNode.ownerDocument) {
151151
// an inline <style> element
152-
sheetHref = s.ownerNode.ownerDocument.location.href;
152+
sheetHref = s.ownerNode.ownerDocument.baseURI;
153153
}
154154
const stringifiedRules = Array.from(rules, (rule: CSSRule) =>
155155
stringifyRule(rule, sheetHref),

packages/rrweb-snapshot/test/utils.test.ts

Lines changed: 50 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@ import {
88
replaceChromeGridTemplateAreas,
99
fixSafariColons,
1010
isNodeMetaEqual,
11+
stringifyStylesheet
1112
} from '../src/utils';
1213
import { NodeType } from '@rrweb/types';
1314
import type { serializedNode, serializedNodeWithId } from '@rrweb/types';
@@ -374,4 +375,53 @@ describe('utils', () => {
374375
expect(out3).toEqual('[data-aa\\:other] { color: red; }');
375376
});
376377
});
378+
379+
describe('stringifyStylesheet', () => {
380+
it('returns null if rules are missing', () => {
381+
const mockSheet = {
382+
rules: null,
383+
cssRules: null,
384+
} as unknown as CSSStyleSheet;
385+
expect(stringifyStylesheet(mockSheet)).toBeNull();
386+
});
387+
388+
it('stringifies rules using .cssRules if .rules is missing', () => {
389+
const mockRule1 = { cssText: 'div { margin: 0; }' } as CSSRule;
390+
const mockSheet = {
391+
cssRules: [mockRule1],
392+
href: 'https://example.com/main.css',
393+
} as unknown as CSSStyleSheet;
394+
expect(stringifyStylesheet(mockSheet)).toBe('div { margin: 0; }');
395+
});
396+
397+
it('uses ownerNode.ownerDocument.baseURI for inline styles', () => {
398+
const mockFontFaceRule = {
399+
cssText: `
400+
@font-face {
401+
font-family: 'MockFont';
402+
src: url('../fonts/mockfont.woff2') format('woff2');
403+
font-weight: normal;
404+
font-style: normal;
405+
}
406+
`
407+
} as CSSRule;
408+
const mockOwnerDocument = {
409+
location: { href: 'https://example.com/page.html' },
410+
baseURI: 'https://example.com/fonts/',
411+
} as unknown as Document;
412+
const mockOwnerNode = {
413+
ownerDocument: mockOwnerDocument,
414+
} as unknown as Node;
415+
const mockSheet = {
416+
cssRules: [mockFontFaceRule],
417+
href: null,
418+
ownerNode: mockOwnerNode,
419+
} as unknown as CSSStyleSheet;
420+
expect(
421+
stringifyStylesheet(mockSheet)?.replace(/\s+/g, ' ').trim()
422+
).toEqual(
423+
"@font-face { font-family: 'MockFont'; src: url('https://example.com/fonts/mockfont.woff2') format('woff2'); font-weight: normal; font-style: normal; }"
424+
);
425+
});
426+
});
377427
});

0 commit comments

Comments
 (0)