VSCODE & GitHub Desktop pre-commit hook: npx: command not found

Viewed 19519

I am starting a new repo, thinking I should use the most recent Huksy v6 which is installed from LintStaged using their setup guide:

npx mrm lint-staged

// package.json updated with:
"husky": ">=6",
"lint-staged": ">=10",

This adds necessary packages and adds the husky files including the precommit files:

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

npx lint-staged

When i run my commit in the terminal it works fine. However, if I try to run my commit in GitHub Desktop or VSCode (which I know some teammates do), it results in an error for both:

npx: command not found. husky - pre-commit hook exited with code 127 (error)

I have npx installed:

npx -v
// 6.14.10

If I try to install in globall, such as described in other StackOverflow suggestions, it returns a warning about existing location (with & with out sudo):

ERR! EEXIST: file already exists, symlink '../lib/node_modules/npx/index.js' -> '/Users/plucks/.nvm/versions/node/v14.15.4/bin/npx' npm ERR! File exists: /Users/plucks/.nvm/versions/node/v14.15.4/bin/npx npm ERR! Remove the existing file and try again, or run npm npm ERR! with --force to overwrite files recklessly.

Is there anything I can do so the programs like VSCode & GitHub Desktop can run?

8 Answers

As per this suggestion, adding the following to your pre-commit file should fix it:

export NVM_DIR="$HOME/.nvm/nvm.sh"
. "$(dirname $NVM_DIR)/nvm.sh"

export NVM_DIR="$HOME/.nvm"
a=$(nvm ls | grep 'node')
b=${a#*(-> }
v=${b%%[)| ]*}

export PATH="$NVM_DIR/versions/node/$v/bin:$PATH"

So the full file would look like this:

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

export NVM_DIR="$HOME/.nvm/nvm.sh"
. "$(dirname $NVM_DIR)/nvm.sh"

export NVM_DIR="$HOME/.nvm"
a=$(nvm ls | grep 'node')
b=${a#*(-> }
v=${b%%[)| ]*}

export PATH="$NVM_DIR/versions/node/$v/bin:$PATH"

npm run test

For husky>=6: update your .husky/pre-commit file to contain this:

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

export NVM_DIR="$HOME/.nvm"
[ -s "$NVM_DIR/nvm.sh" ] && \. "$NVM_DIR/nvm.sh"

npx lint-staged

This will find and expose the current node path and therefore npx path that you are using, which has been configured with Node Version Manager nvm

I had to combine the answers of Cathal and Misol.

I did not want to edit the .husky/pre-commit like Cathal for two reasons:

  1. I would need to that for every project I use husky in
  2. It would actually break husky for my fellow developers on Windows

So I added a global ~/.huskyrc file like Misol did with the following contents:

export NVM_DIR="$HOME/.nvm/nvm.sh"
. "$(dirname $NVM_DIR)/nvm.sh"

export NVM_DIR="$HOME/.nvm"
a=$(nvm ls | grep 'node')
b=${a#*(-> }
v=${b%%[)| ]*}

export PATH="$NVM_DIR/versions/node/$v/bin:$PATH"

For those using fnm instead of nvm, adding the following to ~/.huskyrc worked for me:

eval "$(fnm env)"

Before adding any modifications to your project try restarting your IDE as mentioned in this issue

If you are working on a team with other people who may have installed nvm or node in slightly different fashion than you have, I would not recommend adding any export statements or edits to the $PATH in your .husky/precommit or ~/.huskyrc files.

If you want your VSCode to have proper access to the $PATH you expect from terminal you should always launch VSCode from terminal in the folder you are working from.

For example, in a terminal window:

~/_git/my_project: code .

Will launch VSCode with my_project open in a new window (it should remember your tabs and window state from the last time you worked on your project).

VSCode will now use the $PATH your terminal uses from your ~/.zshrc or ~/.bashrc, etc.

With this setup my .husky/precommit looks like this:

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

npx lint-staged

and my my .lintstagedrc.json looks like this:

{
  "*.{js,jsx,ts,tsx}": [
    "eslint --fix --debug --max-warnings=-1",
    "npm run lint:prettier-fix"
  ],
  "*.{css,less,sass,scss}": ["npm run lint:prettier-fix"],
  "*.{g?(raph)ql,json,html,md,y?(a)ml}": ["npm run lint:prettier-fix"]
}

Open VSCode settings and set the Inherit Env setting (Terminal > Integrated: Inherit Env) to false:

"terminal.integrated.inheritEnv": false

This setting enables or disables whether new shells should inherit their environment from VS Code.

Related