Skip to content
Merged
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Prev Previous commit
Next Next commit
Rename absoluteToStylesheet to absolutifyURLs and call it once af…
…ter stringifying imported stylesheet
  • Loading branch information
jeffdnguyen committed Jul 16, 2024
commit 27432e2ec311396d185d265176e805aa286eb511
6 changes: 3 additions & 3 deletions packages/rrweb-snapshot/src/snapshot.ts
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,7 @@ import {
getInputType,
toLowerCase,
extractFileExtension,
absoluteToStylesheet,
absolutifyURLs,
} from './utils';

let _id = 1;
Expand Down Expand Up @@ -193,7 +193,7 @@ export function transformAttribute(
} else if (name === 'srcset') {
return getAbsoluteSrcsetString(doc, value);
} else if (name === 'style') {
return absoluteToStylesheet(value, getHref(doc));
return absolutifyURLs(value, getHref(doc));
} else if (tagName === 'object' && name === 'data') {
return absoluteToDoc(doc, value);
}
Expand Down Expand Up @@ -523,7 +523,7 @@ function serializeTextNode(
n,
);
}
textContent = absoluteToStylesheet(textContent, getHref(options.doc));
textContent = absolutifyURLs(textContent, getHref(options.doc));
}
if (isScript) {
textContent = 'SCRIPT_PLACEHOLDER';
Expand Down
20 changes: 11 additions & 9 deletions packages/rrweb-snapshot/src/utils.ts
Original file line number Diff line number Diff line change
Expand Up @@ -96,10 +96,8 @@ export function escapeImportStatement(rule: CSSImportRule): string {
export function stringifyStylesheet(s: CSSStyleSheet): string | null {
try {
const rules = s.rules || s.cssRules;
const stringifiedRules = Array.from(rules, stringifyRule)
.map((rule) => {
return s.href ? absoluteToStylesheet(rule, s.href) : rule;
})
const stringifiedRules = [...rules]
.map((rule: CSSRule) => stringifyRule(rule, s.href))
.join('');

return rules ? fixBrowserCompatibilityIssuesInCSS(stringifiedRules) : null;
Expand All @@ -108,7 +106,10 @@ export function stringifyStylesheet(s: CSSStyleSheet): string | null {
}
}

export function stringifyRule(rule: CSSRule): string {
export function stringifyRule(
rule: CSSRule,
sheetHref?: string | null,
): string {
let importStringified;
if (isCSSImportRule(rule)) {
try {
Expand All @@ -118,6 +119,10 @@ export function stringifyRule(rule: CSSRule): string {
stringifyStylesheet(rule.styleSheet) ||
// work around browser issues with the raw string `@import url(...)` statement
escapeImportStatement(rule);

if (sheetHref) {
importStringified = absolutifyURLs(importStringified, sheetHref);
}
} catch (error) {
// ignore
}
Expand Down Expand Up @@ -369,10 +374,7 @@ const URL_IN_CSS_REF = /url\((?:(')([^']*)'|(")(.*?)"|([^)]*))\)/gm;
const URL_PROTOCOL_MATCH = /^(?:[a-z+]+:)?\/\//i;
const URL_WWW_MATCH = /^www\..*/i;
const DATA_URI = /^(data:)([^,]*),(.*)/i;
export function absoluteToStylesheet(
cssText: string | null,
href: string,
): string {
export function absolutifyURLs(cssText: string | null, href: string): string {
return (cssText || '').replace(
URL_IN_CSS_REF,
(
Expand Down
34 changes: 17 additions & 17 deletions packages/rrweb-snapshot/test/snapshot.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,56 +6,56 @@ import { describe, it, expect } from 'vitest';
import { serializeNodeWithId, _isBlockedElement } from '../src/snapshot';
import snapshot from '../src/snapshot';
import { serializedNodeWithId, elementNode } from '../src/types';
import { Mirror, absoluteToStylesheet } from '../src/utils';
import { Mirror, absolutifyURLs } from '../src/utils';

describe('absolute url to stylesheet', () => {
const href = 'http://localhost/css/style.css';

it('can handle relative path', () => {
expect(absoluteToStylesheet('url(a.jpg)', href)).toEqual(
expect(absolutifyURLs('url(a.jpg)', href)).toEqual(
`url(http://localhost/css/a.jpg)`,
);
});

it('can handle same level path', () => {
expect(absoluteToStylesheet('url("./a.jpg")', href)).toEqual(
expect(absolutifyURLs('url("./a.jpg")', href)).toEqual(
`url("http://localhost/css/a.jpg")`,
);
});

it('can handle parent level path', () => {
expect(absoluteToStylesheet('url("../a.jpg")', href)).toEqual(
expect(absolutifyURLs('url("../a.jpg")', href)).toEqual(
`url("http://localhost/a.jpg")`,
);
});

it('can handle absolute path', () => {
expect(absoluteToStylesheet('url("/a.jpg")', href)).toEqual(
expect(absolutifyURLs('url("/a.jpg")', href)).toEqual(
`url("http://localhost/a.jpg")`,
);
});

it('can handle external path', () => {
expect(absoluteToStylesheet('url("http://localhost/a.jpg")', href)).toEqual(
expect(absolutifyURLs('url("http://localhost/a.jpg")', href)).toEqual(
`url("http://localhost/a.jpg")`,
);
});

it('can handle single quote path', () => {
expect(absoluteToStylesheet(`url('./a.jpg')`, href)).toEqual(
expect(absolutifyURLs(`url('./a.jpg')`, href)).toEqual(
`url('http://localhost/css/a.jpg')`,
);
});

it('can handle no quote path', () => {
expect(absoluteToStylesheet('url(./a.jpg)', href)).toEqual(
expect(absolutifyURLs('url(./a.jpg)', href)).toEqual(
`url(http://localhost/css/a.jpg)`,
);
});

it('can handle multiple no quote paths', () => {
expect(
absoluteToStylesheet(
absolutifyURLs(
'background-image: url(images/b.jpg);background: #aabbcc url(images/a.jpg) 50% 50% repeat;',
href,
),
Expand All @@ -66,11 +66,11 @@ describe('absolute url to stylesheet', () => {
});

it('can handle data url image', () => {
expect(absolutifyURLs('url(data:image/gif;base64,ABC)', href)).toEqual(
'url(data:image/gif;base64,ABC)',
);
expect(
absoluteToStylesheet('url(data:image/gif;base64,ABC)', href),
).toEqual('url(data:image/gif;base64,ABC)');
expect(
absoluteToStylesheet(
absolutifyURLs(
'url(data:application/font-woff;base64,d09GMgABAAAAAAm)',
href,
),
Expand All @@ -79,23 +79,23 @@ describe('absolute url to stylesheet', () => {

it('preserves quotes around inline svgs with spaces', () => {
expect(
absoluteToStylesheet(
absolutifyURLs(
"url(\"data:image/svg+xml;charset=utf-8,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 8 8'%3E%3Cpath fill='%2328a745' d='M3'/%3E%3C/svg%3E\")",
href,
),
).toEqual(
"url(\"data:image/svg+xml;charset=utf-8,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 8 8'%3E%3Cpath fill='%2328a745' d='M3'/%3E%3C/svg%3E\")",
);
expect(
absoluteToStylesheet(
absolutifyURLs(
'url(\'data:image/svg+xml;utf8,<svg width="28" height="32" viewBox="0 0 28 32" xmlns="http://www.w3.org/2000/svg"><path d="M27 14C28" fill="white"/></svg>\')',
href,
),
).toEqual(
'url(\'data:image/svg+xml;utf8,<svg width="28" height="32" viewBox="0 0 28 32" xmlns="http://www.w3.org/2000/svg"><path d="M27 14C28" fill="white"/></svg>\')',
);
expect(
absoluteToStylesheet(
absolutifyURLs(
'url("data:image/svg+xml;utf8,<svg width="28" height="32" viewBox="0 0 28 32" xmlns="http://www.w3.org/2000/svg"><path d="M27 14C28" fill="white"/></svg>")',
href,
),
Expand All @@ -104,7 +104,7 @@ describe('absolute url to stylesheet', () => {
);
});
it('can handle empty path', () => {
expect(absoluteToStylesheet(`url('')`, href)).toEqual(`url('')`);
expect(absolutifyURLs(`url('')`, href)).toEqual(`url('')`);
});
});

Expand Down
2 changes: 1 addition & 1 deletion tsconfig.base.json
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@
"moduleResolution": "Node",
"rootDir": "src",
"outDir": "dist",
"lib": ["es6", "dom"],
"lib": ["es6", "dom", "dom.iterable"],
"sourceMap": true,
"skipLibCheck": true,
"declaration": true,
Expand Down