Photo by Vishal Jadhav from Unsplash.
Install and configure ESLint
ESLint is more complex to set up than other packages used in this post. It’s recommended to check this post first for ESLint, especially if you want to use it to check TypeScript code. That post can help you solve all kinds of issues when you set up ESLint for your project. If you just want to have a quick setup for ESLint, you can run this command to install and configure ESLint with a wizard:
$ **npm init** [**@eslint/config**](http://twitter.com/eslint/config)
Select the options that best suit your project and the
package.json file will be updated accordingly. A
[_.eslintrc.js_](https://gist.github.com/lynnkwong/a3300c1b8e0a38348a619bfafcb6812d#file-1170bbdff32b-eslintrc-1-js) file will be created automatically based on the choices you made. You would need to make some changes to meet your requirements. This is the
[_.eslintrc.js_](https://gist.github.com/lynnkwong/a3300c1b8e0a38348a619bfafcb6812d#file-1170bbdff32b-eslintrc-1-js) file that will be used in this post. More details for it can be found in the ESLint post.
Install and configure Prettier
Run the following command to install Prettier:
Note that besides the Prettier package, two packages for ESLint are also installed so it can work nicely with ESLint as the two have some overlap for code formatting.
The default settings of Prettier are normally enough in most cases. However, if your project needs some special styling, you can add them to a file named
.prettierrc.json file in the project root folder. You can add the options on the command line directly if there are not too many of them. Check this link for all the format options for Prettier.
Install and configure lint-staged
By default, the linters like ESLint and Prettier will check all the files in the project. This, however, is very inefficient. When creating a commit, we only want the linters to check the files that are changed or staged. A file is staged means you have run
git add to add it to the staging area. This is where the lint-staged package shines, which lets us only lint the files that are staged.
To install lint-staged, run this command:
$ **npm install --save-dev lint-staged**
To configure lint-staged, you can either create a new object called “
package.json, or create a new file named
[.lintstagedrc.json](https://github.com/okonet/lint-staged#configuration) in the project folder. The latter is better if you have complex settings. However, we will use the former as there are only a handful of settings:
Here we define three tasks for lint-staged. By default, lint-staged will run the tasks concurrently. Therefore, we should pay extra attention if the same file is modified by different tasks. The result can be unpredictable due to race conditions. We should make sure the settings of different linters have no conflict. If necessary, we can disable concurrency by with
--concurrent false on the command line for
# Run the tasks concurrently: $ **npx lint-staged**# Run the tasks sequentially: $ **npx lint-staged --concurrent false**
Note that, when a task fails, all the other tasks will be skipped or killed.
Install and configure Husky
Above we ran lint-staged manually with
npx. If we want to enforce linting before a commit is created, we should run lint-staged in the pre-commit Git hook. The pre-commit hook is actually just a runnable script that is run before a commit is created. We can have any code in the pre-commit hook and the linting code is a perfect use case.
There are three ways to add the linting code for lint-staged in a pre-commit hook:
- Create a pre-commit hook manually and add the above command to run lint-staged in it. This is a bit cumbersome because you need to copy the pre-commit hook to the
- Use the pre-commit installer. This is convenient if we only have pre-commit hooks, and no other types of Git hook like commit-msg or pre-push.
$ **npx husky-init && npm install**
A new folder named
.husky will be created in your project folder which includes a special folder named with an underscore “
_” and a template pre-commit hook. Besides, there is a new script named
prepare added in
package.json, which runs the
husky install command. The
[prepare](https://docs.npmjs.com/cli/v8/using-npm/scripts#life-cycle-scripts) script will create the
.husky folder before the package is packed.
Let’s add the command to run lint-staged in the pre-commit hook in the
Thispre-commit hook will be called before you create a commit in the current project. We need to add it to the project folder as well so it will persist in the project when it’s pushed to the remote repository. Don’t worry, it won’t be overwritten by the
husky install command.
$ **git add package.json** $ **git add package-lock.json** $ **git add .husky/pre-commit** $ **git commit**
Now when you try to create a commit for a file matching the patterns defined by lint-staged as shown above, the pre-commit hook will be called automatically. And only the staged files will be checked: Cheers! We have now successfully set up a Git pre-commit hook in our project, which enforce a coding and formatting standard for this project. Now if anyone tries to add a file that violates the rules defined by the linters, he/she would not be able to commit. You may hate it in the beginning but you will love it over time, especially when you have some new members in your team who don’t know the coding style of your group yet. It will make your codebase less error-prone, easier to maintain, and more enjoyable to read. All the code introduced in the post can be found in this repo.