//

How to lint staged Git files

We use linting to automate code formatting issues, to fix syntax errors and coding style. For example, you may have forgotten a semi-colon during aor bug fix you may have accidentally left a console.log statement.

Why should we use Linting?

Time spent on quality assurance and control can be reduced with automated linting. It also makes sure developers of the code's conformity to your coding standards.

Montitoring for coding errors

A common approach is to have the linting tool running in watch mode within a terminal to monitor and report errors whenever you save a file

The Problem With Watch mode

Popular linting tools include ESLint for JavaScript/TypeScript and stylelint for CSS/SCSS/Sass/Less/SugarSS. Running Lint with watch mode tends to be distracting, with your attention switching back-and-forth between the terminal and code editor.

Ideally, you should run the linter after you finish coding, but you may forget to run the linter and immediately commit your changes.

So there should ideally be an automated solution that hooks into your Git commit lifecycle.

lint-staged For Linting

With lint-staged, git commit command automatically runs the linter against files staged for commit, letting you continue working on the application code without any interruptions.

Once you are done with the code, you stage the modified files and run the linter before committing the changes.

You configure lint-staged to run a specific linter command against files that match a glob pattern. For JavaScript files (.js), ESLint is the linter to run against those files. For CSS files (.css), stylelint is the appropriate linter to run against those files.

git commit

If any files fail to pass, then they are not committed to the remote repository. Before the files can be committed, you must first resolve the errors raised by the linter. For projects with many contributors, linting enforces the project's coding conventions despite each contributor having their own set of opinions and conventions.

Why lint-staged is different from pre-commit And Husky?

Unlike lint-staged, the closely-related tools pre-commit and Husky lint all files, not just staged files. As your project grows, linting files that have not been modified becomes inefficient. It increases development time from all the redundant linting.

Husky vs pre-commit vs lint-staged

Husky supports all Git hooks, whereas pre-commit and lint-staged support only the pre-commit Git hook. Nevertheless, each library allows you to run any number of custom scripts, defined in package.json, when a hook is invoked. Git hooks, such as pre-commit, are invoked by an event such as executing the git commit command.

lint-staged uses Husky under-the-hood.

Add lint-staged to your project

Now let's see a practical example of how to integrate lint-staged into your project.

Install lint-staged

To get started, check that your project already has ESLint, stylelint or Prettier configured (either via a .xxxrc configuration file or a key inside package.json). Otherwise, the following error message is shown during the installation of lint-staged.

Cannot add lint-staged: only eslint, \
stylelint, prettier or custom rules \
are supported.

To install lint-staged, run the following command within the root directory of your project:

npx mrm@2 lint-staged

mrm is a command line tool for automating and managing project configurations.

If you are prompted with the following message, then press y to proceed with the installation:

Need to install the following packages:
  mrm@2
Ok to proceed? (y)

This command creates a ./husky directory. Adds the husky and lint-staged packages to package.json as dev dependencies. Adds a lint-staged property to package.json. If lint-staged finds a .eslintrc.js configuration file, then a *.js property is added to the lint-staged object.

Here's what this looks like in the package.json file.

{
  "lint-staged": {
    "*.js": "eslint --cache --fix"
  }
}

Anytime a JavaScript file is staged for commit, lint-staged runs the ESLint linter with the --cache and --fix flags:

the --cache flag tells ESLint to only check changed files the --fix flag tells ESLint to automatically fix problems when possible. If lint-staged finds a .prettierrc configuration file, then a *.{js,css,md} property is added to the lint-staged object.

Here's what this looks like in the package.json file.

{
  "lint-staged": {
    "*.{js,css,md}": "prettier --write"
  }
}

Anytime a JavaScript, CSS or Markdown file is staged for commit, lint-staged runs Prettier to properly format the contents of the file. This ensures the files are formatted even if a contributor does not have the Prettier plugin installed in their IDE to automatically format the files when saved.

Adding Testing And Other Scripts Suppose you want the staged JavaScript files to pass unit tests written with the Jest testing framework. Adding a new script is relatively straight-forward. Update the value of the *.js key to an array that contains a list of scripts to run against the staged JavaScript files.

As an example, suppose we want to run Jest tests with the jest --passWithNoTests command. The --passWithNoTests option allows the test suite to pass even if there are no test files present and you plan to add unit tests in the future.

{
  "lint-staged": {
    "*.js": [
      "eslint --cache --fix",
      "jest --passWithNoTests"
    ]
  }
}

These scripts run in sequence from the first listed item to the last listed item. If a single command fails, then the entire commit is rejected.

To dive more into linting, check out the lint-staged Documentation.