Skip to content

Commit 9e65a35

Browse files
committed
Update Generator
1 parent 43d3416 commit 9e65a35

File tree

2 files changed

+76
-27
lines changed

2 files changed

+76
-27
lines changed

tools/LinkDotNet.Blog.CriticalCSS/Generator.cs

Lines changed: 74 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -26,35 +26,85 @@ public static async Task<string> GenerateAsync(IReadOnlyCollection<string>urls)
2626

2727
var usedCss = await page.EvaluateAsync<string[]>(
2828
"""
29-
() => {
30-
const styleSheets = Array.from(document.styleSheets);
31-
const usedRules = new Set();
29+
async () => {
30+
const styleSheets = Array.from(document.styleSheets);
31+
const usedRules = new Set();
32+
const processedUrls = new Set();
3233
33-
const viewportHeight = window.innerHeight;
34-
const elements = document.querySelectorAll('*');
35-
const aboveFold = Array.from(elements).filter(el => {
36-
const rect = el.getBoundingClientRect();
37-
return rect.top < viewportHeight;
38-
});
34+
const viewportHeight = window.innerHeight;
35+
const elements = document.querySelectorAll('*');
36+
const aboveFold = Array.from(elements).filter(el => {
37+
const rect = el.getBoundingClientRect();
38+
return rect.top < viewportHeight;
39+
});
3940
40-
styleSheets.forEach(sheet => {
41-
try {
42-
Array.from(sheet.cssRules).forEach(rule => {
43-
if (rule.type === 1) {
44-
aboveFold.forEach(el => {
45-
if (el.matches(rule.selectorText)) {
46-
usedRules.add(rule.cssText);
47-
}
48-
});
49-
}
50-
});
51-
} catch (e) {
41+
async function fetchExternalStylesheet(url) {
42+
if (processedUrls.has(url)) return;
43+
processedUrls.add(url);
44+
45+
try {
46+
const response = await fetch(url);
47+
const text = await response.text();
48+
const blob = new Blob([text], { type: 'text/css' });
49+
const styleSheet = new CSSStyleSheet();
50+
await styleSheet.replace(text);
51+
return styleSheet;
52+
} catch (e) {
53+
console.error('Failed to fetch:', url, e);
54+
return null;
55+
}
56+
}
57+
58+
async function processStyleSheet(sheet) {
59+
try {
60+
if (sheet.href) {
61+
const externalSheet = await fetchExternalStylesheet(sheet.href);
62+
if (externalSheet) {
63+
Array.from(externalSheet.cssRules).forEach(processRule);
5264
}
53-
});
65+
}
66+
67+
Array.from(sheet.cssRules).forEach(processRule);
68+
} catch (e) {
69+
if (sheet.href) {
70+
console.error('CORS issue with:', sheet.href);
71+
}
72+
}
73+
}
5474
55-
return Array.from(usedRules);
75+
function processRule(rule) {
76+
switch (rule.type) {
77+
case CSSRule.STYLE_RULE:
78+
aboveFold.forEach(el => {
79+
try {
80+
if (el.matches(rule.selectorText)) {
81+
usedRules.add(rule.cssText);
82+
}
83+
} catch (e) {}
84+
});
85+
break;
86+
case CSSRule.MEDIA_RULE:
87+
if (window.matchMedia(rule.conditionText).matches) {
88+
Array.from(rule.cssRules).forEach(processRule);
89+
}
90+
break;
91+
case CSSRule.IMPORT_RULE:
92+
processStyleSheet(rule.styleSheet);
93+
break;
94+
case CSSRule.FONT_FACE_RULE:
95+
case CSSRule.KEYFRAMES_RULE:
96+
usedRules.add(rule.cssText);
97+
break;
5698
}
57-
""");
99+
}
100+
101+
for (const sheet of styleSheets) {
102+
await processStyleSheet(sheet);
103+
}
104+
105+
return Array.from(usedRules);
106+
}
107+
""");
58108

59109
foreach (var css in usedCss)
60110
{

tools/LinkDotNet.Blog.CriticalCSS/Program.cs

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -110,11 +110,10 @@ static void OutputToLayout(string css, string? layoutPath)
110110
const string styleTagPattern = "<style[^>]*>.*?</style>";
111111
const string headEndTag = "</head>";
112112

113-
var newStyleTag = $"<style>{css}</style>";
114113

115114
layoutContent = Regex.IsMatch(layoutContent, styleTagPattern, RegexOptions.Singleline)
116-
? Regex.Replace(layoutContent, styleTagPattern, newStyleTag, RegexOptions.Singleline)
117-
: layoutContent.Replace(headEndTag, $"{newStyleTag}\n {headEndTag}", StringComparison.OrdinalIgnoreCase);
115+
? Regex.Replace(layoutContent, styleTagPattern, css, RegexOptions.Singleline)
116+
: layoutContent.Replace(headEndTag, $"{css}\n {headEndTag}", StringComparison.OrdinalIgnoreCase);
118117

119118
File.WriteAllText(layoutPath, layoutContent);
120119
}

0 commit comments

Comments
 (0)