Prettier Function Parenthesis Spacing – Opinionated is Key

Intro

As I progress as a developer, I’ve tried to embrace code formatting tools more and more frequently. That hasn’t stopped my frustrations with them however, and I wanted to provide a short example from a very recent frustrating day that reminded me of their limitations.

The Issue

I had an existing codebase that was poorly formatted (🙃), so I was planning on using ESLint + Prettier (common combo) to clean it up, and enforce some standards going forward. Upon running Prettier, I noticed that it kept adding spaces between the function keyword and the argument parenthesis. For example (demo):

// Before ESLint + Prettier
const myFunc = function() {
    //...
}

// After formatting
const myFunc = function () {
    //...
}

For some reason it was bothering me, and, at least for this particular repo, I was hoping to be able to preserve my style of having no space before the parenthesis.

However, when I tried to go and actually change the formatting default, I ran into issues.

ESLint Rules

A quick search of my issue made it seem like this was because of a very specific ESLint rule: space-before-function-paren. Knowing this, I tried every variation I could think of to turn the rule off.

Examples:

// .eslintrc.json

// Standard approach
{
    "rules": {
        "space-before-function-paren": ["error", "never"]
    }
}

// Applying via plugin rule
{
    "rules": {
        "prettier": {
            "space-before-function-paren": ["error", "never"]
        }
    }
}

I also tried variations with “off”, etc.

Nothing seemed to work. This is because I rarely think about Prettier, and basically forgot the main premise of its functionality.

Prettier – An Opinionated Formatter

Here is a refresher on Prettier (or introduction, depending on your experience):

I’m going to paste two really important bullet points from the home page of Prettier, under the “What is Prettier?” section (emphasis mine):

  • An opinionated code formatter
  • Has few options

Basically, the main point of Prettier is to stop developers from wasting precious time fretting or arguing about formatting styles, hand-editing code to meet style requirements, and messing with complicated config steps. Using Prettier should be a quick set-and-forget step, and this is both its strength and its weakness.

The weakness is that there are very few ways to modify Prettiers’ options, and this rule is just one of many that you cannot override 🔒.

Space After Function – Prettier 2.0

I think part of why this issue might have stuck out to me is because, even though I’ve only used Prettier a handful of times in the past, I recognized that this was new behavior that I was not used to. Sure enough, after a bunch of digging, I found the exact discussions and PRs that brought this in as the new default style in Prettier.

This change was merged and released in the major 2.0 release, very recently in March 2020. You can find confirmation of this in the official release notes, here, or in the main merge PR, #3903.

🔎: For those interested, you can also find lively discussion on the decision on #1139, #3847, #3845.

Solution

Solution A: Don’t use Prettier:

This is harsh advice, but if you are the kind of person that cares strongly about this type of thing, enough to research how to override it, Prettier might not be for you. Again, the whole point of Prettier is to make those kinds of decisions for you, and they are strongly against exposing overrides as options, as that allows for more time wasted on manual configuration and bickering over how to set it up.

Plus, there are other auto-formatting options. For example, ESLint + AirBnB is a great common combination, where you get a bunch of common sense formatting defaults, but you can also configure the setup exactly how you like it using ESLint configs. In fact, just like how Prettier can auto-fix issues, so can ESLint.

Solution B: Force an Old Version of Prettier

Since this change was introduced with version 2.0 of Prettier, if you force your IDE to use an older version of Prettier, prior to the v2.0 release, you shouldn’t see this behavior. There are multiple ways to do this, but the easiest and most recommended way is to “pin” the version in your local package.json file.

For more details, assuming VSCode as your environment, refer to this documentation for “Prettier Resolution” in prettier-vscode.

Warning: Solution B is not recommended as a long term solution, since you will be missing out future (and post-2.0) performance improvements, added features, and security patches.

Solution C: Let ESLint override Prettier

Part of the reason why my attempts at overriding Prettier’s default with ESLint’s rule (space-before-function-paren) did not work, is because I was following Prettier’s recommended setup for ESLint, which includes telling ESLint to disable rules that conflict with Prettier. I’m guessing one of those “conflicting” rules is the space in function declarations (particularly anonymous function declarations).

This brings me to my second solution; let ESLint override Prettier.

This is pretty convoluted, and I’m not even 100% sure it would work, but I figured I would outline the steps anyways

First, you would need to stop telling ESLint to drop rules that conflict / override Prettier. For example, going from this (in .eslintrc.json):

{
    "extends": ["airbnb-base","plugin:prettier/recommended"],
    "rules": {
        //...
    }
}

…. to this:

{
    "extends": ["airbnb-base"],
    "rules": {
        //...
    }
}

Next, you would need to setup your formatting workflow to call Prettier first (e.g., prettier --write .), to apply it’s opinionated styles, and then call ESLint’s formatter (e.g., eslint --fix). You could do this with chained command line commands, or, if you are using VSCode, via extensions and some custom tasks or something like that.

Solution B is not recommended, and is mostly included as an additional way to illustrate how ESLint and Prettier interact

This is the recommended ESLint extension for VSCode, which includes a built-in formatter

Wrap Up

Hope this helps someone! Feel free to leave a comment if you found an additional workaround or have any feedback to share!

Leave a Reply

Your email address will not be published. Required fields are marked *