23

I am trying to use a pre-commit hook to detect eslint errors before commit happens. I am using husky and lint-staged. But it runs the lint command for all the files in src and not on staged files only. Here is my package.json file.

"scripts": {
    "test:ci": "cross-env CI=true react-scripts test --bail --passWithNoTests",
    "lint": "eslint src/**/*.{js,jsx}",
    "lint:fix": "eslint . --fix",
    "precommit": "npm run lint && npm run test:ci"
  }
"husky": {
    "hooks": {
      "pre-commit": "lint-staged"
    }
  },
"lint-staged": {
    "*.js": [
      "npm run precommit"
    ],
    "*.jsx": [
      "npm run precommit"
    ]
  }

Is there any way so that it works ONLY on staged files and not on other files present in the directory?

Prateek
  • 335
  • 1
  • 2
  • 9

5 Answers5

4

With husky v7/lint-staged v11.2.0 - the staged files will simply by added onto the end of your command, separated by spaces. If you have a .husky/pre-commit file which calls npx lint-staged, and then you have a lint-staged config like so:

{
  '*.js': [
    'eslint'
  ]
}

And you modify src/foo.js and src/bar.js, the command that will be run is:

eslint src/foo.js src/bar.js

Doesn't matter what command you have inside of your lint-staged config. Files are just added onto end of command, separated by spaces.

These files will be passed to your test:ci command but they won't make it to your lint subcommand.

You can wrap in bash function... Something like this:

"precommit": "!runIt() { npm run lint $@ && npm run test:ci $@;}; runIt",

Wrote this on my phone, and I barely know bash, so syntax might be wrong

Devin Rhode
  • 23,026
  • 8
  • 58
  • 72
2

According to this lint-staged example, I implemented that in order to lint only staged files (takes like 5 secs) except when there are more than 5 staged files, it checks all the repo (can take more than 1 min):

  1. Upgrade lint-staged package to the latest version
  2. Add a .lintstagedrc.js file at the root of your repo. It could contain something like this:
module.exports = {
  '**/*.js?(x)': (filenames) =>
    filenames.length > 5 ? 'eslint --ext .js,.jsx . --ignore-path .gitignore --fix .' : `eslint ${filenames.join(' ')} --fix`,
  "*.json": [
    "prettier --write"
  ]
}
  1. Remove your old "lint-staged" command from the package.json file
PestoP
  • 247
  • 2
  • 11
2

With the ESLint CLI you have a help parameter npx eslint -h, --help or you can check the CLI docs at the official ESLint docs page/CLI. There's a section related to caching, so that ESLint only looks at files that have been changed.

Caching:
  --cache                         Only check changed files - default: false
  --cache-file path::String       Path to the cache file. Deprecated: use --cache-location - default: .eslintcache
  --cache-location path::String   Path to the cache file or directory
  --cache-strategy String         Strategy to use for detecting changed files in the cache - either: metadata or content - default: metadata
lua_python_java
  • 359
  • 2
  • 8
1

You will need to install two libraries, husky and lint-staged and you need to configure your pre-commit file that you can find inside the .husky folder and add this command to it

npx lint-staged

at the end the file will look like this in case you only want to run eslint

#!/usr/bin/env sh
. "$(dirname -- "$0")/_/husky.sh"

npx lint-staged

Janar
  • 2,623
  • 1
  • 22
  • 32
-2
"husky": {
    "hooks": {
      "pre-commit": "lint-staged"
    },
},
"lint-staged": {
    "*.js": [
        "eslint src/**/*.{js}",
        "cross-env CI=true react-scripts test --bail --passWithNoTests",
        "git add"
    ]
},
hendrixchord
  • 4,662
  • 4
  • 25
  • 39
  • 9
    If this works, it needs some explanation as to _how_ `eslint src/**/*.{js}` will ONLY lint _staged_ files. I can't see any way that it would work. – Devin Rhode Oct 05 '21 at 16:57