16

I found numerous blogs (including the lint-staged doc) introducing such a way to use husky+ lint-staged as the following code defined in the package.json:

{
  "scripts": {
    "precommit": "lint-staged"
  },
  "lint-staged": {
    "src/**/*.js": ["prettier --write","eslint --fix", "git add"]
  }
}

Since there are errors that neither "prettier" nor "eslint --fix" can fix, how can we prevent bad commit by such a usage?

Shawn Chen
  • 1,017
  • 2
  • 13
  • 24

5 Answers5

28

You can indeed run multiple commands with lint-staged and if one of them fails, you will get the correct exit code as shown in the example below. This works via the new husky hooks system:

With a configuration like this in package.json:

"husky": {
    "hooks": {
      "pre-commit": "lint-staged"
    },
},
"lint-staged": {
    "src/**/*.{js,jsx,ts,tsx,json,css}": [
        "prettier --write",
        "eslint --fix src/",
        "tslint --fix --project .",
        "git add"
    ]
},

The configuration runs prettier, eslint and tslint - you would get the following error on linting problems:

husky > pre-commit (node v8.12.0)
  ↓ Stashing changes... [skipped]
    → No partially staged files found...
  ❯ Running linters...
   ❯ Running tasks for src/**/*.{js,jsx,ts,tsx,json,css}
      ✖ prettier --write
        eslint --fix src/
        tslint --fix --project .
        git add
✖ prettier --write found some errors. Please fix them and try committing again.
...
husky > pre-commit hook failed (add --no-verify to bypass)

The last line shows you that git's own pre-commit hook failed and thus your changed won't get commited (if they are not fixable).

Willi Mentzel
  • 27,862
  • 20
  • 113
  • 121
maiksensi
  • 833
  • 1
  • 12
  • 23
5

Some files I use, in case someone can be interested:

.prettierrc

{
  "printWidth": 120,
  "proseWrap": "preserve",
  "semi": false,
  "singleQuote": true,
  "useTabs": false,
  "tabWidth": 2,
  "arrowParens": "avoid",
  "trailingComma": "es5"
}

.lintstagedrc

{
  "**/*.+(js|md)": [
    "prettier --write",
    "eslint --fix src/",
    "git add"
  ]
}

.prettierignore

node_modules
coverage

.huskyrc

{
    "hooks": {
      "pre-commit": "lint-staged"
    }
}
Willi Mentzel
  • 27,862
  • 20
  • 113
  • 121
gildniy
  • 3,528
  • 1
  • 33
  • 23
5

Configure husky, lint-staged

Install following packages to run pre-commit hooks before commit

 npm install -D eslint prettier stylelint
  • Updated package.json
 "devDependencies": {
    "eslint": "^7.32.0",
    "prettier": "^2.3.2",
    "stylelint": "^13.13.1"
  }

This command will install and configure husky and lint-staged for following packages installed

 npx mrm@2 lint-staged 
  • "lint-staged" property is added and following packages are added to devDependencies in package.json

  • This command will also add '.husky' folder that will contain pre-commit hook

 "lint-staged": {
    "*.js": "eslint --cache --fix",
    "*.css": "stylelint --fix",
    "*.{js,css,md}": "prettier --write"
  }

 "devDependencies": {
    ...
    "husky": ">=6",
    "lint-staged": ">=10",
    ...
  }

  "scripts": {
    ...
    "prepare": "husky install"
  },

Configuration files

  • Stylelint configuration file -> .stylelintrc
{
  "plugins": [
    <CAN_HAVE_PLUGINS> LIKE ("stylelint-order","stylelint-scss") AND FOLLOWING PROPERTIES OVERRIDDEN IN "rules {...}"
  ],
  "rules": {
    "indentation": 2,
    "unit-allowed-list": [
      "em",
      "rem",
      "px",
      "%"
    ],
    "order/properties-order": [
      [
        "width",
        "height"
      ],
    "order/properties-alphabetical-order": null,
    "unit-case": "lower",
    "property-case": "lower",
    "string-quotes": "single"
  }
}
  • Prettier configuration file -> .prettierrc
{
    "singleQuote": true,
    "trailingComma": "all",
    "printWidth": 120,
    "tabWidth": 4,
    "useTabs": true,
    "semi": false
}
  • Eslint configuration file -> "eslintrc.json"
{
  "extends": ["eslint:recommended"],
  "parser": "babel-eslint",
  "plugins": [
      <PLUGINS>
  ],
  "rules": {
  ...
   "no-delete-var": "error",
    "no-dupe-args": "error",
    "no-dupe-class-members": "error",
    "no-dupe-keys": "error",
    "no-duplicate-case": "error",
    ...
    <MORE_RULES_DEFINED>
  },
  "env": {
    "es2021": true,
    "node": true
  },
}

  • You can have also ignored files to ignore following files/dir from linting
- .prettierignore
- .stylelintignore
- .eslintignore 
khizer
  • 1,242
  • 15
  • 13
2

I think a good practice is a little bigger than just these tools. I would leverage having an .editorconfig, ( Not everyone uses the same IDE/Editor ) in combination with a good eslint setup, and testing, and a formatting script. You will need to do this twice, once in a hook setup via husky.. and once in CI. ( CI will catch folks who try to --no-verify over a hook )

Run npm install --save-dev husky lint-staged and create a .lintstagedrc and as well as an .huskyrc at root.

Example setup for some scripts in package.json

package.json

In this example I have lint, prettier, and a format script. And notice I am ignoring files in my .gitignore for formatting.

   "format": "npm run pretty -- --write",
    "lint": "eslint --ignore-path .gitignore --ext .js --ext .jsx .",
    "pretty": "prettier --ignore-path .gitignore \"**/*.+(js|json|md)\"",

.lintstagedrc

This will run the commands I want to run when lint-staged is called from the husky hook. If you want to add --fix to the eslint command you can append it here. Be sure your prettier tool is setup to handle formatting afterward.


{
  "*.+(js|jsx)":[
    "eslint"
  ],
  "*.+(js|json|md)":[
    "prettier --write"
  ]
}

.huskyrc

Obviously you can extend a ton of scripts in the pre-commit, pre-push or other hooks via husky.. even enforce commit messages.

{
  "hooks":{
    "pre-commit": "lint-staged && npm run test",
    "commit-msg": "commitlint -E HUSKY_GIT_PARAMS"
  }
}
thedude
  • 21
  • 3
0

You can't, but you can't do that with regular linting either. This will not give you a solution, but it will point out any potential errors in your code.

James Mulholland
  • 1,782
  • 1
  • 14
  • 21