amoerie 5 years ago

What about dynamically changing HTML? Modal dialogs, dynamically loaded divs (depending on access rights), etc.

Unless your css is only ever loaded when the corresponding HTML is, this is going to flag a lot of false positives..

  • leeoniya 5 years ago

    yep, you need to keep a whitelist. i made a 10-liner plugin for css-obj (see my other comment) which i use to mark certain selectors with "!keep" which populates my per-page whitelists during initial css blob gen.

    if most of your classes are dynamically applied or most markup is missing then this type of tool is probably not for you, especially if you have no good way of html-ifying enough state variations to keep your whitelist managable.

    FWIW, i run an SSR'd ecommerce site (with modals and a quite a bit of other dynamic bits) and while whitelisting needs to be maintained, the resulting list is fewer than 30 items and basically static. the items are regex and some cover multiple/related selectors.

    an improvement to this project might be to add inline ignore rules like purgecss does. eg /* nodrop * /

leeoniya 5 years ago

Hi HN,

I put this together when looking to replace Purgecss in my build chain due to its numerous and unresolved/unresolvable correctness deficiencies.

TL;DR:

- Tiny API, ~60 LOC + 3 small deps

- Does not process `<script>` or JS

- Smaller and more thorough than Purgecss, UnCSS, PurifyCSS

- Perf: 2.0x UnCSS, 1.1x PurifyCSS, 0.4x Purgecss

  • owens99 5 years ago

    Nice work! Will give it a try.

Theodores 5 years ago

Very nice tool.

Small request. Can you use your knowledge of AST etc. to write another small 60 line script that just counts the amount of style rules in a CSS file?

I have tried this and not been able to do a good job of it, media queries, CSS variables and other things have thrown me off and I think you are coming from a better starting point for this 'simple task'.

Lines of code is not a useful metric with CSS and counting rules is not so simple as parsing is really a browser thing.

  • leeoniya 5 years ago

    by 'style rules' do you mean selectors or properties/values?

    • Theodores 5 years ago

      Yes, just the amount of selectors.

      Properties/values is another metric worth knowing.

      I think that getting a number for both these metrics in the stylesheets rather than the page currently viewed is more useful if you are working on a site.

      As well as the stylesheets that are external the rules in an embedded stylesheet are useful. My ideal tool takes a page and gets those metrics from attached stylesheets as well as the inline stylesheets, with inline styles totalled up too.

      I have had a go at this using DomDocument PHP but took a guess at the rules based on the total count of '{' - terrible hack, but okay for ballpark figures. I would prefer to be able to do it properly, but I have not got anywhere trying to do it the node way. I didn't even know about CSSTree/AST.

      • tln 5 years ago

        This would be pretty trivial in the Chrome Inspector. Try loading your site, opening the inspector console and running this..

        document.styleSheets[0].cssRules.length

        ..and then work on aggregating all stylesheet rules according to your needs (per stylesheet etc)

        Then if you want to automate further, take that code and use puppeteer to run it headless. That'll work with single page apps as well, in a way the OP's tool (nice work btw!) and DomDocument in PHP never will.

      • leeoniya 5 years ago

        the main loop [1] already only visits "Rule" blocks, so you can just stick a counter in there, taking care to split combinator selectors on "," as i do, and add them up.

        [1] https://github.com/leeoniya/dropcss/blob/master/src/dropcss....

        • Theodores 5 years ago

          Brilliant. Bookmarked. Thanks for that.

          I am going to have a go with that, I found the main problem I was having and that was a failure to actually obtain some stylesheets. The ones that were without the https://domain at the front were silently being downloaded blank, parsed as blank and therefore not giving expected results. Garbage in, garbage out rather than anything complicated. Sometimes though you expect the harder bits to be wrong, e.g. only finding 'one match per line' due to not having a convoluted enough regex, or something else complicated.

          I have to work out how to present data too so I will finish that bit off using my simple 'count the {' approach as that is near enough for a rule count, and fast too.

          However, I am also interested in qualitative analysis to determine if things such as CSS grid is used or if it is all floats, whether CSS variables are used or not and if selectors are all about classes or if there are more advanced ones.

          I think I really need to get the backend bit cludged together for now but then pick up on your work to take things on to this next level. Sometimes a cludge that is ballpark is useful, presenting information can only really be done when you have something to work with. Any developer can find out the information they need, presenting it to a non technical audience in a succinct way in order to back up an argument is a very different proposition.

          Believe it or not 'getting the colours right' is a challenge. So imagine I want to convey to some person that shuns code and only cares about pretty pictures that their plans to use this theme or build a Wix/Shopify/Squarespace site is not what they want to be doing. They aren't going to listen to me describing how these easy solutions are not performant. But, with a few pretty graphs and succinct summaries that becomes easier.

          I think you have given me the pieces of the puzzle that I need to do this. In my own mind I can imagine the bullet points that summarise the key findings. Best get on with it!!!

          Many thanks.

bigbadgoose 5 years ago

OK, what all these tools have not exhibited so far is upstream optimization of source generator, ie scss.

Dream scenario: 1/ run against generated output via url submission, 2/ receive optimized output, 3/ point at source generator tree, 4/ receive suggested source diffs

Lucid dream scenario: point at repository, receive optimized source diff suggestions on a per-file basis

  • leeoniya 5 years ago

    > 4/ receive suggested source diffs.

    most of the removed css isnt necessarily useless globally, it's just useless in context. eg a shared bootstrap css grid will be pruned differently on different pages, but there's no single "suggestion" that can be used to modify that shared initial grid.

    for css that's leftover by accident that should actually be removed from the source, i agree. but how will you discern the first scenario from the second?

    • bigbadgoose 5 years ago

      Per-group (URLs that operate within a 10% optimization range) cached css, generated by source tree + crawl + ongoing visit data?

      Edit, also pls send me a pony. Optimzations have a few audiences, the primaries of which are the visitor and the developer. Source tree prunes ("developer audience") not addressed in my off-the-cuff pipe dream above

  • err4nt 5 years ago

    CSS-blocks.com is the closest high-quality tool like this, but it's approach is slightly different, it doesn't work against any page, but for this approach it's by far the best quality and most powerful tool like this right now. And, it's made by one of the maintainers of Sass

buu700 5 years ago

Does (or will) this support SCSS, and Angular HTML, and JavaScript/TypeScript/JSX? I'm on a project right now where a tool like that will be immensely helpful pretty soon.

  • leeoniya 5 years ago

    most definitely not. at least not in the core.

    the aim is to stay simple and target the common baseline; there are ~1e6 css and html supersets with existing tools to output plain html and css. surely it's not difficult to glue the subset you need together.

    as an aside, i've come to dislike scss and much prefer to maintain my stylesheets in plain js, without awkward looping constructs, conditionals, variables, "mixins", etc. all of this is an already-solved problem with es modules and the language i already use: js.

    check out:

    https://github.com/cssobj/cssobj

    https://github.com/cssobj/cssobj-plugin-gencss

jhabdas 5 years ago

Very pithy, Leon. What made you think to write this?

P.s. When you slightly tweak MIT code you need to include the copyright and notice in your license, or ask the copyright holder to switch to 0BSD.

JensRex 5 years ago

I wish there was something like this not written in JavaScript.

  • leeoniya 5 years ago

    i'm sure there will be soon enough. i kind of laughed to myself when calling it "fast" since it takes 175ms to process ~45 KB of data :D. in a compiled language (or wasm) it would no doubt be an order of magnitude faster.

    • postalrat 5 years ago

      Why is wasm faster than javascript? Can't the browser compile javascript to something equivalent?

adrianhel 5 years ago

The fact that this is even needed is why I like CSS-in-JS.

  • leeoniya 5 years ago

    you might still need it if you plan to use third party css libs, but not wholesale.