diff --git a/packages/rrweb-snapshot/src/snapshot.ts b/packages/rrweb-snapshot/src/snapshot.ts
index 44f2a2963b..7ceea14096 100644
--- a/packages/rrweb-snapshot/src/snapshot.ts
+++ b/packages/rrweb-snapshot/src/snapshot.ts
@@ -25,7 +25,7 @@ import {
getInputType,
toLowerCase,
extractFileExtension,
- absoluteToStylesheet,
+ absolutifyURLs,
} from './utils';
let _id = 1;
@@ -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);
}
@@ -523,7 +523,7 @@ function serializeTextNode(
n,
);
}
- textContent = absoluteToStylesheet(textContent, getHref(options.doc));
+ textContent = absolutifyURLs(textContent, getHref(options.doc));
}
if (isScript) {
textContent = 'SCRIPT_PLACEHOLDER';
diff --git a/packages/rrweb-snapshot/src/utils.ts b/packages/rrweb-snapshot/src/utils.ts
index 6b7700e2a4..408d913a6f 100644
--- a/packages/rrweb-snapshot/src/utils.ts
+++ b/packages/rrweb-snapshot/src/utils.ts
@@ -96,10 +96,12 @@ 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 = [];
+ // for (let i = 0; i < rules.length; i++) {
+ // stringifiedRules.push(stringifyRule(rules[i], s.href));
+ // }
+ const stringifiedRules = [...rules]
+ .map((rule: CSSRule) => stringifyRule(rule, s.href))
.join('');
return rules ? fixBrowserCompatibilityIssuesInCSS(stringifiedRules) : null;
@@ -108,7 +110,7 @@ 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 {
@@ -118,6 +120,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
}
@@ -369,10 +375,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,
(
diff --git a/packages/rrweb-snapshot/test/snapshot.test.ts b/packages/rrweb-snapshot/test/snapshot.test.ts
index bfab523940..7bf6141e44 100644
--- a/packages/rrweb-snapshot/test/snapshot.test.ts
+++ b/packages/rrweb-snapshot/test/snapshot.test.ts
@@ -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,
),
@@ -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,
),
@@ -79,7 +79,7 @@ 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,
),
@@ -87,7 +87,7 @@ describe('absolute url to stylesheet', () => {
"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,\')',
href,
),
@@ -95,7 +95,7 @@ describe('absolute url to stylesheet', () => {
'url(\'data:image/svg+xml;utf8,\')',
);
expect(
- absoluteToStylesheet(
+ absolutifyURLs(
'url("data:image/svg+xml;utf8,")',
href,
),
@@ -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('')`);
});
});
diff --git a/tsconfig.base.json b/tsconfig.base.json
index bcee1c7337..557bfa46ae 100644
--- a/tsconfig.base.json
+++ b/tsconfig.base.json
@@ -10,7 +10,7 @@
"moduleResolution": "Node",
"rootDir": "src",
"outDir": "dist",
- "lib": ["es6", "dom"],
+ "lib": ["es6", "dom", "dom.iterable"],
"sourceMap": true,
"skipLibCheck": true,
"declaration": true,