Last active
February 20, 2024 21:34
-
-
Save thomaswilburn/fab35b632b73b9e0aaf95d2f0fbda91e to your computer and use it in GitHub Desktop.
Async imports for CSS files
This file contains 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
var links = document.querySelectorAll(`link[rel="stylesheet"][media="async"], link[rel="async-styles"]`); | |
for (var link of links) { | |
var resolved = new URL(link.href, window.location); | |
var processed = await getSheet(resolved.toString()); | |
var style = document.createElement("style"); | |
var constructed = new CSSStyleSheet(); | |
var output = serializeCSS(processed); | |
constructed.replaceSync(output); | |
// console.log(output); | |
document.adoptedStyleSheets.push(constructed); | |
} | |
function serializeCSS(sheet) { | |
var output = ""; | |
for (var rule of Array.from(sheet.cssRules)) { | |
output += rule.cssText + "\n"; | |
} | |
return output; | |
} | |
async function getSheet(url, cache = new Set()) { | |
if (cache.has(url)) { | |
console.log(`Skipping import for ${url}, already loaded elsewhere`); | |
return { cssRules: [], url } | |
} | |
cache.add(url); | |
var response = await fetch(url); | |
var text = await response.text(); | |
var sheet = parseSheet(text); | |
sheet.url = url; | |
var processed = await processSheet(sheet, cache); | |
return processed; | |
} | |
function parseSheet(text) { | |
var parser = new DOMParser(); | |
var html = parser.parseFromString(`<style>${text}</style>`, "text/html"); | |
var style = html.querySelector("style"); | |
return style.sheet; | |
} | |
async function processSheet(stylesheet, cache) { | |
for (var i = 0; i < stylesheet.cssRules.length; i++) { | |
var rule = stylesheet.cssRules[i]; | |
if (rule instanceof CSSImportRule) { | |
stylesheet.deleteRule(i); | |
var resolved = new URL(rule.href, stylesheet.url).toString(); | |
var imported = await getSheet(resolved, cache); | |
for (var j = imported.cssRules.length - 1; j >= 0; j--) { | |
var insert = imported.cssRules[j]; | |
stylesheet.insertRule(insert.cssText, i); | |
} | |
i += imported.cssRules.length; | |
} | |
} | |
return stylesheet; | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment