Maintaining code formatting and quality automatically on your front-end projects using Prettier, ES/TSLint and StyleLint

At work, I've spun up a handful of React projects that have a number of engineers working on it (onshore and offshore). When reviewing code, I'm very particular about how code is formatted and it's quality. This is probably an artifact of me always using formatters and linters in my projects, so it's become a personal standard of mine to make sure these things are done correctly.

While reviewing pull requests, I find myself sometimes pointing out code formatting (inconsistent spacing, incorrect indentation, etc) and quality issues (using any, using var etc). I try to avoid doing so as I don't think it should be part of the code review - everyone knows how frustrating it is to have formatting issues pointed out.  So I began thinking of ways that I could encourage adherence to formatting/quality standards without having to point them out or fix them myself. The answer was to automatically enforce (not just recommend) by using a collection of formatters/linters.

Prettier

My absolute favourite code formatter is Prettier! I've used Prettier on every single JavaScript project I've created at home and at work. It's an opinionated code formatter who's opinion I happen to strongly agree with. It formats all code very clean, easy to read format. To start off with I just used the Prettier VSCode extension which I could just run over code that I'm working on. Sometimes I forgot to run it so I then move onto adding it to run on file save, and added a script to run over all my files in package.json.

From their website, Prettier is described as:

Prettier is an opinionated code formatter. It enforces a consistent style by parsing your code and re-printing it with its own rules that take the maximum line length into account, wrapping code when necessary.

It has support for JavaScript, JSX, Angular, Vue, Flow, TypeScript, CSS, Less, and SCSS, HTML, JSON, GraphQL, Markdown and YAML.

Installation and configuration

Installing Prettier is simple, run:

npm i --D prettier

There are a number of formatting rules that Prettier provides, I'm a fan of just using the default ruleset. However, I still think it's handy to have a Prettier config file just to make sure everyone is using the same Prettier config and in case new formatting rules need to be added. Create prettierrc.json file then place the following in it:

{
  "trailingComma": "es5",
  "tabWidth": 4,
  "semi": false,
  "singleQuote": true
}

I would recommend installing the Prettier VSCode extension so you can see formatting errors in real-time.

Now we have to add an NPM script to run Prettier over all of our files and a script that runs a check over our files. In package.json add:

"prettier": "prettier --write src/**/*.{js,tsx,scss}"
"prettier:check": "prettier --list-different src/**/*.{js,tsx,scss}"

Make sure to update these scripts to run on files types that you're using in your project. I use prettier:check in the pre-commit hook (to be discussed later) and have the prettier option to just allow people to run Prettier over all their code and do it's magic.

ES/TSLint

For a majority of my projects I use TSLint by Palantir. However, I would use ESLint for linting any JavaScript I write. TSLint is described as:

TSLint is an extensible static analysis tool that checks TypeScript code for readability, maintainability, and functionality errors. It is widely supported across modern editors & build systems and can be customized with your own lint rules, configurations, and formatters.

TSLint can be used as a code formatter, but I prefer using Prettier for that. We will only be enabling rules that pertain to code quality issues. Examples of these issues might be that the any type is being used, a console.log is present or using let when const should be used.

Installation and configuration

Install TSLint by running:

npm i -D tslint

Then create a tslint.json file and place the following config inside:

{
  "defaultSeverity": "error",
  "extends": ["tslint:recommended"],
  "jsRules": {},
  "rules": {
    "object-literal-sort-keys": false,
    "ordered-imports": false,
    "quotemark": [true, "single", "jsx-double"],
    "trailing-comma": false,
    "semicolon": [true, "always", "ignore-bound-class-methods"],
    "arrow-parens": [true, "ban-single-arg-parens"],
    "interface-over-type-literal": false
  },
  "rulesDirectory": []
}

Obviously feel free to add/remove rules as you prefer, but make sure that the rules here don't conflict with Prettier, for example, the quotemark rule by default wants double, whereas we've configured Prettier to use single quotemark.

We also need to introduce an NPM script to run TSLint over all our files, in package.json scripts add:

"tslint:check": "tslint -c tslint.json 'src/**/*.{ts,tsx}'"

I would also recommend installing the TSLint VSCode extension, again, to see linting errors in real-time.

StyleLint

I'm a huge fan of using CSS preprocessors like Sass over CSS (I just cannot live without nesting) and I was using SassLint for all my linting needs. SassLint worked fine, but I wanted to use a more generic style linter that could be used across multiple stylesheet type. A bit of research lead me to StyleLint. I haven't looked back since.

It has support for SCSS, Sass, Less and SugarSS. It's described as being:

A mighty, modern linter that helps you avoid errors and enforce conventions in your styles.

StyleLint provides hundreds of options that you can configure it with. It also has a number of great "base" rule-sets that you can simply install from NPM, add one line in package.json and have everything just work. For example, there are base rule-sets for CSS, SCSS and LESS. It's also super easy to extend and override these rule-sets.

Installation and configuration

We'll just be configuring StyleLint for css. Install StyleLint using:

npm i -D stylelint

The easiest way to get up and running with StyleLint is to extend the basic CSS rule-set. This requires an additional install:

npm i -D stylelint-config-recommended

Now create a .stylelintrc.json and in it place:

{
  "extends": "stylelint-config-recommended"
}

You can read all the basic rules provided by this here. You can also easily extend/override rules by adding a rules key like:

{
  "extends": "stylelint-config-recommended",
  "rules": {
    "at-rule-no-unknown": [ true, {
      "ignoreAtRules": [
        "extends"
      ]
    }],
    "block-no-empty": null,
    "unit-whitelist": ["em", "rem", "s"]
  }
}

Again, StyleLint has a VSCode extension I recommend installing. Now let's add a package.json script:

"stylelint:check": "stylelint \"src/**/*.css\"",

Pre-commit hooks

With Prettier, ES/TSLint and StyleLint installed and configured, we just need a way to enforce these have been run before the pull request is created!

An excellent NPM library that was recommended to me by a co-worker is called pre-commit. pre-commit allows you to run an NPM script before a git commit is performed. When this script is run and an error is thrown, the commit won't occur. This is incredibly useful and I've utilised it to enforce the engineer has run Prettier, Es/TsLint and StyleLint before submitting their code for review.

To get it working we first have to install it:

npm i -D pre-commit

Before we use pre-commit, create a new package.json script:

"lint-all": "npm run prettier:check && npm run tslint:check && npm run stylelint:check"

This script will run all of our formatters/linters sequentially and output any errors. This is the script we will get pre-commit to run.

In package.json add:

  "pre-commit": [
    "lint-all"
  ],

Now, anytime a git commit is run, Prettier, TSlint and StyleLint will all be run over your code. If there are any errors from them, the commit will fail and the errors will be output. Only once all errors are resolved will the commit work.

Hope this article helps you maintain your front-end project's code quality + formatting without having to point these our in pull requests!