Make your source code up

At Puzzle we recommend to use Prettier for frontend projects. Learn why and how we suggest to our engineers to use the opinionated code formatter. (German version)

Why Prettier?

Prettier is a MIT licensed source code formatter that became very popular in the frontend ecosystem. Why not use the formatting feature of your favorite IDE you may ask? Well, there are a couple of reasons:

  • Prettier is opinionated with only a few configuration options to adjust the resulting style. The community is pretty keen on resisting to add new options — the whole idea is to stop all on-going debates over styles and free up resources that can be used to deliver features to your customers. If you’re interested, you can read about the reasons for every choice in the Rationale documentation chapter.
  • It is a CLI tool. That makes it possible to use it apart from the IDE, e.g. to integrate it into your SCM/CI workflow.
  • It is editor independent, with support for the most editors/IDEs.
  • It formats many languages, with built-in support for JavaScript, TypeScript, JSON, CSS, SCSS, HTML, Angular Templates, JSX, Markdown and even more through its plugin ecosystem.
  • It produces a consistent output.

Beyond JavaScript

What startet as a “JavaScript pretty printer” became a versatile code formatter for a variety of languages in the last couple of months. Due to Prettier’s growing plugin ecosystem there is now support for Java, Ruby, Python, PHP, ELM, Swift and more.

Interestingly, as stated by the author of the Ruby plugin, Prettier’s plugin API seems to be well-engineered:

The Ruby plugin folks are also working on a Gem providing a standalone binary for Prettier (using zeit/pkg) which doesn’t even require Ruby developers to install Node to use Prettier in their projects.

Things like these might help to establish Prettier as the code formatter of choice for all kinds of languages.

Best practices

We recommend to use Prettier in three phases:

  1. Integration in the editor by formatting on file save.
  2. Integration in the SCM by formatting on commit (Git pre-commit hook).
  3. Integration in the CI pipeline by using a linting step that fails if a file is not properly formatted.

Furthermore, consider the following aspects: 

  • Always use a project-local version of Prettier, don’t install it globally. It is important that all developers/systems use the same Prettier version as the style may differ from version to version.
  • For the same reason, you must pin a particular Prettier version in your package.json (i.e. "prettier": "1.16.4" not "prettier": "^1.16.4") and perform Prettier updates manually, reformatting the whole code base afterwards (see section Migration).
  • Finally, disable all style linting (e.g. with ESLint/TSLint), as this is needless and may conflict with Prettier.

Setup

In the following sections I’m going to show in detail how to configure Prettier according to the above best practices.

Installation & configuration

Add Prettier to your project, pinned to an exact version:

yarn add prettier --dev --exact
# or
npm install --save-dev --save-exact prettier

Remark: to be able to use the project-local CLI tool in the terminal, make sure you have ./node_modules/.bin in your PATH.

If you prefer a custom configuration, you may add a .prettierrc file. We use single quotes for JavaScript/TypeScript files and Angular templates:

{
  "overrides": [
    {
      "files": "*.{js,ts,component.html}",
      "options": {
        "singleQuote": true
      }
    }
  ]
}

Per default, Prettier ignores the node_modules directory. You can exclude more directories/files in a .prettierignore file, e.g.:

coverage-html-report/
dist/
vendor/

Migration

As previously mentioned, you should always pin Prettier to a specific version and update it manually. To update Prettier, execute:

yarn upgrade --exact prettier@latest
# or
npm install --save-exact prettier@latest

After each update or when adding Prettier to an existing project, you have to format the complete code base. As a convenience, we recommend to add a task to your package.json:

{
  "scripts": {
    "format": "prettier --write \"./**/*.{js,ts,json,css,scss,html,md,yaml}\""
  }
}

With this script, the following is all it takes to reformat your project’s code base:

yarn format
# or
npm run format

git commit -a -m "Reformat sources after Prettier update"

Bye bye style linting

With the use of Prettier, linting code style with ESLint or TSLint is superfluous and can be disabled. Luckily, the official packages eslint-config-prettier and tslint-config-prettier help us doing this. First, install the package (we do this for TSLint in this example):

yarn add --dev tslint-config-prettier
# or
npm install --save-dev tslint-config-prettier

Then, in the TSLint configuration file (tslint.json), you can override the style rules by adding the Prettier rule set at the end (this is important!) of the extended rule sets:

{
  "extends": [
    "tslint:recommended",
    "codelyzer",
    "tslint-config-prettier"
  ]
}

Any rules directly configured in the TSLint configuration file under "rules", must be removed as well. The config packages provide a neat tool to list the affected rules:

tslint-config-prettier-check ./tslint.json
# or
eslint --print-config . | eslint-config-prettier-check

Editor integration

There are Prettier-integrations for most editors to format the code on save or with a keyboard shortcut: Emacs, VIM, Visual Studio Code, Atom, Sublime Text, JetBrains IntelliJ and Visual Studio.

Check out the Editor Integration page for editor-specific instructions.

Pre-commit hook

We recommend to configure the Git pre-commit hook with Husky and lint-staged. For this, you need to install these two packages:

yarn add lint-staged husky --dev
# or
npm install --save-dev lint-staged husky

And add the following configuration to your package.json:

"husky": {
     "hooks": {
         "pre-commit": "lint-staged"
     }
},
"lint-staged": {
  "./**/*.{js,ts,json,css,scss,html,md,yaml}": [
    "prettier --write",
    "git add"
  ]
}

Now the source code is being formatted when committed, even if the editor integration is not configured or somehow not working.

To also execute ESLint/TSLint infront of the formatting task, you may extend your configuration:

"lint-staged": {
  "linters": {
    "./src/**/*.ts": [
      "tslint",
      "prettier --write",
      "git add"
    ],
    "./**/*.{js,json,css,scss,html,md,yaml}": [
      "prettier --write",
      "git add"
    ]
  }
}

Prettier linting step in CI

As last resort, we recommend to add a linting step to your CI pipeline, if the pre-commit hook is not installed or not working properly. Here also you can make use of the official packages eslint-plugin-prettier and tslint-plugin-prettier (in this example using TSLint):

npm install --save-dev tslint-plugin-prettier
# or
yarn add --dev tslint-plugin-prettier

Create a separate TSLint configuration file (tslint-prettier.json), that exclusively does style linting:

{
  "extends": ["tslint-plugin-prettier"],
  "rules": {
    "prettier": true
  }
}

Having two separate configurations allows to not perform style linting locally and also makes it possible to run the linter in the pre-commit hook before Prettier.

Assuming you already have a lint task in your package.json, add another task, that uses the above configuration:

{
  "scripts": {
    "lint": "tslint \"src/**/*.ts\" -e \"src/**/*.spec.ts\"",
    "lint:format": "tslint -c tslint-prettier.json \"src/**/*.ts\""
  }
}

Then use this task in your CI pipeline:

yarn lint:format
# or
npm run lint:format

Note that this only checks JavaScript/TypeScript files.

Conclusion

I hope I was able to convince you to start using Prettier and illustrate our best practices. There is one important warning to make: once you’ve started using Prettier, there is no going back! 🤩

HappyPretty hacking!

Image: Creative Commons CC0 Public Domain, Source

Comments are closed here.