john
Oct 25 2020 at 11:33 GMT
I have an HTML file that has CSS distributed across several <style>
tags.
A lot of the CSS included in the HTML is not used.
I would like to remove all unused CSS and leave only CSS that is actually used on the page.
How can I write a removeUnusedCss
function in NodeJS that takes the content of the HTML file and returns the same content but with all unused CSS stripped away?
function removeUnusedCss(html) {
// ...
}
Laverage
Oct 25 2020 at 12:22 GMT
There is an npm package called dropcss
that takes the CSS and HTML as input, and returns only the CSS that is used:
const dropcss = require("dropcss");
const result = dropcss({ css, html });
const usedCss = result.css;
So, to remove all unused CSS from an HTML file with dropcss
, we would need to do the following:
dropcss
.dropcss
into the HTML in place of the original CSS.To extract the CSS from all the <style>
tags, we need a simple HTML parser, such as node-html-parser
.
We start by parsing the passed html
using the parse
function provided by node-html-parser
and selecting all <style>
tags.
const document = parse(html);
const styles = document.querySelectorAll("style");
We then check if there are no styles. If that's the case, we are done and so we return the HTML unchanged.
if (styles.length === 0) {
return html;
}
Otherwise, we collect the CSS inside all <style>
tags into a single string variable css
.
const css = styles.map((style) => style.innerHTML).join("\n");
Now that we extracted the CSS, we can pass it to dropcss
along with the HTML to get only the used CSS.
const usedCss = dropcss({ css, html }).css
We then get the last <style>
tag by popping it from the styles
array and remove all the remaining <style>
tags from the document.
const lastStyle = styles.pop();
styles.forEach((style) => style.parentNode.removeChild(style));
Finally, we set the content of the last <style>
tag that we left in the document to usedCss
and return the document HTML.
lastStyle.set_content(usedCss);
return document.toString();
Here's the final removeUnusedCss
function that does all the steps we just went through:
const { parse } = require("node-html-parser");
const dropcss = require("dropcss");
function removeUnusedCss(html) {
const document = parse(html);
const styles = document.querySelectorAll("style");
if (styles.length === 0) {
return html;
}
const css = styles.map((style) => style.innerHTML).join("\n");
const usedCss = dropcss({ css, html }).css;
const lastStyle = styles.pop();
styles.forEach((style) => style.parentNode.removeChild(style));
lastStyle.set_content(usedCss);
return document.toString();
}
Don't forget to install the node-html-parser
and dropcss
dependencies:
npm install node-html-parser dropcss