JavaScript/TypeScript code formatting and linting with ESLint, Prettier, EditorConfig, husky and lint-staged

Sofija Zec-Baškarad
Undabot
Published in
15 min readNov 10, 2020

--

Summary

This article deals with the code formatting and linting setup using ESLint, Prettier and EditorConfig for Node, React, React Native and Vue, both for JavaScript and TypeScript. It covers the installations of required packages and ESLint, Prettier and EditorConfig configurations setup with explanations and, also, setting up pre-commit checks with husky and lint-staged.

Keywords: code formatting, ESLint, EditorConfig, Prettier, husky, lint-staged, JavaScript, TypeScript, Node, React, React Native, Vue, setup, linting, configuration

Introduction

Starting the development on a new project is very exciting but it is very important to think ahead and prevent possible problems that can arise along the way. For example, one of the possible problems when collaborating with others can be caused by different code styles and practices. Not only will the project code be inconsistent, there are also the risks of (merge and/or verbal) conflicts due to different styles when changing the same file, which is unnecessarily time consuming.

To make the collaborating easier, before a collaborative project, developers should discuss the code standards and rules they will follow and set up the project accordingly. Of course, you can modify the rules and configs during the project if your team agrees on making changes. Once the coding preferences are discussed, this article will try to help you set up the project so you don’t have these problems. Also, this article can be useful, even if you are alone on the project, because you’ll get the error warnings and nicely formatted and consistent code.

ESLint, Prettier and EditorConfig

It is possible that developers are using different code editors and follow different code practices and styles, and that is why this guide will cover three tools that will help bring the code linting, code formatting consistency and code editors in harmony — ESLint, Prettier and EditorConfig. You can learn more about why you should use all three in the Why You Should Use ESLint, Prettier & EditorConfig article.

ESLint

ESLint is a JavaScript linting utility. As described in the What are JavaScript linters? article:

Linters detect common programming errors and ensure that certain best practices are followed.

ESLint analyses your code to help you detect formatting issues and find code inconsistencies and it does that by parsing the source code into a data format called Abstract Syntax Tree (AST), which is used to check what your code should look like or how it should behave.

ESLint warning example
ESLint error example

You can find more about ESLint on their official website:

Prettier

Prettier is a code formatter, but it doesn’t check your code quality like ESLint. On the other hand, it does the formatting much better than ESLint.

Some of the reasons why you should use Prettier are mentioned here and summed with:

You press save and code is formatted. No need to discuss style in code review. Saves you time and energy.

Prettier’s formatting will be triggered after you have written the code — for example, on saving the content (if you run it from your editor), or from the command line. It is recommended to integrate Prettier with your editor:

Formatting from the command line is a good way to get started, but you get the most from Prettier by running it from your editor, either via a keyboard shortcut or automatically, whenever you save a file.

Prettier formatting example

You can find more about Prettier on their official website:

EditorConfig

EditorConfig defines code formatting among various editors and IDEs by overriding their configuration. As described on its official website:

EditorConfig helps maintain consistent coding styles for multiple developers working on the same project across various editors and IDEs.

This allows your team to share a basic code formatting style and it reduces the job Prettier does because the code is already formatted in a preconfigured way. While Prettier applies the formatting rules after the code is written, EditorConfig allows you to define the rules that will be applied while writing the code.

EditorConfig formatting example

You can find more about EditorConfig on their official website:

Setting up the project code formatting and linting

This section will cover the ESLint, Prettier and EditorConfig setups and configurations for Node, React, React Native and Vue, both for JavaScript and TypeScript.

A lot of editors can read the EditorConfig file format, some natively, some with a plugin. You can check if a plugin is necessary and available for your editor here. EditorConfig configuration will be located in the .editorconfig file.

ESLint and Prettier will be installed as dev dependencies and you can also install a Prettier extension for integrating it with your editor. For example, if you’re using the VSCode Editor, you can install the Prettier — Code formatter extension (esbenp.prettier-vscode). You can find out how to integrate Prettier with your editor here. Just make sure that it is set as the default formatter in your editor settings. ESLint configuration will be located in the .eslintrc file and Prettier configuration will be located in the .prettierrc file.

Based on the technology used in your project, additional plugins and parsers will also be installed.

1. Dependencies installation and explanations

This section will cover the installation of the dependencies, based on the technology you are going to use.

Node

No matter what you use, Node, React, React Native or Vue, JavaScript or TypeScript, do install, as a dev dependency, the following npm packages: eslint, prettier, eslint-config-prettier and eslint-plugin-prettier.

npm i -D eslint prettier eslint-plugin-prettier eslint-config-prettier

Packages’ details:

  • You can see the eslint and prettier details in the ESLint, EditorConfig and Prettier section.
  • eslint-config-prettier: disables all the rules that can produce conflicts with Prettier and therefore, when adding it to the ESLint configuration under the extends section, it should be added last, so that it can override other configs: "extends": ["…", "prettier"].
  • eslint-plugin-prettier: is a plugin that runs Prettier as an ESLint rule. This plugin works best if other ESLint formatting rules are disabled and eslint-config-prettier is used for that. There are two ways to integrate this plugin with the eslint-config-prettier:
    1. have ["prettier"] as the last item in the extends section (to override other configs), add "prettier/prettier": "error" to the rules section and add ["prettier"] to the plugins section, or
    2. add ["plugin:prettier/recommended"] as the last item to the extends section (instead of "prettier") and then you don’t need the "prettier/prettier": "error" in the rules section and you don’t need ["prettier"] in the plugins section.
    Both ways enable eslint-plugin-prettier, extend eslint-config-prettier configuration and set the prettier/prettier rule to error, but the first one allows easier modifications.

👉 Go to ESLint, Prettier and EditorConfig configuration setup
👉
Go to TypeScript setup

React

In addition to the Node setup, install the following additional plugins: eslint-plugin-react and eslint-plugin-react-hooks

npm i -D eslint prettier eslint-plugin-prettier eslint-config-prettier eslint-plugin-react eslint-plugin-react-hooks

Packages’ details:

  • eslint-plugin-react: is a plugin that enables a preset of linting rules specific to React. To enable this plugin, ["plugin:react/recommended"] should be added to the extends section and { version: 'detect' } should be added to the settings.react section in the ESLint configuration. If you don’t want to use this preset of rules and instead you want to specify individual rules, you should do 2 things: add ["react"] under the plugins section and enable JSX support by adding { "jsx": true } under parserOptions.ecmaFeatures section in the ESLint configuration. Note that from React version 17 you don’t have to import React from 'react' anymore and you can disable linting rules for that by adding "react/jsx-uses-react": "off” and "react/react-in-jsx-scope": "off" under the rules section in the ESLint configuration.
  • eslint-plugin-react-hooks: is a plugin for enforcing the two React hook rules: call hooks from React function components and call hooks from custom hooks. To use linting rules for those two hook rules, you should do two things: add ["react-hooks"] under the plugins section and add "react-hooks/rules-of-hooks": "error" and "react-hooks/exhaustive-deps": "warn" under the rules section of the ESLint configuration.

👉 Go to ESLint, Prettier and EditorConfig configuration setup
👉
Go to TypeScript setup

React Native

In addition to the Node setup, install the following additional plugins: eslint-plugin-react, eslint-plugin-react-hooks , @react-native-community/eslint-config and eslint-plugin-react-native

npm i -D eslint prettier eslint-plugin-prettier eslint-config-prettier eslint-plugin-react eslint-plugin-react-hooks @react-native-community/eslint-config eslint-plugin-react-native

Packages’ details:

  • You can read more about the eslint-plugin-react and eslint-plugin-react-hooks in the React section.
  • @react-native-community/eslint-config: is the ESLint config for React Native and you should add ["@react-native-community"] to the extends section in the ESLint configuration to enable it.
  • eslint-plugin-react-native: is a plugin that enables React Native specific rules for ESLint. To use this preset of rules you should add 3 things to the ESLint configuration:
    1. add ["react-native"] under the plugins section,
    2. enable JSX support by adding { "jsx": true } under the parserOptions.ecmaFeatures section and
    3. whitelist all browser-like globals by adding { "react-native/react-native": true } under the env section.

👉 Go to ESLint, Prettier and EditorConfig configuration setup
👉
Go to TypeScript setup

Vue

In addition to the Node setup, install the following additional parsers and a plugin: vue-eslint-parser, eslint-plugin-vue and @babel/eslint-parser

npm i -D eslint prettier eslint-plugin-prettier eslint-config-prettier vue-eslint-parser eslint-plugin-vue @babel/eslint-parser

Packages’ details:

  • vue-eslint-parser: Since ESLint’s default parser (Espree) can’t lint Vue single file components because they aren’t plain JavaScript, this parser generates enhanced Abstract Syntax Tree (AST) and enables the linting of <template> and <script> parts of the .vue files. To enable this parser, you should add "vue-eslint-parser" under the parser section in the ESLint configuration. If you want to use a different parser for parsing the <script> part you can add another parser, for example "@babel/eslint-parser", under the parserOptions.parser section.
  • eslint-plugin-vue: this is the official ESLint plugin for Vue which, in combination with the vue-eslint-parser, enables linting of .vue files. To enable it, you should add ["plugin:vue/essential"] under the extends section in the ESLint configuration. If you want to use a different preset of rules, you can find the list of available ones here.
  • @babel/eslint-parser: this parser, unlike the default ESLint parser, supports experimental and non-standard syntaxes provided by Babel. This means that this parser enables linting any code that Babel considers valid.

👉 Go to ESLint, Prettier and EditorConfig configuration setup
👉
Go to TypeScript setup

TypeScript

If you’re using TypeScript, in addition to the Node setup and additional plugins and parsers based on the technology you are using mentioned above, you will also need an additional parser and a plugin: @typescript-eslint/eslint-plugin and @typescript-eslint/parser

npm i -D @typescript-eslint/eslint-plugin @typescript-eslint/parser

Packages’ details:

  • @typescript-eslint/eslint-plugin: like ESlint, TypeScript uses a parser to transform your source code to a data format called Abstract Syntax Tree (AST) used for giving feedback about problems in your code. The problem is that ESLint and TypeScript use different AST formats. This plugin is used so that ESLint and TypeScript work together and, in combination with the @typescript-eslint/parser, allows for TypeScript specific rules to run. To enable this plugin, you should add ["@typescript-eslint"] under the plugins section in the ESLint configuration. This enables you to modify rules related to typescript-eslint in the following format: "@typescript-eslint/rule-name": "error". Also, you can enable all recommended rules by adding ["plugin:@typescript-eslint/recommended"] under the extends section of the ESLint configuration. To disable all TypeScript rules that conflict with Prettier, you also have to add ["prettier/@typescript-eslint"] in the extends section.
  • @typescript-eslint/parser: this parser is just one of the necessary parts that, in combination with some plugin (usually @typescript-eslint/eslint-plugin), enable using ESLint and TypeScript together. To use ESLint and TypeScript together, you should add "@typescript-eselint/parser" under the parser section in the ESLint configuration if you are not using Vue with TypeScript. If you are using Vue with TypeScript, you should add "@typescript-eslint/parser" under the "parserOptions.parser" section because it will be used only for the <script> part .

2. The ESLint, Prettier and EditorConfig configuration setup

This section will cover the ESLint, Prettier and EditorConfig configuration files based on the technology you are going to use.

ESLint configuration

Based on the technology you are using, you will have to add some parsers, plugins and rules that you’ve installed earlier to your .eslintrc.js (or .json, .yaml, …) file, which should be located in the root of your project. You need to put the correct parser, if necessary (if you’re using TypeScript or Vue for example), into the .eslintrc.js, prettier under the plugins section in order to use it, as well as the corresponding plugins under the extends section. Note that it is important to put them in the correct order — i.e. Prettier should be the last one so it can override others. You can set up your own set of rules in the .eslintrc.js or you can use presets that are available, based on the technology you are using. For example, a set of rules you can use recommended by the ESLint team is eslint:recommended.

The rules that you are planning to put here under the rules property should be about the code quality, not code formatting. If you want to add any formatting rules, add them in the Prettier configuration. Otherwise, it is very likely to have conflicts between ESLint and Prettier. Because both ESLint and Prettier can format your code, they can conflict with one another if not set up correctly. You can check more about it in the Set up ESlint, Prettier & EditorConfig without conflicts article.

Besides specifying which rules are enabled and at what error level, you can also specify environments that bring global variables that are predefined, and the additional global variables accessed during execution.

An example of the file content possibilities:

You can use this example in your .eslintrc.js file and remove anything that’s non-related to the technology you are using, or you can find the example for each technology here:

You can find more about the plugins and parsers mentioned in the example in the Dependencies installation and explanations section.

You can choose what rule set and what rules you would like to use and you can find them and the explanations here: ESLint, Prettier, React, TypeScript, Vue.

If you don’t want ESLint to check some files or directories, you can put the paths to those files in a file called .eslintignore and ESLint will not check them.

An example of the .eslintignore file:

server.js
dist/*
node_modules/*

You can find more about this here.

Prettier configuration

Prettier does not require a configuration file, but you can define your own set of formatting rules in the .prettierrc file, which should be located in the root of your project. That way you can, for example, specify the quote type to be used in the project or include a trailing comma for a cleaner diff preview etc.

An example of the file content:

You can find all available rules you can use and the explanations here.

If you don’t want Prettier to check some files or directories, you can put the paths to those files in a file called .prettierignore and Prettier will not check them.

An example of the .prettierignore file:

# Ignore all HTML files: 
*.html

You can find more about this here.

EditorConfig configuration

You can define your own set of formatting rules in the .editorconfig file, which should be located in the root of your project. That way you can, for example, specify the indent style (tabs or spaces) and size to be used across the project.

An example of the file content:

You can find all available rules you can use and the explanations here.

3. Linting scripts and pre-commit checks

When you’re done with installing and configuring, here is something that you can do to make your formatting and linting easier. Besides the automatic formatting, if you have Prettier integrated with your editor, you can also add linting scripts to make it easier to lint or lint and format all the files you want. Also, you can use a pre-commit check that will do it for you and assure that nothing unformatted sneaks into the repository.

You can add scripts into the package.json file for linting and fixing formatting errors, where you will specify what file types you want to lint and the path to those files. For example, if you want to lint .js and .vue files in you src folder, you can add scripts like these:

Now you can lint or lint and format by simply running npm run lint or npm run lint:fix. The --cache flag improves ESLint’s running time by linting only changed files and it will generate the .eslintcache file.

You can also use a pre-commit check to do the linting when committing your staged changes. When you run git commit, the pre-commit check will run and, if the check fails, you will see all the errors the linter has found and committing won’t be done. Otherwise, the commit is made as usual. Preventing you to commit, if the check detected errors, will, at the end, save you a great amount of time. Therefore, pre-commit checks are a good place to run linting and also other scripts, such as tests, etc. As described in the Using lint-staged, husky, and pre-commit hooks to fail fast and early article:

The extra few seconds per commit far outweigh the lost time of CI failing after 15 minutes, determining and fixing why, and then keeping half an eye on the next 20 minute run to make sure it does not fail again.

To run the pre-commit checks, you can set up husky and lint-staged. Husky allows you to run scripts on git commands, for example on running git commit, and lint-staged assures that the script is triggered only on staged files so that the lint process is faster and the results are more relevant.

Install and configure husky and lint-staged with:

npx mrm lint-staged

You will find the generated configuration in the project’s package.json file:

Note that if you are using ESLint with --cache, you should use it here as well because running ESLint without --cache will delete the .eslintcache file. You can also modify the lint-staged configuration by specifying what staged files you want to check (for example *.{js,vue}), add several scripts inside an array, or remove the --fix flag so that it doesn’t fix errors automatically, for example:

"lint-staged": {
"*.{js,vue}": [
"eslint --cache",
"npm run some-other-script"
]
}

If you want to specify the script for linting that you’ve already added (for example you want to put npm run lint instead of eslint), note that lint-staged passes the staged files that match the specified criteria (*.{js,vue}) to that script, so the linting won’t be applied only on staged files because you’ve already specified all the files in your lint script that should be checked by adding 'src/**/*.{js,vue}'.

Conclusion

For easier development and collaboration, in order to avoid formatting conflicts and to have a second pair of eyes that will warn you about errors in your code, it is very useful to set up code formatting and linting and a great way to do that is by setting up ESLint, Prettier and EditorConfig that cover the code quality, consistent code formatting and are synchronizing your team’s editors and IDEs. You will have to install some dependencies for the technologies you are using, like some parsers and plugins, and then you’ll have to add the configurations for EditorConfig, ESLint and, optionally, for Prettier. There you can define your team’s own set of rules and you can integrate Prettier with your editor or IDE for automatic formatting when saving the file or via a keyboard shortcut. You can also add scripts for linting and fixing lint errors to make linting and formatting your project easier, as well as add a pre-commit hook to do the linting (and fixing) and formatting for you, when you commit your changes, to assure that some unformatted code doesn’t end up in the repository. This way you and your team can start working on a project with joy and without the fear of conflicts.

Thank you for reading and big thanks to Antonija Butković for the illustrations!

--

--