commitlint: Cannot find module "@commitlint/config-conventional" when running commintlint globally

Expected Behavior

I installed commitlint and commitlint/config-conventional globally, thus running echo 'hello world' | commitlint under any directory should works.

Current Behavior

The command raises an exception.

/usr/local/lib/node_modules/@commitlint/cli/lib/cli.js:67
                throw err;
                ^

Error: Cannot find module "@commitlint/config-conventional" from "/home/fabrizio"
    at resolveId (/usr/local/lib/node_modules/@commitlint/cli/node_modules/@commitlint/resolve-extends/lib/index.js:134:12)
    at resolveConfig (/usr/local/lib/node_modules/@commitlint/cli/node_modules/@commitlint/resolve-extends/lib/index.js:111:18)
    at /usr/local/lib/node_modules/@commitlint/cli/node_modules/@commitlint/resolve-extends/lib/index.js:63:18
    at Array.reduce (<anonymous>)
    at loadExtends (/usr/local/lib/node_modules/@commitlint/cli/node_modules/@commitlint/resolve-extends/lib/index.js:61:32)
    at resolveExtends (/usr/local/lib/node_modules/@commitlint/cli/node_modules/@commitlint/resolve-extends/lib/index.js:44:17)
    at Object.$If_1 (/usr/local/lib/node_modules/@commitlint/cli/node_modules/@commitlint/core/lib/load.js:90:46)
    at Object.<anonymous> (/usr/local/lib/node_modules/@commitlint/cli/node_modules/@commitlint/core/lib/load.js:159:18)
    at <anonymous>

Affected packages

  • cli
  • config-conventional

Steps to Reproduce (for bugs)

  1. npm install -g @commitlint/cli @commitlint/config-conventional
  2. echo "module.exports = {extends: ['@commitlint/config-conventional']};" > ~/.commitlintrc.js
  3. echo 'should fail' | commitlint
commitlint.config.js ```js module.exports = {extends: ['@commitlint/config-conventional']}; ```

Your Environment

Executable Version
commitlint --version 7.5.2
git --version 2.17.1
node --version 8.10.0

About this issue

  • Original URL
  • State: open
  • Created 5 years ago
  • Reactions: 35
  • Comments: 47 (16 by maintainers)

Commits related to this issue

Most upvoted comments

I think commitlint is usually being used on a per project basis. So each project has it’s own config. If you want to use it globally like you tried you could use the --config option and try this:

echo 'should fail' | commitlint --config ~/.commitlintrc.js

Workaround for those in the same case as me, manually include the rules from your chosen config in your commitlint.config.js config file.

Here are the rules for @commitlint/config-conventional in YAML:

.commitlintrc.yaml

---
# The rules below have been manually copied from @commitlint/config-conventional
# and match the v1.0.0 specification:
# https://www.conventionalcommits.org/en/v1.0.0/#specification
#
# You can remove them and uncomment the config below when the following issue is
# fixed: https://github.com/conventional-changelog/commitlint/issues/613
#
# extends:
#   - '@commitlint/config-conventional'
rules:
  body-leading-blank: [1, always]
  body-max-line-length: [2, always, 100]
  footer-leading-blank: [1, always]
  footer-max-line-length: [2, always, 100]
  header-max-length: [2, always, 100]
  subject-case:
    - 2
    - never
    - [sentence-case, start-case, pascal-case, upper-case]
  subject-empty: [2, never]
  subject-full-stop: [2, never, "."]
  type-case: [2, always, lower-case]
  type-empty: [2, never]
  type-enum:
    - 2
    - always
    - [build, chore, ci, docs, feat, fix, perf, refactor, revert, style, test]

@dexpota I just tried this on a clean Ubuntu VM:

npm install -g @commitlint/config-conventional @commitlint/cli
echo "module.exports = {extends: ['@commitlint/config-conventional']}" > ~/.commitlintrc.js
echo "hello world" | commitlint

Output is:

⧗   input: hello world
✖   subject may not be empty [subject-empty]
✖   type may not be empty [type-empty]
✖   found 2 problems, 0 warnings 
    (Need help? -> https://github.com/conventional-changelog/commitlint#what-is-commitlint )
cat ~/.commitlintrc.js
module.exports = {extends: ['@commitlint/config-conventional']}

I’m sorry, but I can’t reproduce your issue.

This issue is related to https://github.com/conventional-changelog/commitlint/issues/126#issuecomment-345508707

to provide some color --it looks like our issue is slightly different from the one reported here.

I can deterministically reproduce the module resolution failure on both node 8.x and 10.x when using npx to fetch and run commitlint; however, I cannot reproduce on either 8.x or 10.x if the modules are first installed globally.

works with npm i -g
npm i -g @commitlint/config-conventional @commitlint/cli
echo 'hello world' \
  | commitlint -x @commitlint/config-conventional

❯ docker run --rm -i --entrypoint sh node:8.15.1 <<'EOT'
npm i -g @commitlint/config-conventional @commitlint/cli
echo 'hello world' \
  | commitlint -x @commitlint/config-conventional
EOT
/usr/local/bin/commitlint -> /usr/local/lib/node_modules/@commitlint/cli/lib/cli.js
+ @commitlint/config-conventional@7.5.0
+ @commitlint/cli@7.5.2
added 137 packages from 64 contributors in 9.439s

⧗   input: hello world
✖   subject may not be empty [subject-empty]
✖   type may not be empty [type-empty]
✖   found 2 problems, 0 warnings
    (Need help? -> https://github.com/conventional-changelog/commitlint#what-is-commitlint )
❯ docker run --rm -i --entrypoint sh node:10.15.3 <<'EOT'
npm i -g @commitlint/config-conventional @commitlint/cli
echo 'hello world' \
  | commitlint -x @commitlint/config-conventional
EOT
/usr/local/bin/commitlint -> /usr/local/lib/node_modules/@commitlint/cli/lib/cli.js
+ @commitlint/config-conventional@7.5.0
+ @commitlint/cli@7.5.2
added 137 packages from 64 contributors in 10.263s

⧗   input: hello world
✖   subject may not be empty [subject-empty]
✖   type may not be empty [type-empty]
✖   found 2 problems, 0 warnings
    (Need help? -> https://github.com/conventional-changelog/commitlint#what-is-commitlint )

fails with npx -p
echo 'hello world' \
  | npx \
    -p @commitlint/config-conventional \
    -p @commitlint/cli \
  commitlint -x @commitlint/config-conventional

❯ docker run --rm -i --entrypoint sh node:8.15.1 <<'EOT'
echo 'hello world' \
  | npx \
    -p @commitlint/config-conventional \
    -p @commitlint/cli \
  commitlint -x @commitlint/config-conventional
EOT
npx: installed 137 in 9.894s
/root/.npm/_npx/7/lib/node_modules/@commitlint/cli/lib/cli.js:113
	throw err;
	^

Error: Cannot find module "@commitlint/config-conventional" from "/"
    at resolveId (/root/.npm/_npx/7/lib/node_modules/@commitlint/cli/node_modules/@commitlint/resolve-extends/lib/index.js:112:14)
    at resolveConfig (/root/.npm/_npx/7/lib/node_modules/@commitlint/cli/node_modules/@commitlint/resolve-extends/lib/index.js:92:20)
    at reduce (/root/.npm/_npx/7/lib/node_modules/@commitlint/cli/node_modules/@commitlint/resolve-extends/lib/index.js:49:20)
    at Array.reduce (<anonymous>)
    at loadExtends (/root/.npm/_npx/7/lib/node_modules/@commitlint/cli/node_modules/@commitlint/resolve-extends/lib/index.js:47:32)
    at resolveExtends (/root/.npm/_npx/7/lib/node_modules/@commitlint/cli/node_modules/@commitlint/resolve-extends/lib/index.js:30:19)
    at Object.$If_1 (/root/.npm/_npx/7/lib/node_modules/@commitlint/cli/node_modules/@commitlint/load/lib/index.js:69:45)
    at Object.<anonymous> (/root/.npm/_npx/7/lib/node_modules/@commitlint/cli/node_modules/@commitlint/load/lib/index.js:142:17)
    at <anonymous>
❯ docker run --rm -i --entrypoint sh node:10.15.3 <<'EOT'
echo 'hello world' \
  | npx \
    -p @commitlint/config-conventional \
    -p @commitlint/cli \
  commitlint -x @commitlint/config-conventional
EOT
npx: installed 137 in 8.683s
/root/.npm/_npx/9/lib/node_modules/@commitlint/cli/lib/cli.js:113
	throw err;
	^

Error: Cannot find module "@commitlint/config-conventional" from "/"
    at resolveId (/root/.npm/_npx/9/lib/node_modules/@commitlint/cli/node_modules/@commitlint/resolve-extends/lib/index.js:112:14)
    at resolveConfig (/root/.npm/_npx/9/lib/node_modules/@commitlint/cli/node_modules/@commitlint/resolve-extends/lib/index.js:92:20)
    at reduce (/root/.npm/_npx/9/lib/node_modules/@commitlint/cli/node_modules/@commitlint/resolve-extends/lib/index.js:49:20)
    at Array.reduce (<anonymous>)
    at loadExtends (/root/.npm/_npx/9/lib/node_modules/@commitlint/cli/node_modules/@commitlint/resolve-extends/lib/index.js:47:32)
    at resolveExtends (/root/.npm/_npx/9/lib/node_modules/@commitlint/cli/node_modules/@commitlint/resolve-extends/lib/index.js:30:19)
    at Object.$If_1 (/root/.npm/_npx/9/lib/node_modules/@commitlint/cli/node_modules/@commitlint/load/lib/index.js:69:45)
    at Object.<anonymous> (/root/.npm/_npx/9/lib/node_modules/@commitlint/cli/node_modules/@commitlint/load/lib/index.js:142:17)

At this point I’m thinking this is either an issue with @commitlint/resolve-extends or a bug in npx.

@paesrafael guessing you don’t work with any others as that’s only gonna work for your computer.

Guys, here the same problem happened when installing globally.

I solved it by adding the full path to the @commitlint/config-conventional folder in my commitlint.config.js in each project.

Example: module-yarn-global-commitlint

This is far from the best way, but it resolved.

With @commitlint/cli and @commitlint/config-conventional installed globally, on Linux, I got it working like this:

echo "hello world" | commitlint -g ~/.commitlintrc.js -x $(npm root -g)/@commitlint/config-conventional

we’re also running into this issue.

our goal is 0 configuration enforcement of conventional commits in CI --I expected the following to work:

❯ cd $(mktemp -d) && ls -a
.  ..

❯ export CI_COMMIT_MESSAGE='foo: bar'

❯ npx -p @commitlint/config-conventional -p @commitlint/cli -c 'echo $CI_COMMIT_MESSAGE | commitlint -x @commitlint/config-conventional'
npx: installed 137 in 8.51s
/Users/foo/.npm/_npx/6761/lib/node_modules/@commitlint/cli/lib/cli.js:113
	throw err;
	^

Error: Cannot find module "@commitlint/config-conventional" from "/private/var/folders/xr/dxys9d310_s1j3klz_1xwz9jq1qqv5/T/tmp.BsKwQjE1QE"
    at resolveId (/Users/foo/.npm/_npx/6761/lib/node_modules/@commitlint/cli/node_modules/@commitlint/resolve-extends/lib/index.js:112:14)
    at resolveConfig (/Users/foo/.npm/_npx/6761/lib/node_modules/@commitlint/cli/node_modules/@commitlint/resolve-extends/lib/index.js:92:20)
    at reduce (/Users/foo/.npm/_npx/6761/lib/node_modules/@commitlint/cli/node_modules/@commitlint/resolve-extends/lib/index.js:49:20)
    at Array.reduce (<anonymous>)
    at loadExtends (/Users/foo/.npm/_npx/6761/lib/node_modules/@commitlint/cli/node_modules/@commitlint/resolve-extends/lib/index.js:47:32)
    at resolveExtends (/Users/foo/.npm/_npx/6761/lib/node_modules/@commitlint/cli/node_modules/@commitlint/resolve-extends/lib/index.js:30:19)
    at Object.$If_1 (/Users/foo/.npm/_npx/6761/lib/node_modules/@commitlint/cli/node_modules/@commitlint/load/lib/index.js:69:45)
    at Object.<anonymous> (/Users/foo/.npm/_npx/6761/lib/node_modules/@commitlint/cli/node_modules/@commitlint/load/lib/index.js:142:17)

I did some digging too because I really really want to implement zero-config and the GitHub Action 😅 There is actually a chain of dependencies, working together making global imports work, here it goes:

  1. @commitlint/cli - requests resolved configuration from @commitlint/resolve-extends
  2. @commitlint/resolve-extends - fetches configuration based on module ids with resolve-from and/or resolve-global
  3. resolve-global - needs a place to look at for global modules, so it requests a path to this with global-dirs
  4. global-dirs - currently has an issue where it resolves the symlink origin of the installed Node, instead of resolving to the proper global folder.

There we go, that’s our issue too. I tried adding a 3rd fallback in @commitlint/resolve-extends to look into the hardcoded /usr/local/lib/node_modules folder, and it worked.

I’m not sure if we should drop or swap out resolve-global, because it’s a nice library and has support for both Yarn and NPM. Maybe we can pitch in with Sindre to get this fixed? There are some great developers who have documented a lot in that issue, so it’s up for grabs to fix it I guess.

For now, I can confidently add the “bug” label to this until that issue is resolved.

I was also facing this issue when using node installed by Homebrew on a Mac (which gets installed to /opt/homebrew on Macs with the newer ARM-based chips). The suggestion of setting NODE_PATH worked for me. I just added export NODE_PATH=$(npm root -g) to my .profile file.

Just set NODE_PATH, in my case:

export NODE_PATH="$XDG_DATA_HOME/yarn/global/node_modules:$XDG_DATA_HOME/npm/lib/node_modules"

I tried your solution and is not working, the same exception as before.

From what I understand from issue #123 it should be possible to use commitlint from any directory starting from version 5.0.1.

This might be a bit late, but here is my setup:

  1. Install @commitlint/cli and @commitlint/config-conventional globally via npm.
sudo npm i -g @commitlint/cli @commitlint/config-conventional
  1. Create the following alias for commitlint in your shell configuration file, like .zsh-aliases for example.
alias commitlint='commitlint --extends "@commitlint/config-conventional"'
  1. Success.

Now you can use commitlint with config-conventional from anywhere, without having to create a .commitlintrc.js in every project.

> echo 'hello world' | commitlint 
⧗   input: hello world
✖   subject may not be empty [subject-empty]
✖   type may not be empty [type-empty]

✖   found 2 problems, 0 warnings
ⓘ   Get help: https://github.com/conventional-changelog/commitlint/#what-is-commitlint

> echo 'feat: use commitlint globally' | commitlint -c false
# no output, means it works

> commitlint --print-config
{
  extends: [ '@commitlint/config-conventional' ],
  formatter: '@commitlint/format',
  .....
}

@paesrafael guessing you don’t work with any others as that’s only gonna work for your computer.

One year later, I am experiencing same issue with node v14.17.3 and npm 6.14.13 and globally installed commitlint. His reply actually helped me to focus on actual work

I tried with node version 10.15.3 and npm version 6.4.1 and now it’s working.

I am also having the same problem. I would like to use commitlint on a non-node.js project (with no package.json).

Reproduce

cat <<EOF > .commitlintrc.yaml
extends:
  - '@commitlint/config-conventional'
EOF

echo "test" | npm exec --yes\
  --package @commitlint/config-conventional\
  --package @commitlint/cli\
  commitlint

Error:

Error: Cannot find module "@commitlint/config-conventional" from "/Users/romain/Code/politician/template-repo"
    at resolveId (/Users/romain/.npm/_npx/bda3302a37d8221c/node_modules/@commitlint/resolve-extends/src/index.ts:131:14)
    at resolveConfig (/Users/romain/.npm/_npx/bda3302a37d8221c/node_modules/@commitlint/resolve-extends/src/index.ts:105:20)
    at /Users/romain/.npm/_npx/bda3302a37d8221c/node_modules/@commitlint/resolve-extends/src/index.ts:51:20
    at Array.reduce (<anonymous>)
    at loadExtends (/Users/romain/.npm/_npx/bda3302a37d8221c/node_modules/@commitlint/resolve-extends/src/index.ts:49:13)
    at resolveExtends (/Users/romain/.npm/_npx/bda3302a37d8221c/node_modules/@commitlint/resolve-extends/src/index.ts:25:19)
    at load (/Users/romain/.npm/_npx/bda3302a37d8221c/node_modules/@commitlint/load/src/load.ts:56:33)
    at async main (/Users/romain/.npm/_npx/bda3302a37d8221c/node_modules/@commitlint/cli/src/cli.ts:202:17) {
  code: 'MODULE_NOT_FOUND'
}

@mamachanko mentioned semantic-release’s plugin system works well. I would like to add that textlint’s plugin system also works:

npm exec --yes\
  --package textlint-filter-rule-allowlist\
  --package textlint-filter-rule-comments\
  --package textlint-rule-terminology\
  textlint .

I got it to work by installing packages not-exactly-globally.

You install npm packages to the user’s home directory, e.g. by following these instructions.

I have seen it work with nvm, but apparently that does not work for everyone (see @OmgImAlexiscomment below).

Thanks, that helped me!

No sure if pnpm ever worked with this or not but I know that there is at least one PR related to pnpm. Would be great to have someone who could take care of checking and testing pnpm support.

Here’s how I managed to arrive at a zero config solution (workaround):

npx --yes --package="@commitlint/cli" --package="@commitlint/config-conventional" -c "command -v commitlint | sed 's/.bin\/commitlint$//' > prefix.temp; git exclude prefix.temp; commitlint --extends \"$(cat prefix.temp)@commitlint/config-conventional\" --edit"

Requires an intermediary temp file, which I didn’t manage to get rid of…

Just to add to @politician’s great comment, the command then becomes something like: npx commitlint --from main --to HEAD --verbose --config commitlintrc.yaml.

I have to say that I’m somewhat shocked that this was so difficult to find. Does nobody outside of the JS ecosystem use commitlint?

@Kehrlann I have this issue with nvm lol

I got it to work by installing packages not-exactly-globally.

You install npm packages to the user’s home directory, e.g. by following these instructions.

I have seen it work with nvm, but apparently that does not work for everyone (see @OmgImAlexiscomment below).

Can confirm that it does not work.

fwiw semantic-release’s plugins work as expected with npx. Knowing nothing about the implementation at least it suggests that this isn’t a fundamental problem.

npx \
  --yes \
  --package semantic-release@18.0.0 \
  --package @semantic-release/exec@6.0.2 \
  -- \
    semantic-release

Yup, it would be great to use it like @knksmith57 mentioned in the second example. So having only commitlint.config.js file with

module.exports = {extends: ['@commitlint/config-conventional']}

and running:

npx -p @commitlint/config-conventional -p @commitlint/cli -c 'echo "test" |commitlint'

So the project can either have it own rules/config (if it’s included in package.json) or use default by only including the basic config file (eg. for non-nodejs projects)

Unfortunately, it’s still blocked by https://github.com/sindresorhus/global-dirs/issues/13. 😞 Apparently, its kind of a hard issue to solve. If it’s not solvable in that library, we might have to rethink if we can solve this issue without this library.

But that’s a decision where also @marionebl and @escapedcat must be involved.

I’ve tested this one, and unfortunately global-dirs@1.0.0 isn’t here (yet). Right now, resolve-global needs to be updated. Luckily, I created a PR for this, let’s hope it’s merged (& released) soon! 😄

Little status update: a PR to fix the underlying issue as described above is merged. Now we have to wait for a release and then we can test if it’s still broken or not. 😄

To quote Sindre (maker of the package):

I’ll do a new release once the other open PRs are merged.