-
-
Notifications
You must be signed in to change notification settings - Fork 1.5k
fix: nested stylesheets should have absolute URLs #1533
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Merged
Juice10
merged 15 commits into
rrweb-io:master
from
pendo-io:jn-correct-absolute-urls-for-nested-stylesheets
Jul 25, 2024
Merged
Changes from all commits
Commits
Show all changes
15 commits
Select commit
Hold shift + click to select a range
d685bc6
Replace relative URLs with absolute URLs when stringifying stylesheets
jeffdnguyen c6c0ee3
Add test to show desired behavior for imported stylesheets from seper…
jeffdnguyen f69e8f3
Add changeset
jeffdnguyen 27432e2
Rename `absoluteToStylesheet` to `absolutifyURLs` and call it once af…
jeffdnguyen 6ca68b8
Don't create the intermediary array of the spread operator
eoghanmurray ddebff5
Formalize that `stringifyRule` should expect a sheet href
eoghanmurray 04b3fc6
Ensure a <style> element can also import and gets it's url absolutized
eoghanmurray 0c0ceb9
Apply formatting changes
eoghanmurray f4bfd73
Handle case where non imported stylesheet has relative urls that need…
jeffdnguyen 72f6a68
Clarify in test files where jpegs are expected to appear in absolutif…
jeffdnguyen 772f64c
Movee absolutifyURLs call for import rules out of trycatch
jeffdnguyen 8edb9fa
Add a benchmarking test for stringifyStylesheet
eoghanmurray e4d1861
Avoid the duplication on how to fall back
eoghanmurray 74f3758
Add explanatory comment
eoghanmurray acf1cb9
Code style: more compact
eoghanmurray File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,5 @@ | ||
--- | ||
"rrweb-snapshot": patch | ||
--- | ||
|
||
Fix `url()` rewrite for nested stylesheets by rewriting during stringification instead of after |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -71,7 +71,7 @@ | |
* Browsers sometimes incorrectly escape `@import` on `.cssText` statements. | ||
* This function tries to correct the escaping. | ||
* more info: https://bugs.chromium.org/p/chromium/issues/detail?id=1472259 | ||
* @param cssImportRule | ||
Check warning on line 74 in packages/rrweb-snapshot/src/utils.ts
|
||
* @returns `cssText` with browser inconsistencies fixed, or null if not applicable. | ||
*/ | ||
export function escapeImportStatement(rule: CSSImportRule): string { | ||
|
@@ -96,19 +96,21 @@ | |
export function stringifyStylesheet(s: CSSStyleSheet): string | null { | ||
try { | ||
const rules = s.rules || s.cssRules; | ||
return rules | ||
? fixBrowserCompatibilityIssuesInCSS( | ||
Array.from(rules, stringifyRule).join(''), | ||
) | ||
: null; | ||
if (!rules) { | ||
return null; | ||
} | ||
const stringifiedRules = Array.from(rules, (rule: CSSRule) => | ||
stringifyRule(rule, s.href), | ||
).join(''); | ||
return fixBrowserCompatibilityIssuesInCSS(stringifiedRules); | ||
} catch (error) { | ||
return null; | ||
} | ||
} | ||
|
||
export function stringifyRule(rule: CSSRule): string { | ||
let importStringified; | ||
export function stringifyRule(rule: CSSRule, sheetHref: string | null): string { | ||
if (isCSSImportRule(rule)) { | ||
let importStringified; | ||
try { | ||
importStringified = | ||
// for same-origin stylesheets, | ||
|
@@ -117,15 +119,25 @@ | |
// work around browser issues with the raw string `@import url(...)` statement | ||
escapeImportStatement(rule); | ||
} catch (error) { | ||
// ignore | ||
importStringified = rule.cssText; | ||
} | ||
if (rule.styleSheet.href) { | ||
// url()s within the imported stylesheet are relative to _that_ sheet's href | ||
return absolutifyURLs(importStringified, rule.styleSheet.href); | ||
} | ||
return importStringified; | ||
} else { | ||
let ruleStringified = rule.cssText; | ||
if (isCSSStyleRule(rule) && rule.selectorText.includes(':')) { | ||
// Safari does not escape selectors with : properly | ||
// see https://bugs.webkit.org/show_bug.cgi?id=184604 | ||
ruleStringified = fixSafariColons(ruleStringified); | ||
} | ||
} else if (isCSSStyleRule(rule) && rule.selectorText.includes(':')) { | ||
// Safari does not escape selectors with : properly | ||
// see https://bugs.webkit.org/show_bug.cgi?id=184604 | ||
return fixSafariColons(rule.cssText); | ||
if (sheetHref) { | ||
return absolutifyURLs(ruleStringified, sheetHref); | ||
} | ||
return ruleStringified; | ||
} | ||
|
||
return importStringified || rule.cssText; | ||
} | ||
|
||
export function fixSafariColons(cssStringified: string): string { | ||
|
@@ -351,3 +363,62 @@ | |
const match = url.pathname.match(regex); | ||
return match?.[1] ?? null; | ||
} | ||
|
||
function extractOrigin(url: string): string { | ||
let origin = ''; | ||
eoghanmurray marked this conversation as resolved.
Show resolved
Hide resolved
|
||
if (url.indexOf('//') > -1) { | ||
origin = url.split('/').slice(0, 3).join('/'); | ||
} else { | ||
origin = url.split('/')[0]; | ||
} | ||
origin = origin.split('?')[0]; | ||
return origin; | ||
} | ||
|
||
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 absolutifyURLs(cssText: string | null, href: string): string { | ||
return (cssText || '').replace( | ||
URL_IN_CSS_REF, | ||
( | ||
origin: string, | ||
quote1: string, | ||
path1: string, | ||
quote2: string, | ||
path2: string, | ||
path3: string, | ||
) => { | ||
const filePath = path1 || path2 || path3; | ||
const maybeQuote = quote1 || quote2 || ''; | ||
if (!filePath) { | ||
return origin; | ||
} | ||
if (URL_PROTOCOL_MATCH.test(filePath) || URL_WWW_MATCH.test(filePath)) { | ||
return `url(${maybeQuote}${filePath}${maybeQuote})`; | ||
} | ||
if (DATA_URI.test(filePath)) { | ||
return `url(${maybeQuote}${filePath}${maybeQuote})`; | ||
} | ||
if (filePath[0] === '/') { | ||
return `url(${maybeQuote}${ | ||
extractOrigin(href) + filePath | ||
}${maybeQuote})`; | ||
} | ||
const stack = href.split('/'); | ||
const parts = filePath.split('/'); | ||
stack.pop(); | ||
for (const part of parts) { | ||
if (part === '.') { | ||
continue; | ||
} else if (part === '..') { | ||
stack.pop(); | ||
} else { | ||
stack.push(part); | ||
} | ||
} | ||
return `url(${maybeQuote}${stack.join('/')}${maybeQuote})`; | ||
}, | ||
); | ||
} |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,12 @@ | ||
body { | ||
margin: 0; | ||
background: url('../should-be-in-root-folder.jpg'); | ||
border-image: url('data:image/svg+xml;utf8,<svg xmlns="http://www.w3.org/2000/svg" x="0px" y="0px" viewBox="0 0 256 256"><g><g><polygon points="79.093,0 48.907,30.187 146.72,128 48.907,225.813 79.093,256 207.093,128"/></g></g></svg>'); | ||
} | ||
p { | ||
color: red; | ||
background: url('./should-be-in-alt-css-folder.jpg'); | ||
} | ||
body > p { | ||
color: yellow; | ||
} |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,2 +1,3 @@ | ||
@import '//fonts.googleapis.com/css2?family=Open+Sans:wght@400;600;700&family=Roboto:wght@100;300;400;500;700&display=swap"'; | ||
@import './style.css'; | ||
@import '../alt-css/alt-style.css'; |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
Uh oh!
There was an error while loading. Please reload this page.