From a74bd4972ccf80314f8eac8b05068434997ae161 Mon Sep 17 00:00:00 2001 From: 01zulfi <85733202+01zulfi@users.noreply.github.com> Date: Mon, 16 Jun 2025 12:14:37 +0500 Subject: [PATCH] clipper: move inlining stylesheeet & css import resolution logic to addStylesToHead Signed-off-by: 01zulfi <85733202+01zulfi@users.noreply.github.com> --- packages/clipper/src/domtoimage.ts | 3 -- packages/clipper/src/index.ts | 2 +- packages/clipper/src/styles.ts | 57 +++++++++++++++++++++++------- 3 files changed, 45 insertions(+), 17 deletions(-) diff --git a/packages/clipper/src/domtoimage.ts b/packages/clipper/src/domtoimage.ts index 22435ab1a..0b1959e86 100644 --- a/packages/clipper/src/domtoimage.ts +++ b/packages/clipper/src/domtoimage.ts @@ -28,7 +28,6 @@ import { width, isSVGElement } from "./utils.js"; -import { inlineStylesheets } from "./styles.js"; import { cloneNode } from "./clone.js"; // Default impl options @@ -47,8 +46,6 @@ async function getInlinedNode(node: HTMLElement, options: Options) { if (!clone || clone instanceof Text) return; - if (stylesheets) await inlineStylesheets(options.fetchOptions); - if (fonts) clone = await embedFonts(clone, options.fetchOptions); if (inlineImages) await inlineAllImages(clone, options.fetchOptions); diff --git a/packages/clipper/src/index.ts b/packages/clipper/src/index.ts index e0bbebfd2..0b02c2814 100644 --- a/packages/clipper/src/index.ts +++ b/packages/clipper/src/index.ts @@ -490,7 +490,7 @@ async function getPage( head.appendChild(title); if (config?.styles) { - addStylesToHead(head, fetchOptions); + await addStylesToHead(head, fetchOptions); } return { diff --git a/packages/clipper/src/styles.ts b/packages/clipper/src/styles.ts index c97d37fda..d3e544abb 100644 --- a/packages/clipper/src/styles.ts +++ b/packages/clipper/src/styles.ts @@ -19,7 +19,7 @@ along with this program. If not, see . import { constructUrl, FetchOptions } from "./fetch.js"; import { inlineAll } from "./inliner.js"; -export async function inlineStylesheets(options?: FetchOptions) { +async function resolveImports(options?: FetchOptions) { for (const sheet of document.styleSheets) { const rulesToDelete = []; if (await skipStyleSheet(sheet, options)) continue; @@ -31,16 +31,17 @@ export async function inlineStylesheets(options?: FetchOptions) { if (rule.type === CSSRule.IMPORT_RULE) { const href = (rule as CSSImportRule).href; const result = await downloadStylesheet(href, options); - if (!result) continue; - if (sheet.ownerNode) sheet.ownerNode.before(result); - else document.head.appendChild(result); - rulesToDelete.push(i); + if (result) { + if (sheet.ownerNode) sheet.ownerNode.before(result); + else document.head.appendChild(result); + rulesToDelete.push(i); + } } } - await inlineBackgroundImages(sheet, options); - - for (const ruleIndex of rulesToDelete) sheet.deleteRule(ruleIndex); + if (sheet.cssRules.length !== 0) { + for (const ruleIndex of rulesToDelete) sheet.deleteRule(ruleIndex); + } } } @@ -83,20 +84,50 @@ function isStylesheetForPrint(sheet: CSSStyleSheet | HTMLLinkElement) { .includes("print"); } -export function addStylesToHead(head: HTMLHeadElement, options?: FetchOptions) { +export async function addStylesToHead( + head: HTMLHeadElement, + options?: FetchOptions +) { + await resolveImports(options); + for (const sheet of document.styleSheets) { if (isStylesheetForPrint(sheet)) continue; - if (sheet.href && sheet.ownerNode instanceof HTMLLinkElement) continue; - const styleNode = rulesToStyleNode(sheet.cssRules); - head.appendChild(styleNode); + const href = + sheet.href && sheet.ownerNode instanceof HTMLLinkElement + ? sheet.ownerNode.href + : sheet.ownerNode instanceof HTMLStyleElement + ? sheet.ownerNode.getAttribute("href") + : null; + if (href) { + const result = await downloadStylesheet(href, options); + if (!result) continue; + const cssStylesheet = new CSSStyleSheet(); + cssStylesheet.replace(result.innerHTML); + await inlineBackgroundImages(cssStylesheet, options); + const toAppend = rulesToStyleNode(cssStylesheet.cssRules); + head.appendChild(toAppend); + continue; + } + + if (sheet.cssRules.length > 0) { + await inlineBackgroundImages(sheet, options); + const styleNode = rulesToStyleNode(sheet.cssRules); + head.appendChild(styleNode); + continue; + } + + if (sheet.ownerNode instanceof HTMLStyleElement) { + head.appendChild(sheet.ownerNode.cloneNode(true)); + continue; + } } } function rulesToStyleNode(cssRules: CSSRuleList) { const cssText = Array.from(cssRules) .map((r) => r.cssText) - .reduce((acc, text) => acc + text); + .reduce((acc, text) => acc + text, ""); const style = document.createElement("style"); style.innerHTML = cssText; return style;