I have started writing this post multiple times but never ended up posting it. I wasn’t able to figure out a proper way to express my position about Prettier. But this time, I think I should try harder to explain that for future reference.
First of all, I am not against Prettier. Actually, I love it.
I Love Prettier #
Prettier is a great tool, and it saved me a lot of time. I appreciated the efforts of the maintainers and contributors to make it possible and formed a great foundation of how the clean code would look for the community. I have to confess that the title is a bit clickbait. I use Prettier a lot for interactive documentation and playgrounds, like VueUse and UnoCSS. I love it for the out-of-box support of a lot of languages. I could make the generated code pretty with less than 5 mins of integrating Prettier.
But, Why Not? #
If you have ever come across my open source projects, you might find that I rarely use Prettier to format the source code. In this post, I would try to explain the reason why I made this decision:
It’s Opinionated #
Prettier describes itself to be "an opinionated code formatter".
Opinionated essentially means it’s not for everyone. Prettier makes a lot of hard-coded decisions to provide a minimal configuration interface. That makes it very easy to use (it’s excellent!) and the code consistent across projects. However, on the other hand, it also means you are losing the ability to have fine-grained tweaks to how your code should look like.
While I love most of Prettier’s decisions, it sometimes makes you upset when you find something you don’t want and don’t have a workaround.
The Line Wrapping Noise #
The main thing that itches me a lot is the auto wrapping / unwrapping based on the length of the code. Prettier has the concept of printWidth
, which constrains each line to fit with a certain width (by default, it’s 80 characters). It’s generally great to have the code fitting in one screen and avoid horizontal scrolls.
However, I often found it hurting the readability and git diffing.
@patak_dev recently brought up an example of that in PR reviewing:
Formatters are awesome, especially when doing PR reviews. They also introduce issues though, for example when an addition triggers a line break. The diff isn't showing what changed here. It would be great if diff viewers would be Prettier-aware, counting line breaks as spacing. pic.twitter.com/ZuApmctllU
— patak (@patak_dev) September 30, 2022
Sometimes when you modify a string literal in JavaScript that may make the line a bit longer than the value of printwidth
, Prettier will force wrapping the line. It breaks the inline diffing and make the changes hard to review. Imagine in another pull request, we might reduce the string a bit shorter, Prettier will then unwrap the lines back to one line. Back and forth, it creates a lot of unnecessary noises.
The following image shows another example:
The 42 of printWidth
is made up for demonstration, but it happens in any printWidth
On the left is the input code and on the right is the output of Prettier. I don’t need to point out but you probably already have the answer of which one is "more pretty". From my point of view, Prettier follows the rule too strict. And in fact it makes the code much harder to read and modify, violating the initial goal of formatting - to make the code more readable.
The real pain point is that this behavior is not optional. You can’t disable it completely(#3468). Increasing the printWidth
only delays the circumstance and will affect other files that you didn’t touch. The only workaround you can do is to use // prettier-ignore
, which to me, the "all or nothing" choice loses the point of using Prettier in the first place.
Mess with ESLint #
Prettier as a code formatter, only cares about code styles but not the logic. Thus we see it’s quite common for projects to use ESLint along with Prettier to also check the logic. If you have ever configured that yourself, you might notice there are some functionality overlaps between them - ESLint can also lint for code styles. The common practice is to use eslint-config-prettier
to disable those overlaps rules in ESLint (there are also a few other solutions).
However, the approach creates quite a lot of mess to me:
My points here:
— Anthony Fu (@antfu7) July 3, 2020
1. Prettier Only is cool - It's out-of-box.
2. If you need to use ESLint, it can do the formatting as good as Prettier - and more configurable
3. Prettier + ESLint still needs a lot of configs - It doesn't make your life easier.
— Anthony Fu (@antfu7) July 3, 2020
4. You can have full control in ESLint but not in Prettier, mixing them together feels weird.
5. I don't think parsing two times can be faster (maybe I am wrong)
ESLint’s auto fix could also do the formatting just as well as Prettier - with much more freedom of choices.
Alternatives #
ESLint is essential to my workflow to ensure the code quality. If ESLint is already capable of doing formatting, the best solution for me is to use it in one go.
I spent some time configuring my ESLint and made it a config preset:
@antfu/eslint-configIt turns out, the setup configuration can also be very minimal:
npm i -D @antfu/eslint-config
// eslint.config.js
import antfu from '@antfu/eslint-config'
export default antfu({
// customizations
})
That’s all you need. With the IDE extensions, it’s also possible to trigger auto fixing on save. It works similarly to Prettier but respects your choices when to break the lines, with many best practices of linting. It’s also quite opinionated, but thanks to the new Flat Config, it gives you the full control of customizations over every single bit that you want to change. Moreover, you can always fork it to make your own versions.
Sidenote: You might hear so voicing saying "Don’t use ESLint for formatting" - here are some discussions and a response from the ESLint team, for you to make your own judgement.
Wrapping Up #
This post is only trying to explain my personal experience and opinions. Of course, you can have different views and don’t need to agree with me at all. I am not blaming Prettier for this. Different tools have different purposes and focuses, and there is no better or worse. It’s just about using the right tools for the right circumstances. I will still be a happy user of Prettier in usages that I don’t need the maximum customizability, and using ESLint exclusively for my projects’ source code.
Hope this could make myself clear and maybe give you some insights. Cheers!