Created
September 24, 2024 10:49
-
-
Save jonathanpv/54044cd3ea02896c7875710495cfdfa4 to your computer and use it in GitHub Desktop.
better
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
(async function downloadCompleteHTML() { | |
// Helper function to fetch content of external files (CSS, JS, images) | |
async function fetchResource(url, isBinary = false) { | |
try { | |
const response = await fetch(url); | |
if (isBinary) { | |
const blob = await response.blob(); | |
return new Promise((resolve, reject) => { | |
const reader = new FileReader(); | |
reader.onloadend = () => resolve(reader.result); | |
reader.onerror = reject; | |
reader.readAsDataURL(blob); | |
}); | |
} else { | |
return await response.text(); | |
} | |
} catch (error) { | |
console.warn('Failed to fetch resource:', url); | |
return ''; | |
} | |
} | |
// Helper function to inline external CSS and convert relative URLs to absolute | |
async function fetchAndProcessCSS(linkElement) { | |
const href = linkElement.href; | |
const cssContent = await fetchResource(href); | |
// Resolve relative URLs within CSS (for images, fonts, etc.) | |
return cssContent.replace(/url\((?!['"]?(?:data|https?|ftp):)['"]?([^'")]+)['"]?\)/g, function(match, relativeUrl) { | |
const absoluteUrl = new URL(relativeUrl, href).href; | |
return `url(${absoluteUrl})`; | |
}); | |
} | |
// Helper function to convert images to base64-encoded data URIs | |
async function inlineImages(element) { | |
const images = element.querySelectorAll('img'); | |
for (let img of images) { | |
if (img.src.startsWith('http')) { | |
const dataUri = await fetchResource(img.src, true); | |
img.src = dataUri; // Replace the src with base64-encoded data URI | |
} | |
} | |
} | |
// Helper function to parse CSS and apply styles inline | |
function applyStyles(element, styleSheet) { | |
for (let rule of styleSheet.cssRules) { | |
if (rule instanceof CSSStyleRule) { | |
try { | |
const elements = element.querySelectorAll(rule.selectorText); | |
elements.forEach(el => { | |
const computedStyle = getComputedStyle(el); | |
for (let prop of rule.style) { | |
if (prop.startsWith('--')) continue; // Skip CSS variables | |
const value = computedStyle.getPropertyValue(prop); | |
const priority = rule.style.getPropertyPriority(prop); | |
el.style.setProperty(prop, value, priority); | |
} | |
}); | |
} catch (e) { | |
console.warn('Failed to apply styles for selector:', rule.selectorText, e); | |
} | |
} | |
} | |
} | |
// Remove CSS variable definitions from style attributes | |
function removeCSSVariableDefinitions(element) { | |
if (element.style) { | |
for (let i = element.style.length - 1; i >= 0; i--) { | |
const propName = element.style[i]; | |
if (propName.startsWith('--')) { | |
element.style.removeProperty(propName); | |
} | |
} | |
} | |
for (let child of element.children) { | |
removeCSSVariableDefinitions(child); | |
} | |
} | |
// Fetch and process all external CSS | |
const linkElements = [...document.querySelectorAll('link[rel="stylesheet"]')]; | |
const allCSS = await Promise.all(linkElements.map(fetchAndProcessCSS)); | |
const combinedCSS = allCSS.join('\n'); | |
// Create a style sheet from the combined CSS | |
const styleSheet = new CSSStyleSheet(); | |
await styleSheet.replace(combinedCSS); | |
// Apply styles inline to all elements in the document | |
applyStyles(document, styleSheet); | |
// Remove all <link> and <style> elements | |
document.querySelectorAll('link[rel="stylesheet"], style').forEach(el => el.remove()); | |
// Inline all images as base64 data URIs | |
await inlineImages(document); | |
// Remove CSS variable definitions from style attributes | |
removeCSSVariableDefinitions(document.documentElement); | |
// Get the final HTML including the modified DOM | |
const finalHTML = document.documentElement.outerHTML; | |
// Create a downloadable HTML file | |
const downloadHTML = (content, fileName) => { | |
const a = document.createElement("a"); | |
const file = new Blob([content], { type: "text/html" }); | |
a.href = URL.createObjectURL(file); | |
a.download = fileName; | |
document.body.appendChild(a); | |
a.click(); | |
document.body.removeChild(a); | |
}; | |
// Download the final HTML file | |
downloadHTML(finalHTML, "index_inline_css.html"); | |
// Hide loading overlay (assuming it exists in your HTML) | |
const loadingOverlay = document.getElementById('loadingOverlay'); | |
if (loadingOverlay) { | |
loadingOverlay.style.display = 'none'; | |
} | |
console.log("Download complete. The HTML file contains inline CSS from all external stylesheets."); | |
})(); |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment