From 8e0181661a549cc8baf12526de3b9cf14a56c7f4 Mon Sep 17 00:00:00 2001 From: sharad-sharma Date: Thu, 5 Sep 2024 13:56:27 +0530 Subject: [PATCH 1/3] feat(dom-snapshot): add external stylesheets serialization support --- packages/dom/src/serialize-cssom.js | 29 +++++++++++++++++++++++++++++ packages/dom/src/serialize-dom.js | 9 ++++++--- 2 files changed, 35 insertions(+), 3 deletions(-) diff --git a/packages/dom/src/serialize-cssom.js b/packages/dom/src/serialize-cssom.js index 4e5804f7e..96a8bb68a 100644 --- a/packages/dom/src/serialize-cssom.js +++ b/packages/dom/src/serialize-cssom.js @@ -25,6 +25,35 @@ function createStyleResource(styleSheet) { return resource; } +export function serializeExternalStyles(ctx) { + let { dom, clone, warnings } = ctx; + let styleSheets = null; + try { + styleSheets = dom.styleSheets; + } catch { + warnings.add('Skipping `styleSheets` as it is not supported.'); + } + if (styleSheets) { + for (let styleSheet of styleSheets) { + if (isCSSOM(styleSheet) || styleSheet.href?.startsWith('blob:')) { + continue; + } else if (styleSheet.href && styleSheet.cssRules) { + try { + let styleTag = document.createElement('style'); + styleTag.type = 'text/css'; + styleTag.innerHTML = Array.from(styleSheet.cssRules) + .map(cssRule => cssRule.cssText).join('\n'); + clone.head.appendChild(styleTag); + } catch (err) { + handleErrors(err, 'Error serializing external stylesheet: ', null, { + stylesheetHref: styleSheet.href + }); + } + } + } + } +} + export function serializeCSSOM(ctx) { let { dom, clone, resources, cache, warnings } = ctx; // in-memory CSSOM into their respective DOM nodes. diff --git a/packages/dom/src/serialize-dom.js b/packages/dom/src/serialize-dom.js index 0402d6d69..a446a6bbd 100644 --- a/packages/dom/src/serialize-dom.js +++ b/packages/dom/src/serialize-dom.js @@ -1,6 +1,6 @@ import serializeInputs from './serialize-inputs'; import serializeFrames from './serialize-frames'; -import serializeCSSOM from './serialize-cssom'; +import serializeCSSOM, { serializeExternalStyles } from './serialize-cssom'; import serializeCanvas from './serialize-canvas'; import serializeVideos from './serialize-video'; import { cloneNodeAndShadow, getOuterHTML } from './clone-dom'; @@ -36,6 +36,7 @@ function serializeElements(ctx) { serializeVideos(ctx); if (!ctx.enableJavaScript) { + if (ctx.serializeExternalStyles) serializeExternalStyles(ctx); serializeCSSOM(ctx); serializeCanvas(ctx); } @@ -64,7 +65,8 @@ export function serializeDOM(options) { domTransformation = options?.dom_transformation, stringifyResponse = options?.stringify_response, disableShadowDOM = options?.disable_shadow_dom, - reshuffleInvalidTags = options?.reshuffle_invalid_tags + reshuffleInvalidTags = options?.reshuffle_invalid_tags, + serializeExternalStyles = options?.serialize_external_styles } = options || {}; // keep certain records throughout serialization @@ -74,7 +76,8 @@ export function serializeDOM(options) { hints: new Set(), cache: new Map(), enableJavaScript, - disableShadowDOM + disableShadowDOM, + serializeExternalStyles }; ctx.dom = dom; From 0af3d0a18e4202f88f70310a2d9b05a24bc05329 Mon Sep 17 00:00:00 2001 From: sharad-sharma Date: Thu, 5 Sep 2024 15:26:00 +0530 Subject: [PATCH 2/3] fix: handle CORS inaccessible stylesheets --- packages/dom/src/serialize-cssom.js | 43 +++++++++++++++++++++++------ 1 file changed, 34 insertions(+), 9 deletions(-) diff --git a/packages/dom/src/serialize-cssom.js b/packages/dom/src/serialize-cssom.js index 96a8bb68a..8f7615a25 100644 --- a/packages/dom/src/serialize-cssom.js +++ b/packages/dom/src/serialize-cssom.js @@ -37,17 +37,42 @@ export function serializeExternalStyles(ctx) { for (let styleSheet of styleSheets) { if (isCSSOM(styleSheet) || styleSheet.href?.startsWith('blob:')) { continue; - } else if (styleSheet.href && styleSheet.cssRules) { + } else if (styleSheet.href) { + let corsAccessible = false; try { - let styleTag = document.createElement('style'); - styleTag.type = 'text/css'; - styleTag.innerHTML = Array.from(styleSheet.cssRules) - .map(cssRule => cssRule.cssText).join('\n'); - clone.head.appendChild(styleTag); + if (styleSheet.cssRules) corsAccessible = true; } catch (err) { - handleErrors(err, 'Error serializing external stylesheet: ', null, { - stylesheetHref: styleSheet.href - }); + // Not CORS accessible + } + if (corsAccessible) { + try { + let styleTag = document.createElement('style'); + styleTag.type = 'text/css'; + styleTag.innerHTML = Array.from(styleSheet.cssRules) + .map(cssRule => cssRule.cssText).join('\n'); + clone.head.appendChild(styleTag); + } catch (err) { + handleErrors(err, 'Error serializing external stylesheet: ', null, { + stylesheetHref: styleSheet.href + }); + } + } else { + try { + fetch(styleSheet.href) + .then(response => response.text()) + .then(cssText => { + let styleTag = document.createElement('style'); + styleTag.type = 'text/css'; + styleTag.innerHTML = cssText; + }) + .catch(error => { + console.error('Failed to fetch stylesheet:', error); + }); + } catch (err) { + handleErrors(err, 'Error serializing external stylesheet: ', null, { + stylesheetHref: styleSheet.href + }); + } } } } From 6206cc82cdd36ecdc560375cda3b746489d5ca7c Mon Sep 17 00:00:00 2001 From: sharad-sharma Date: Thu, 5 Sep 2024 17:40:44 +0530 Subject: [PATCH 3/3] chore: remove cors inaccessible stylesheet serialization --- packages/dom/src/serialize-cssom.js | 17 ----------------- 1 file changed, 17 deletions(-) diff --git a/packages/dom/src/serialize-cssom.js b/packages/dom/src/serialize-cssom.js index 8f7615a25..5b2417772 100644 --- a/packages/dom/src/serialize-cssom.js +++ b/packages/dom/src/serialize-cssom.js @@ -56,23 +56,6 @@ export function serializeExternalStyles(ctx) { stylesheetHref: styleSheet.href }); } - } else { - try { - fetch(styleSheet.href) - .then(response => response.text()) - .then(cssText => { - let styleTag = document.createElement('style'); - styleTag.type = 'text/css'; - styleTag.innerHTML = cssText; - }) - .catch(error => { - console.error('Failed to fetch stylesheet:', error); - }); - } catch (err) { - handleErrors(err, 'Error serializing external stylesheet: ', null, { - stylesheetHref: styleSheet.href - }); - } } } }