Linting Staged Git Files with lint-staged

An easy way to improve code quality is linting code for formatting issues, syntax typos and inconsistencies. For example, you may have accidentally left a console.log statement that prints environment variables during development. Or you may have forgotten a semi-colon during a quick bug fix. Regardless, identifying and resolving these mistakes not only reduces the amount of time and resources spent on quality assurance and control, but also reassures developers of the code's functionality.

Popular linting tools include ESLint for JavaScript/TypeScript and stylelint for CSS/SCSS/Sass/Less/SugarSS. While coding, you may have the linting tool running in watch mode within a terminal to monitor and report errors and warnings whenever you edit and save a file. This can become quite distracting, especially if you are focused more on adding new features to the application code before a tight deadline and you cannot afford to switch back-and-forth between the terminal and code editor.

Suppose you correct a problem and later on, you decide to scrap the code that you just fixed. Unfortunately, you wasted time on fixing a non-existent problem. Ideally, you should run the linter after you finish coding, but you may forget to run the linter and immediately commit the changes (with the mistakes).

With lint-staged, executing the command git commit automatically runs the linter against files staged for commit. This lets you continue working on the application code without any interruptions, and once you are done with the code, you can stage the modified files and run the linter before committing them. You can configure lint-staged to run a specific linter command against files that match a glob pattern. For JavaScript files (*.js), you may select ESLint as the linter to run against those files. For CSS files (*.css), you may select stylelint as the linter to run against those files.

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.

Below, I'm going to show you how to integrate lint-staged into your project.

How Does lint-staged Differ From pre-commit and Husky?#

Unlike lint-staged, pre-commit and Husky lints all files, not just staged files. As your project grows, linting every file, even those that have not been recently modified and previously passed all the linting rules, becomes inefficient and increases development time from redundant linting.

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

lint-staged uses Husky under-the-hood.

Installation#

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.

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

Note: 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:

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.

(package.json)

Anytime a JavaScript file is staged for a commit, lint-staged runs the ESLint linter with the --cache and --fix options. --cache tells ESLint to only check changed files, and --fix 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.

(package.json)

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

Adding New 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. Just update the value of the *.js key to an array that contains a list of scripts to run against the staged JavaScript files.

Let's run the 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.

(package.json)

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.

Next Steps#

Try integrating lint-staged to your own JavaScript libraries. You can also check out our new course, The newline Guide to Creating React Libraries from Scratch, where we teach you everything you need to know to succeed in creating a library. 


Sources#