tl;dr; minimalcss 0.8.2 introduces a 20% post-processing optimization by lumping many CSS selectors to their parent CSS selectors as a pre-emptive cache.
In minimalcss the general core of it is that it downloads a DOM tree, as HTML, parses it and parses all the CSS stylesheets associated. These might be from
<link ref="stylesheet"> or
Once the CSS stylesheets are turned into an AST it loops over each and every CSS selector and asks a simple question; "Does this CSS selector exist in the DOM?". The equivalent is to open your browser's Web Console and type:
>>> document.querySelectorAll('div.foo span.bar b').length > 0 false
For each of these lookups (which is done with
cheerio by the way),
minimalcss reduces the CSS, as an AST, and eventually spits the AST back out as a CSS string. The only problem is; it's slow. In the case of
view-source:https://semantic-ui.com/ in the CSS it uses, there are
6,784 of them. What to do?
First of all, there isn't a lot you can do. This is the work that needs to be done. But one thing you can do is be smart about which selectors you look at and use a "decision cache" to pre-emptively draw conclusions. So, if this is what you have to check:
#example .solid .column p b
#example .solid .column p
As you process the first one you
extract that the parent CSS selector is
#example and if that doesn't exist in the DOM, you can efficiently draw conclusion about all preceeding selectors that all start with
#example .... Granted, if they call exist you will pay a penalty of doing an extra lookup. But that's the trade-off that this optimization is worth.
Check out the comments where I tested a bloated page that uses Semantic-UI before and after. Instead of doing 3,285 of these
document.querySelector(selector) calls, it's now able too come to the exact same conclusion with just 1,563 lookups.
Sadly, the majority of the time spent processing lies in network I/O and other overheads but this work did reduce something that used to take 6.3s (median) too 5.1s (median).