-
Notifications
You must be signed in to change notification settings - Fork 0
/
index.js
87 lines (72 loc) · 3.21 KB
/
index.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
const path = require("path");
const fs = require("fs");
const getUrl = decl => {
var matches = /(url\(\s*['"]?)([^"')]+)(["']?\s*\))/g.exec(decl.value);
return matches && matches[2];
};
/**
* Find all rules with a :hover pseudoclass and prefetch them either via HTML or JS.
*/
module.exports = (opts = {}) => {
opts = opts || {};
opts.outputType = opts.outputType || "html";
opts.preloadType = opts.preloadType || "prefetch";
return {
postcssPlugin: "postcss-preload-hovers",
Once(root, { result }) {
if (opts.outputType && opts.outputType !== "html" && opts.outputType !== "js") {
return result.warn(`postcss-preload-hovers only accepts an outputType of "html", "js" or "file"`);
}
if (opts.preloadType !== "prefetch" && opts.preloadType !== "preload" && opts.preloadType !== "image") {
return result.warn(`postcss-preload-hovers only accepts an preloadType of "prefetch", "preload" or "image"`);
}
const from = result.opts.from ? path.dirname(result.opts.from) : ".";
const to = result.opts.to ? path.dirname(result.opts.to) : ".";
const rebaseUrl = url => (url.startsWith("http") ? url : path.join(path.relative(from, to), url));
let urlsToPreload = [];
// Get all URLs from hover pseudorules
root.walkRules(/:hover/, rule => {
rule.walkDecls(decl => {
var url = getUrl(decl);
if (url) urlsToPreload.push(url);
});
});
// Turn any image loaders into their appropriate HTML or JS representations
const preloaders = urlsToPreload
.filter(url => /\.jpe?g$|\.png$|\.gif$|\.svg$/.test(url))
.map(url => rebaseUrl(url));
result = (function () {
if (opts.outputType === "html") {
if (opts.preloadType === "image") {
return preloaders.map(url => `<img src="${url}" style="display: none;">`).join("\n");
} else {
return preloaders.map(url => `<link rel="${opts.preloadType}" href="${url}" as="image">`).join("\n");
}
} else if (opts.outputType === "js") {
const arrayString = "[" + preloaders.map(url => `"${url}"`).join(",") + "]";
if (opts.preloadType === "image") {
return `${arrayString}.forEach(function(url) { var img = new Image(); img.src = url; });`;
} else {
return `${arrayString}.forEach(function(url) { var link = document.createElement("link"); link.rel = "${opts.preloadType}"; link.href = url; link.as = "image"; document.head.appendChild(link); });`;
}
} else {
result.warn("Unknown output type ${opts.outputType} (it shouldn't be possible to get here!)");
}
})();
if (opts.filename) {
// Write the results to a file
fs.writeFileSync(opts.filename, result);
return;
}
if (opts.resultObj) {
// Write the results to a shared object (very unfunctional, but a convenient and fast way to get data out)
opts.resultObj.data = result;
return;
}
// Otherwise write the HTML or JS as comment nodes which we can then extract in the stringifier
root.removeAll();
root.append({ text: result });
},
};
};
module.exports.postcss = true;