Lint on precommit Git hook made easy

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