JavaScript/TypeScript code formatting and linting with ESLint, Prettier, EditorConfig, husky and lint-staged
Table of content
- Summary
- Introduction
- ESLint, Prettier and EditorConfig
- Setting up the project code formatting and linting
1. Dependencies installation and explanations
▫️ Node
▫️ React
▫️️ React Native
▫️ Vue
▫️ TypeScript
2. The ESLint, Prettier and EditorConfig configuration setup
▫️️ ESLint configuration
▫️️ Prettier configuration
▫️️ EditorConfig configuration
3. Linting scripts and pre-commit checks - Conclusion
- References
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.
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.
You can find more about Prettier on their official website:
Prettier · Opinionated Code Formatter
Opinionated Code Formatter
Opinionated Code Formatterprettier.io
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.
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
andprettier
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 theextends
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 andeslint-config-prettier
is used for that. There are two ways to integrate this plugin with theeslint-config-prettier
:
1. have["prettier"]
as the last item in theextends
section (to override other configs), add"prettier/prettier": "error"
to therules
section and add["prettier"]
to theplugins
section, or
2. add["plugin:prettier/recommended"]
as the last item to theextends
section (instead of"prettier"
) and then you don’t need the"prettier/prettier": "error"
in therules
section and you don’t need["prettier"]
in theplugins
section.
Both ways enableeslint-plugin-prettier
, extendeslint-config-prettier
configuration and set theprettier/prettier
rule toerror
, 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 theextends
section and{ version: 'detect' }
should be added to thesettings.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 theplugins
section and enable JSX support by adding{ "jsx": true }
underparserOptions.ecmaFeatures
section in the ESLint configuration. Note that from React version 17 you don’t have toimport 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 therules
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 theplugins
section and add"react-hooks/rules-of-hooks": "error"
and"react-hooks/exhaustive-deps": "warn"
under therules
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
andeslint-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 theextends
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 theplugins
section,
2. enable JSX support by adding{ "jsx": true }
under theparserOptions.ecmaFeatures
section and
3. whitelist all browser-like globals by adding{ "react-native/react-native": true }
under theenv
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 theparser
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 theparserOptions.parser
section.eslint-plugin-vue
: this is the official ESLint plugin for Vue which, in combination with thevue-eslint-parser
, enables linting of.vue
files. To enable it, you should add["plugin:vue/essential"]
under theextends
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 theplugins
section in the ESLint configuration. This enables you to modify rules related totypescript-eslint
in the following format:"@typescript-eslint/rule-name": "error"
. Also, you can enable all recommended rules by adding["plugin:@typescript-eslint/recommended"]
under theextends
section of the ESLint configuration. To disable all TypeScript rules that conflict with Prettier, you also have to add["prettier/@typescript-eslint"]
in theextends
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 theparser
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:
- Node
- Node + TypeScript
- React
- React + TypeScript
- React Native
- React Native + TypeScript
- Vue
- Vue + TypeScript
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!
References
- ESLint
- Prettier
- EditorConfig
- husky
- lint-staged
- Set up ESlint, Prettier & EditorConfig without conflicts by François Hendriks
- Why You Should Use ESLint, Prettier & EditorConfig by François Hendriks
- What are JavaScript linters? by Matt Zeunert
- Using lint-staged, husky, and pre-commit hooks to fail fast and early by Dominic Fraser
- Prettier — Code formatter extension
- Git hooks
- eslint-config-prettier
- eslint-plugin-prettier
- eslint-plugin-react
- eslint-plugin-react-hooks
- @react-native-community/eslint-config
- eslint-plugin-react-native
- vue-eslint-parser
- Espree
- eslint-plugin-vue
- @babel/eslint-parser
- @typescript-eslint/eslint-plugin
- @typescript-eslint/parser
- EditorConfig Properties