logologo

Why I don't use Prettier

Oct 1 · 12min

中文 Chinese Version

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:

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 formating - 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:

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-config

It turns out, the setup configuration can also be very minimal:

npm i -D @antfu/eslint-config
npm i -D @antfu/eslint-config
// .eslintrc
{
  "extends": "@antfu"
}
// .eslintrc
{
  "extends": "@antfu"
}

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. Oh, of course, it’s also very opinionated towards my needs. But maybe, it could be a good reference for you to create your own version.

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!

CC BY-NC-SA 4.0 2021-PRESENT © Anthony Fu