-
Notifications
You must be signed in to change notification settings - Fork 415
/
Copy pathcollect.js
90 lines (73 loc) · 1.84 KB
/
collect.js
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
/* @flow */
const postcss = require('postcss');
/* ::
type CollectResult = {
critical: string,
other: string,
};
*/
const collect = (
html /* : string */,
css /* : string */,
globalCSS /* : ?string */
) /* : CollectResult */ => {
const animations = new Set();
const other = postcss.root();
const critical = postcss.root();
const stylesheet = postcss.parse(css);
const htmlClassesRegExp = extractClassesFromHtml(html);
const handleAtRule = rule => {
let addedToCritical = false;
rule.each(childRule => {
if (childRule.selector.match(htmlClassesRegExp)) {
critical.append(rule.clone());
addedToCritical = true;
}
});
if (rule.name === 'keyframes') {
return;
}
if (addedToCritical) {
rule.remove();
} else {
other.append(rule);
}
};
stylesheet.walkRules(rule => {
if (rule.parent.name === 'keyframes') {
return;
}
if (rule.parent.type === 'atrule') {
handleAtRule(rule.parent);
return;
}
if (rule.selector.match(htmlClassesRegExp)) {
critical.append(rule);
} else {
other.append(rule);
}
});
critical.walkDecls(/animation/, decl => {
animations.add(decl.value.split(' ')[0]);
});
stylesheet.walkAtRules('keyframes', rule => {
if (animations.has(rule.params)) {
critical.append(rule);
}
});
return {
critical: (globalCSS || '') + critical.toString(),
other: other.toString(),
};
};
const extractClassesFromHtml = (html /* : string */) /* : RegExp */ => {
const htmlClasses = [];
const regex = /\s+class="([^"]*)"/gm;
let match = regex.exec(html);
while (match !== null) {
match[1].split(' ').forEach(className => htmlClasses.push(className));
match = regex.exec(html);
}
return new RegExp(htmlClasses.join('|'), 'gm');
};
module.exports = collect;