This post involves setting up eslint, stylelint, husky and lint-staged to ensure you lint on precommit git hook. Less than 5 mins of setup that will automate linting and make it a part of your daily development process. If you are unfamiliar with the libraries that will be used, lets quickly see what each one of them does.
Libraries Used and What they do
- ESlint – Tool to identify and report errors in JavaScript
- Stylelint – Tool to identify and report errors in your Styles
- Lint-Staged – Runs commands/tools (like ESlint, Stylelint) automatically only on staged (git) files
- Husky – Simplifies creating & running commands on git hooks
1. Setup ESLint
ESLint improves our code quality by fixing minor errors automatically and helps to enforce certain coding standards upon the developer. Let’s install and configure ESLint to see it in action
// install eslint npm install eslint --save-dev // configure eslint rules ./node_modules/.bin/eslint --init
When you configure eslint, a .eslintrc.js
file will be created at the root of your project.
Lets update your package.json
to simplify running eslint
// package.json "scripts": { ... "lintjs": "./node_modules/.bin/eslint . --fix" }
Now to run eslint, simply type npm run lintjs
. This will scan your entire project and will fix the potentially fixable javascript errors. Other errors which are not automatically fixed will be listed in the terminal.
To make eslint ignore files/directories, you can create a .eslintignore
file at the root of your project. Its syntax is similar to .gitignore
file’s syntax.
2. Setup Stylelint
Stylelint helps to maintain consistent coding style by checking and reporting style-related errors. It is capable of paring .css
, .less
, .sass
files. Let us see how to install and configure Stylelint
// install stylelint npm install stylelint --save-dev // configure stylelint rules npm install stylelint-config-standard --save-dev
There are several ways to configure stylelint, we will configure it directly in the package.json
. We will also update the scripts section of package.json to simplify runnning stylelint
// package.json ... "stylelint": { "extends": "stylelint-config-standard" }, "scripts": { ... "lintcss": "./node_modules/.bin/stylelint "**/*.css --fix" }
To run stylelint, simply type npm run lintcss
. This will scan your entire project and will fix the potentially fixable CSS errors. Other errors which are not automatically fixed will be listed in the terminal.
To make stylelint ignore files/directories, you can create a .stylelintignore
file at the root of your project. Its syntax is similar to .gitignore
file’s syntax.
An example of how stylelint reports errors is shown below
3. Setup Lint-Staged
Lint-Staged basically runs a specific command that it is configured to run on staged files. Let us install, configure and checkout Lint-Staged in action
// install lint-staged npm install lint-staged --save-dev
There are several ways of configuring lint-staged, we will configure it in package.json
.
The syntax of the configuration that lint-staged expects is of the format
"lint-staged": { "*": ["your-command"] }
where *
refers to the files to be passed to “your-command” as arguments. Based on that, our package.json will look something like…
// package.json ..., "lint-staged": { "*.{js,tsx}": [ "./node_modules/.bin/eslint --fix", "git add" ], "*.{css,less,sass}": [ "./node_modules/.bin/stylelint --fix", "git add" ] },
Explanation – "*.{js,tsx}"
=> will select only files with the extension .js, .tsx
and will execute 2 commands on it (eslint --fix
followed by git add
). Likewise, the stylelint, git add
command will be executed only on files with the extension .css, .less, .sass
.
To test it out, modify any .js
file with some arbitrary code (like var x = 1;
) and stage it (git add filename.js
). Once you do that, execute lint-staged by running
./node_modules/.bin/lint-staged
Since you edited a javascript file, lint-staged will cause Eslint to be executed on that particular file giving you an output similar to the one shown here
4. Setup Husky
Husky makes it extremely easy to setup a git hook. A git hook is generally used to run some code before an event occurs in git (like a git commit/push/pull
). A pre-commit git hook is a hook that executes before a commit happens. We will use this pre-commit git hook to automatically run lint-staged to ensure our javascript and stylesheets stay linted all the time and block the commit if any potential errors were found. (Without Husky, we would have to manually edit the pre-commit git hook found in the .git/hooks/
directory)
Installing and configuring Husky
// install husky npm install husky --save-dev // syntax to configure husky (.huskyrc, .huskyrc.json, .huskyrc.js or package.json) "husky": { "hooks": { "pre-commit": "command-to-execute", "pre-push": "command-to-execute", "...": "..." } }
We want lint-staged
to run on the pre-commit git hook, so lets configure it in our package.json
file
// package.json ..., "husky": { "hooks": { "pre-commit": "lint-staged" } },
Now each time you edit a javascript/css file, stage it and try to commit the file, the lint-staged
command gets executed that causes both the linters configured earlier(eslint, stylelint) to be executed. If any error is found and was not able to be automatically fixed, it will be reported and the commit will be cancelled.
Felicitations! You have successfully integrated pre-commit checks to your workflow.
Commit without running Linters
Sometimes, you might want to commit your code without running any linter or without having husky to block your commit. You can do that simply by adding a commit and passing the --no-verify
parameter to the commit as shown…
// skip running checks on git hook git commit -m "your message" --no-verify
Performance
As pre-commit hooks are executed on the client-side, executing commands like eslint, stylelint adds a few seconds each time you make a commit. While running these linters may not really slow you down, make sure to avoid the temptation of running tests, analysis, prettification, etc in the git hooks that will certainly increase the execution time considerably causing unnecessary frustration.
Lastly, here’s a short video that shows lint on Precommit git hook in action –
That’s it folks! Hope it helps 🙂
References
- https://codeburst.io/continuous-integration-lint-staged-husky-pre-commit-hook-test-setup-47f8172924fc
- https://medium.com/@rashtay/how-to-run-eslint-using-pre-commit-hook-25984fbce17e
- https://medium.com/@bartwijnants/using-prettier-and-husky-to-make-your-commits-save-2960f55cd351
- https://blog.vanila.io/pre-commit-git-hooks-with-husky-b2fce57d0ecd
- https://www.vojtechruzicka.com/githooks-husky/
- https://www.orangejellyfish.com/blog/code-consistency-with-eslint-and-husky/
- https://www.39digits.com/automatically-format-your-javascript-commits-using-prettier-and-husky