github

leeoniya / dropcss

  • воскресенье, 24 марта 2019 г. в 00:18:53
https://github.com/leeoniya/dropcss

JavaScript
A simple, thorough and fast unused-CSS cleaner



🗑 DropCSS

A simple, thorough and fast unused-CSS cleaner (MIT Licensed)


Introduction

DropCSS is an unused CSS cleaner; it takes your HTML and CSS as input and returns only the used CSS as output. The core is simply some minimal glue between these awesome low-level tools:

The entire logic for DropCSS is this ~60 line file.

It is recommended to also run your CSS through an optimizer like clean-css to group selectors, merge and remove redundant rules, purge unused keyframes, etc. Whether this is done before or after DropCSS is up to you, but since clean-css also minifies, it probably makes sense to run DropCSS first to avoid bouncing [and re-parsing] the output back and forth (optimize & minify -> drop) vs (optimize -> drop -> minify), though this will likely depend on your actual input; profiling is your friend.

A bit more on this project's backstory in this Reddit thread.


Installation

npm install -D dropcss

Usage & API

const dropcss = require('dropcss');

let html = `
    <html>
        <head></head>
        <body>
            <p>Hello World!</p>
        </body>
    </html>
`;

let css = `
    .card {
      padding: 8px;
    }

    p:hover a:first-child {
      color: red;
    }
`;

const whitelist = /\b(?:#foo|\.bar)\b/;

let dropped = new Set();

// returns a string
let cleanCSS = dropcss({
    html,
    css,
    shouldDrop: (sel) => {
        if (whitelist.test(sel))
            return false;
        else {
            dropped.add(sel);
            return true;
        }
    },
});

console.log(cleanCSS);

console.log(dropped);

shouldDrop is called for every CSS selector that could not be matched in the html. Return false to retain it or true to drop it. Additionally, this hook can be used to log all removed selectors.


Features

DropCSS stands on the shoulders of giants.

  • Removal of practically all conceivable selectors is achieved thanks to the exhaustive selector support of css-select: https://github.com/fb55/css-select#supported-selectors.
  • CSSTree enables media queries to be transparently processed and removed like all other blocks without special handling.
  • Retention of all transient pseudo-class and pseudo-element selectors which cannot be deterministically checked from the parsed HTML.

Performance

Input

test.html

  • 18.8 KB minified
  • 502 dom nodes via document.querySelectorAll("*").length

styles.min.css

  • 27.67 KB combined, optimized and minified via clean-css
  • contents: Bootstrap's reboot.css, an in-house flexbox grid, global layout, navbars, colors & page-specific styles. (the grid accounts for ~85% of this starting weight, lots of media queries & repetition)

Output

lib size w/deps output size reduction time elapsed unused bytes (test.html coverage)
DropCSS 2.16 MB
251 Files, 51 Folders
6.60 KB 76.15% 175ms 575 / 8.5%
UnCSS 13.7 MB
2,831 Files, 301 Folders
6.72 KB 75.71% 429ms 638 / 9.3%
Purgecss 2.53 MB
513 Files, 110 Folders
8.01 KB 71.05% 78ms 1,806 / 22.0%
PurifyCSS 3.45 MB
791 Files, 207 Folders
15.4 KB 44.34% 186ms 9,440 / 59.6%

Notes

  • About 400 "unused bytes" are due to an explicit/shared whitelist, not an inability of the tools to detect/remove that CSS.
  • About 175 "unused bytes" are due to vendor-prefixed (-moz, -ms) properties & selectors that are inactive in Chrome, which is used for testing coverage.
  • Purgecss does not support attribute or complex selectors: Issue #110.

Caveats

  • Not tested against malformed HTML (the underlying Fast HTML Parser claims to support common cases but not all)
  • Not tested against malformed CSS (the underlying CSSTree parser claims to be "Tolerant to errors by design")
  • There is no processing or execution of <script> tags; your HTML must be fully formed (or SSR'd). You should generate and append any additional HTML that you'd want to be considered by DropCSS. If you need JS execution, consider using the larger, slower but still good output, UnCSS. Alternatively, Puppeteer can now output coverage reports, and there might be tools that utilize this coverage data to clean your CSS, too. DropCSS aims to be minimal, simple and effective.