Hacker News new | past | comments | ask | show | jobs | submit login
Automatic class sorting with Prettier (2022) (tailwindcss.com)
98 points by ekiauhce 8 months ago | hide | past | favorite | 79 comments



Biome [0], a fast Prettier-compatible formatter, is currently working on adding class sorting [1]. We expect to ship the feature with the next release (on February). We are discussing which options to provide for the feature (mainly on the Discord of Biome).

[0] https://biomejs.dev/ [1] https://github.com/biomejs/biome/pull/1362


I commend anyone for trying to make the tooling ecosystem better, but I’ve never once thought Prettier was too slow. It runs in a fraction of a second on file save.

The performance comparison on Biomejs’ site shows a Prettier run taking 14 seconds, which I can imagine on a very large code base might be true - but that’s a one-off case surely? Once it’s run, it’s just a case of format on save or commit which is back to near-instantaneous.

What’s the use case I’m missing here?


Typically, you would check the formatting of the entire codebase on the CI or even locally (to ensure that you are doing the same checks on the CI and locally). On a large code base this can take several seconds, reducing developer experience. Yes, you can use git hook to check only changed files. However, this requires more setup and may lead to some misses.

Biome can also format malformed code. It supports formatting as you type.

Biome has less known non-idempotent formatting (For some edge cases you need to run twice Prettier to get a stabilized output).

Biome is also a linter. You get two tools that are closely compatible.


git commit hooks & ci checks that ensure everything is formatted because that one coworker refuses to set it up to run on save and keeps forgetting causing merge conflicts down the line


We all know that individual…

But still, formatting changed files on commit, even on CI ought to be a fraction of a second.


> The plugin will respect your tailwind.config.js file and work with any Tailwind plugins you’ve installed, but _there is no way to change the sort order_.

Really like that they don't give options to change the settings. Just one less thing to bike shed within teams. Really doesn't matter what is picked, just as long as it is consistent (and not obviously stupid).


I've seen this "options mean people don't bikeshed" argument made about gofmt.

The ‘original’ quote, from someone explaining why gofmt has no configuration options is:

> The usual saying is that gofmt isn’t anybody’s preferred style, but it’s adequate for everybody.

And the interpretation from someone asking about configuring some aspect of it is (emphasis mine):

> The usual saying is that gofmt isn’t anybody’s preferred style, but it’s adequate for everybody who still using it

Being opinionated about defaults is often a positive thing. Removing any options just makes your tool less useful.


This actually has a semantic purpose, it's not just about bike shedding. CSS classes, if applied to the same element, will prefer the class that's defined later in the CSS file. The plugin sorts them via priority order so it's more clear is one tag might override another.


Interesting idea. I’ve seen people get very confused by thinking that adding them in a certain order to the element would give some sort of control.

Which order do they do it in? Later classes are later in the css so more likely to be applied?


Yes, the specificity/precedence is all determined statically from only the .css files, the class order has nothing to do with it. This is a good thing because it allows for methods like https://developer.mozilla.org/en-US/docs/Web/API/DOMTokenLis... to not need to concern themselves with insert positions.

https://developer.mozilla.org/en-US/docs/Web/CSS/Specificity

> If the competing selectors have the same values in all the three columns, the proximity rule comes into play, wherein the last declared style gets precedence.


Sorry, I meant what order does this is linter do it in?

I’m well aware of how css works, I’ve been here since we did table layouts with shims!


The order of the classes in the dom will match the order of the classes in the .css files


Why is less-than-obviously stupid consistency better than choice?


I used to work in a restaurant where the thing that held the knives was agnostic about which direction the blade faced. It's quite beneficial to know which direction the knife is facing when grabbing it, so we wanted to establish a standard. There was a lengthy discussion about which was better, we picked one, then we had to train the rest of the staff and remember to tell new hires. And people still forgot, so having a standard was pointless.

If the knife storage had been opinionated, we would have expended no effort and achieved consistency. The choice of direction was essentially arbitrary, but making a choice and sticking to it was valuable.


Given it's Prettier's whole philosophy, best to read from them directly:

- https://prettier.io/docs/en/why-prettier - https://prettier.io/docs/en/option-philosophy


Prettier makes some obviously stupid choices though. That coupled with their disregard for their users is why I don’t use it.

I switched to Rome (now Biome) after this debacle: https://github.com/prettier/prettier/issues/840


Whether they do make obviously stupid choices or not doesn't invalidate the principle.

As to whether they do make obviously stupid choices - I personally don't mind any of their choices (even if I wouldn't have made the same choice myself), and I know I'm not alone in this position, which means that by definition they're not "obviously" stupid. You can disagree with the choices and the trade-offs, sure, that doesn't make it obviously stupid.


So many lives have already been lost in the tabs vs spaces debate, do we want to start this conversation again?


I detailed the reasons at length in the issue thread. It might not be obvious if you haven’t seen the code examples, but once you see it, it’s pretty clear.

I also completely disagree with your reasoning above.

The fact that many people believe or do some thing does not mean that “by definition” that that thing is not obviously stupid. E.g., inhaling glue, smashing things with one’s head, “the secret”, mukbang videos… the list is nearly endless.

Finally, “the principle” behind Prettier is also flawed when taken to the extreme they do. Paraphrasing my final comment on the github issue,

> It can be used to defend literally any styling choices, even ones that deliberately misaligned conditional branches with others at its logical level (much like prettier already is doing on a small scale in the example I referenced).

> Yes human beings are adaptable, but some things are easier to adapt to than others. It's objectively easier to spell Spanish than English, for example. It pays off to have consistency at a deeper level than simply making the same idiosyncratic choices each time an identical situation comes up.


Tienes razon sobre el asunto de que uno puede escribir palabras mas facil en otras lenguas. Pero lo importante en este caso es que la gente encuentran lo que esperan. Si la mayoria de la gente buscan `} else {` sera mejor darles lo que esperan. Posiblemente una investigacion cientifica podia descubrir que `else {` seria mejor para los que ya no se acostumbraron a `} else {`, pero estamos en un mundo lleno de gente que ya se acostumbraron. Pues `} else {` sirve bien, lo mismo que sirve bien usar una lengua familiar aunque otra lengua tiene ventajas.


Translation: You're right on the point that one can spell words more easily in other languages. But the important thing in this case is that people find what they expect. If the majority are looking for `} else {` it's better to give them what they expect. It's possible that a scientific investigation might find that `else {` would be better for those who haven't yet become accustomed to `} else {`, but we're in a world full of people who've already become so accustomed. So `} else {` still works better, just as it works better to use a familiar language even though another language has advantages.


This confuses choosing a more phonetic option among multiple competing options with changing to a completely different language.


"Multiple competing options" ignores that there's a prevalent style already.

https://github.com/prettier/prettier/issues/840#issuecomment...

Consistency has more value than the subjective advantage of the proposal that you're comparing to the objective advantage of being phonetic. I think the prettier maintainers made the right choice.


There are multiple prevalent styles. The emoji counts on the issue thread you linked to and the number of essentially duplicates make that very clear.


Developer: Makes software with a unique value proposition of "there are no configurations, it is what it is".

Random user: Your software is unacceptable; add an option to my favorite subjective preference!

I wonder, are those people trolling?


People were trying to get the broken behavior fixed. I was more in the camp of simply removing the offending rule. But, contrary to your claim above, they did already have some config options.

Ultimately, the solution is to use Biome or another formatter instead, but many devs have Prettier forced on them at work.


Broken is subjective for this case. Some people like choice A and others want B - neither is broken.


Oh, for sure. If you don't want to live with the decisions from the project whose goal is not letting you make your own decisions, you should use something with a different goal. There is a reason most of those projects grow a bit and then die.

What you don't do is insist the developer adds the option. Even if you feel like the developer is more approachable than your boss.


In the hundreds of people who interacted on that thread, I don’t think a single person insisted that the dev do anything.

It’s a dishonest characterization of the issue thread to imply that it was its nature. People shared discussed the problem with the tool’s behavior, shared examples and motivations.

Prettier’s (IMO wrong) decision was theirs to make but the response was also gratuitously smug.


Because otherwise you spend too much time arguing about not-so-important matters (in a word: bikeshed - you end up bikeshedding less).


Because it saves time and sanity. First, you don't have to deal with endless debates about stupid crap every other code review. Second, local wanna be controlling personalities have less space to nitpick choices of others and other do not have to deal with them.


People bikeshed given choices. When people have one choice, they get onto writing code that actually matters.


The more realistic outcome is they get onto bikeshedding other choices like pickigng a more configurable tool since, you know, you haven't actually eliminated choices, just reduced them without constraining: infinity - 1 = infinity


Didn't happen in the ~dozen team I worked with, so I wouldn't say it's the "more realistic outcome"


People who can’t help but bikeshed will consistently find themselves surrounded by bikeshedding


Very true. Tools are often abandoned for being too restrictive and I’ve seen it several times just with formatters alone.


"not obviously stupid" is entirely subjective. I think the way prettier handles parentheses in JS is very obviously stupid, for example.


Just curious, which rule is that? This is the only one I could see about parentheses - https://prettier.io/docs/en/options.html#arrow-function-pare...


Prettier removes any parentheses that aren't strictly necessary. So if you type:

  value = (a ? ((a * b) + c) : d);
It turns into:

  value = a ? a * b + c : d;
This is just a very basic example, there are many situations where the result is way worse. I feel pretty confident in saying that this is quite obviously stupid.


Does anyone know if it's possible to get Tailwind class sorting in Elixir Phoenix HEEX templates. It would be a great addition to the Elixir formatter.

Maybe we could write a formatter plugin in Elixir that does the same thing if this one isn't usable directly.



Thanks! I'll try it out soon. Looks exactly what I wanted, including the feature to order variants automatically (`dark:sm:... -> sm:dark:...` from the repo's readme).


In a similar vein, you can sort imports with Prettier using Trivago’s plugin.

https://github.com/trivago/prettier-plugin-sort-imports


This is amazing, thank you!


This blog post is from 2022.


that's 120 JavaScript years ago!


You’re joking, but I know some projects moving to Biomejs, because Prettier is now outdated (I don’t really write JavaScript, so I have no idea).


I do work in JavaScript, but I also had no idea what Biome was. Apparently the Rome project rebranded. The main appeal, I think, is that it is written in native code and significantly faster than Prettier.


I had learned of both Biome and Rome, but didn’t know about the rebrand. Makes me think they’ll switch gears to focus on improving the linter after reaching 100% parity.


I'd love to give Biome a try, but it's currently lacking OP's submission of sorting Tailwind classes.

https://github.com/biomejs/biome/discussions/164


A contributor is currently working on this feature [0] We are currently discussing which options to add to the rule on the Discord of Biome. We expect to ship the feature with the next release (on February). A nightly will be released earlier to gather feedback.

[0] https://github.com/biomejs/biome/pull/1362


That's great to hear, thanks!


Let's add another step in our toolchain & deployment bundle.

It saddens me to see people new to web development don't realize that to deploy a webpage, all it takes is just uploading (SFTP) a single .html file onto a web server.

Nothing more is technically required than that, but we've made it so complex you'd never know.


Deployment can be as easy and as complicated as you like it. Nobody took away an option to upload a single html file via SFTP.


Heck, plenty of websites today run directly out of S3.


Sure, we can simplify it as such....

Deploy it to what? How? Via what? Who is managing it? Who is paying for it? Who physically installed the server, and setup your ability to DrawTheRestOfTheHTML?

Personally - while we want abstraction in our deployment understandings to smooth ramp understanding - its important to see all the supporting inputs that made your SFTP of an .html possible.

>>I once saw him teach a philosophy lesson about a pencil. A Fuckin' Pencil!

https://www.youtube.com/watch?v=67tHtpac5ws


All it takes to get somewhere is to walk there, and yet we've dreamed up all these complicated machines that get us there even faster.


> all it takes is just uploading (SFTP) a single .html file onto a web server

Yes, it's unfortunate that new developers don't know the basics. However, that's not an option for a multi-page site with complex user interactions.

There's no point in complaining about new tools being created which serve a need. If it makes someone's job easier when they're creating complex web apps, it's a good thing.


> any classes in the base layer will be sorted first, followed by classes in the components layer, and then finally classes in the utilities layer

I guess you can get away with that because a tool can follow those rules.

But man, I <3 alpha sort.


It follows the order the classes are written in the css so it makes understanding how the css is applied easier. It’s not just an arbitrary ordering


That's how you get very-important layout classes (hidden, flex, etc) put arbitrarily in the middle of purely-visual ones (border, etc.). I've seen this in practice, and it makes grokking exiting code a massive pain.

But then I'm so old school I prefer just putting the CSS in the CSS, or even the `style` attribute. (I must say I do appreciate the pseudo-class support in tailwind.)


But then if I'm looking for "xyz" in a list of a dozen classes, I can easily find whether it exists.


Both MDN and the W3C complain about Prettier putting closing slashes on HTML tags such as <input />. While allowed due to backward compatibility to XHTML, they have never been specified, do nothing, and browsers ignore them so it is pointless to put them there.

https://github.com/validator/validator/wiki/Markup-%C2%BB-Vo...

https://github.com/orgs/mdn/discussions/242


> While allowed due to backward compatibility to XHTML, they have never been specified, do nothing, and browsers ignore them so it is pointless to put them there.

What do you mean by "never been specified"? They are in the spec: https://www.w3.org/html/wg/spec/syntax.html#start-tags

> Then, if the element is one of the void elements, or if the element is a foreign element, then there may be a single U+002F SOLIDUS character (/). This character has no effect on void elements, but on foreign elements it marks the start tag as self-closing.


You are looking at what I said. What you are quoting says it's allowed, and it "has no effect", but if you look at the actual element specification[1], it never says to use it. In fact, it says nothing at all about it.

[1] https://html.spec.whatwg.org/dev/input.html#the-input-elemen...

You will never find any HTML specification which will tell you a closing slash is required or that it has any meaning or does anything at all.


It very clearly says it has no effect on void elements, and then directly follows up with describing the effect it does have.

And the link you provided is specifically for the input tag, which has nothing to do with the syntax definition in general. Why would they repeat a generally applicable rule in more specific sections?


I added some links to my original post that you need to read. That the specification for the input element--and ALL HTML elements--does not state to use a closing slash should mean something or at least indicate something. If it's required or has meaning you would think the specification would show that. It doesn't. It never has.

You also need to read up on what a foreign element actually is and it's not HTML.


Your point is still unclear there. The specification allows it, for historical reasons. The fact it doesn’t recommend it does not change that.

Many people, myself included, prefer to have code that is easily parseable (both mentally and by a program) without requiring a lookahead or awareness of a list of special elements. A slash for self-closing elements achieves that. It just makes sense. Can you imagine JSX allowing this?


In order to put a slash there, you need to already know that tag can take a slash, so nothing is gained by putting it there.

Though something is allowed, it is unspecified, not required, does nothing. So why would you want to write markup that is not needed and does nothing? This makes no sense whatsoever and I only find such discussions on public forums such as this one.


This is about readability. The point is that only if you _don't_ have an ending slash, you need to know the tag type. If there is one, you don't need to know anything to understand the tree structure, the code is self-evident.

Do you add quotes to your single-word attribute values? Why? They are also unnecessary following the spec: https://html.spec.whatwg.org/#unquoted

Do you omit the opening html tag because it's optional? https://html.spec.whatwg.org/#optional-tags

Do you write unclosed <dd> tags? Do you close your paragraph elements?

The spec allows a lot of questionable styles, your argument that because something is not required it is superfluous doesn't hold any water.


Your use of the word superfluous is exactly what I'm saying. Why you want to write unnecessary, useless markup is beyond me. Even MDN and the W3C complain about it but that seems to mean nothing to you but I can tell when I can't teach someone values so I'm done here.


I see in your profile you've joined HN just a year ago. Welcome! I feel the need to point out that this is not a place to "teach someone values" though, but to have meaningful conversation. There doesn't have to be a winner.

The comments section of the guidelines offers some good rules of thumb: https://news.ycombinator.com/newsguidelines.html


[flagged]


You are repeating what has already been stated and explained. Throwing insults doesn't change what's already been written.


And you're still not understanding what's written there.


It is not pointless just because browsers ignore them. It’s there for humans reading the markup.


No. It's not there at all. And that's the point. No one ever told anyone to put one there.


React popularized it, and in its context having self-closing tags on React elements to indicate leaf nodes makes a lot of sense. Prettier just went with that and also does it for HTML.

I'm wondering why you are so triggered by that issue that you have to bring it up in a context where its off-topic (it could be brought up on any post related to Prettier).

The validator Wiki page even highlights that it's essentially a non-issue, except for interactions with unquoted attributes, which Prettier also converts to quoted attributes, so that interaction never happens. The other reason is for "teaching the wrong" mental model, which I guess is fair from the position of MDN, but Prettier was never designed as a "teaching formatter".

And if you, even with all that context want to opt-out of that formatting, there is a community-maintained plugin that adjusts the formatting to how you want it: https://github.com/awmottaz/prettier-plugin-void-html


> it's essentially a non-issue, except for...

Hope you never get tripped up by the "except for".

People were mixing XML and XHTML with HTML before React and got themselves into trouble.

Why are you so triggered by someone who thinks people should just follow the standard and not write unnecessary markup/code? That is a programmer's worst nightmare but people here seem to support it.


Sorry, what does this have to do with the article?




Guidelines | FAQ | Lists | API | Security | Legal | Apply to YC | Contact

Search: