UNPKG

postcss-preload-hovers

Version:

A plugin to search for images with the :hover pseudo-class and generate links to preload them

88 lines (72 loc) 3.28 kB
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;