DEV Community

Cover image for My opinion about opinionated Prettier: 👎
shaman-apprentice
shaman-apprentice

Posted on • Edited on

My opinion about opinionated Prettier: 👎

Let's first remember, that there is not only black and white. Like almost everything, Prettier comes with pros and cons. If it's a good or bad trade-off depends on you and your environment.

This blog post has the following structure:

  • Gains I see
  • Costs I see
  • Return on investment I see (only blurry)
  • My conclusion

Gains I see

  • Consistent, well formatted code is easier to read.
  • Consistent formatting reduces diffs in pull requests, speeding them up.
  • Creating a custom formatting style guide in your team is an investment of time. Even worse, it can lead to personal frustration when your preferred style gets rejected. Different custom style guides in different teams are annoying. When you use Prettier, you don't have to invest any time, as Prettier enforces its style. Formatting will be the same for every team. Furthermore, personal frustration should be reduced, as you get overruled by a library with a huge community.
  • Prettier can be your one solution for formatting all your web stack (.ts, .html, .css, .json, ...).
  • Every formatting violation can be automatically fixed by Prettier.

Costs I see

  • Prettier enforces rules without mercy and common sense. Sometimes, it makes formatting worse for me. For example, the following snippet is kept by Prettier:

    ngOnInit(): void {
      fromEvent(document, "click").pipe(
        scan((count) => count + 1, 0),
        filter((count) => this.magicDocument.isMagicNumber(count)),
        tap((count) => this.magicDocument.pullBlueMagicRabbitOutOfTheHat(count)),
      );
    }
    

    But when I subscribe, it gets formatted to:

    ngOnInit(): void {
      fromEvent(document, "click")
        .pipe(
          scan((count) => count + 1, 0),
          filter((count) => this.magicDocument.isMagicNumber(count)),
          tap((count) =>
            this.magicDocument.pullBlueMagicRabbitOutOfTheHat(count),
          ),
        )
        .subscribe();
    }
    

    Why is the pipe now on its own line, giving every operator within an extra level of indentation? Is it really an improvement, that the max line length is honored, but now, the tap has a different horizontal and vertical alignment than the other operators? No matter what the answers to those questions are, it's not helpful, that Prettier forces me to switch the formatting depending on the existence of the subscription in the last line.

    Or let's look at the following two snippets formatted with Prettier:

    <section class="user-container">
      <section class="...">...</section>
    
      <section class="user-privacy-settings">
        @for (privacySetting of privacySettings; track privacySetting.identifier) {
          <div>...</div>
        }
      </section>
    </section>
    

    and

    <section class="user-container">
      <section class="...">...</section>
    
      @if (user.isAuthenticated) {
        <section class="user-privacy-settings">
          @for (
            privacySetting of privacySettings;
            track privacySetting.identifier
          ) {
            <div>...</div>
          }
        </section>
      }
    </section>
    

    Because I decided to only show the privacy settings, when the user is authenticated, the for loop now spans 4 lines. I find the one-liner easier to read, although it is one character over the max line length.

    Of course, you might argue, that I should refactor the code anyway. So, Prettier puts pressure on me when to refactor and when to go quick and dirty. Which might be a good or a bad thing depending on context, in my opinion.

  • Prettier is a further tool in your toolchain. Every used tool has a risk of impacting your development. For example,

    • when I wanted to use Angular's new template syntax, I was initially blocked by Prettier, as it formatted the new syntax horribly.
    • the technical decision how Svelte should treat self-closing html elements was hindered by Prettier:

      Ideally we would also disallow self-closing void elements (i.e. rather than ), but whether or not this is realistic depends on whether Prettier's current habit of adding an unnecessary /> to void elements prevents us from doing that.

    • From my point of view, Prettier doesn't work well for styling with utility classes. For a discussion see Prettier#7863 or Prettier#5948.

Return on investment I see (only blurry)

How much time and energy can be saved by good formatting? How much time and energy do you have to invest for the savings?

I think the gains are pretty low. That spacing, quotes, etc. are formatted uniformly is nice. But the extra complexity added by non-uniform formatting for reading code or pull requests is marginal.

The costs are also pretty low. A tool like Prettier is performant enough to run every time you save a file. When you manually honor the formatting, the time is negligible compared to your overall working time. The only risk I see is, that you might burn emotional energy for potential marginal savings with discussions about something like single or doubled quotes.

My conclusion

When a project has already decided to use Prettier, I wouldn't rebel against it. I think the potential gain from reopening the topic isn't worth the energy used for the discussion.

But when I have free choice, I will not use Prettier. I claim, that I can do a better job with formatting code to be well readable than Prettier. At the latest when a technical decision is influenced by Prettier, I am convinced that freedom in any technical choice is more valuable than the advantages of Prettier.

Currently, I am using ESLint for formatting of basic things like spacing and quotes. However, those rules were deprecated with v8.53.0 and moved to @stylistic/eslint-plugin. But they recommend Prettier or dprint.

I am curious for new best practices. All trade-offs might change over time with new tools, new experiences and inputs from following developers. So please share your thoughts in the comments.

Top comments (1)

Collapse
 
hybrideyegrillage profile image
HybridEyeGrillage

If using eslint, I'd recommend using @antfu/eslint-config with the flatConfig setup. It will incorporate all of the various eslibt packages, but still give you control over the settings and what you want to have included. Anthony does have it set to his own preferences, but you can easily overwrite them.
I've started using it and never looked back.