commitlint: require() of ES Module /xxx/commitlint.config.js from /xxx/node_modules/cosmiconfig/dist/loaders.js not supported. Instead change the require of commitlint.config.js in /xxx/node_modules/cosmiconfig/dist/loaders.js to a dynamic import() which is available in all CommonJS modules.

Expected Behavior

When I upgrade commitlint to the latest version in an ESModule project and trigger the commit-msg hook, the following error will appear:

> git -c user.useConfigOnly=true commit --quiet --allow-empty-message --file -
[STARTED] Preparing lint-staged...
[COMPLETED] Preparing lint-staged...
[STARTED] Running tasks for staged files...
[STARTED] lint-staged.config.js — 76 files
[STARTED] src/**/* — 59 files
[STARTED] prettier -l -w
[COMPLETED] prettier -l -w
[COMPLETED] src/**/* — 59 files
[COMPLETED] lint-staged.config.js — 76 files
[COMPLETED] Running tasks for staged files...
[STARTED] Applying modifications from tasks...
[COMPLETED] Applying modifications from tasks...
[STARTED] Cleaning up temporary files...
[COMPLETED] Cleaning up temporary files...
/xxx/node_modules/cosmiconfig/dist/loaders.js:32
    if (parseJson === undefined) {
                                                          ^

Error [ERR_REQUIRE_ESM]: require() of ES Module /xxx/commitlint.config.js from /xxx/node_modules/cosmiconfig/dist/loaders.js not supported.
Instead change the require of commitlint.config.js in /xxx/node_modules/cosmiconfig/dist/loaders.js to a dynamic import() which is available in all CommonJS modules.
    at module.exports (/xxx/node_modules/import-fresh/index.js:32:59)
    at loadJsSync (/xxx/node_modules/cosmiconfig/dist/loaders.js:17:12)
    at #loadConfiguration (/xxx/node_modules/cosmiconfig/dist/Explorer.js:92:30)
    at #readConfiguration (/xxx/node_modules/cosmiconfig/dist/Explorer.js:77:80)
    at async search (/xxx/node_modules/cosmiconfig/dist/Explorer.js:44:40)
    at async Explorer.search (/xxx/node_modules/cosmiconfig/dist/Explorer.js:71:20)
    at async loadConfig (/xxx/node_modules/@commitlint/load/lib/utils/load-config.js:45:19)
    at async load (/xxx/node_modules/@commitlint/load/lib/load.js:19:20)
    at async main (/xxx/node_modules/@commitlint/cli/lib/cli.js:189:20) {
  code: 'ERR_REQUIRE_ESM',
  filepath: '/xxx/commitlint.config.js'
}

Node.js v18.17.0
husky - commit-msg hook exited with code 1 (error)

package.json

{
  "type": "module",
  "devDependencies": {
    "@commitlint/cli": "^18.4.1",
    "@commitlint/config-conventional": "^18.4.0"
  }
}

commit-msg

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

npx --no-install commitlint --edit "$1"

commitlint.config.js

export default {
  extends: ["@commitlint/config-conventional"],
};

cosmiconfig version

% npm list cosmiconfig

├─┬ @commitlint/cli@18.4.1
│ └─┬ @commitlint/load@18.4.1
│   ├─┬ cosmiconfig-typescript-loader@5.0.0
│   │ └── cosmiconfig@8.3.6 deduped
│   └── cosmiconfig@8.3.6
└─┬ @svgr/rollup@8.1.0
  ├─┬ @svgr/core@8.1.0
  │ └── cosmiconfig@8.3.6 deduped
  └─┬ @svgr/plugin-svgo@8.1.0
    └── cosmiconfig@8.3.6 deduped

Current Behavior

No response

Affected packages

  • cli
  • core
  • prompt
  • config-angular

Possible Solution

No response

Steps to Reproduce

1. First step
2. Second step

Context

No response

commitlint --version

@commitlint/cli@18.4.1

git --version

git version 2.39.2 (Apple Git-143)

node --version

v18.17.0

About this issue

  • Original URL
  • State: closed
  • Created 8 months ago
  • Comments: 15 (9 by maintainers)

Most upvoted comments

The resolve-extends issue might be resolved by https://github.com/conventional-changelog/commitlint/issues/3705; is that updating the entire package to use ESM?

That issue is just a reminder that commitlint in general should be switched to ESM. I opened this up because we already have dep updates being blocked by this (at least I think that’s the case).

Unfortunately, this specific case can’t be covered in the Jest tests; trying to use the dynamic import in node < 20.8.0 will cause a seg fault and prevent the test from finishing. But I was able to verify the change manually with linking to another repo.

So people who use v20 should use at least use 20.8? Sounds good to me. CI would pass, right?

I also noticed that the resolve extends package doesn’t do well with ESM since it uses require to load additional extended config, but I wasn’t able to get something working for that. I can make a new issue to address it since it’s unrelated.

Is this part of or just #3705 maybe?

Thanks for all your work!

Technically the async loaders will work in source code with other node versions, but for the purposes of the tests, the sync loaders should be used (this was also the previous behavior because before cosmiconfig 8.2.0, the async loaders used commonJS like the sync loaders do now). I’ve set up the tests to skip the ones that would cause Jest to crash.

The resolve-extends issue might be resolved by #3705; is that updating the entire package to use ESM? There may be similar test issues as the ones seen in the cosmiconfig update as a heads up.

@escapedcat @pfdgithub I’d like to simplify the original implementation for this - basically use the async loaders if dynamic await is supported (node > 20.8.0) OR config is an ESM module application. Otherwise, use the sync loaders. I almost have some additional tests ready to push to cover additional cases, and code changes are minor, similar to the PR. Unfortunately, this specific case can’t be covered in the Jest tests; trying to use the dynamic import in node < 20.8.0 will cause a seg fault and prevent the test from finishing. But I was able to verify the change manually with linking to another repo.

I also noticed that the resolve extends package doesn’t do well with ESM since it uses require to load additional extended config, but I wasn’t able to get something working for that. I can make a new issue to address it since it’s unrelated.

Sorry, PR3772 used the wrong email address

I guess so, yes. 18.3 working for you?

Strangely, I deleted the node_modules and package-lock.json files and downgraded to versions @commitlint/cli@18.2.0 and @commitlint/config-conventional@18.1.0, which were the normal versions I used before, but I still get the error.

% npm list @commitlint/cli

└── @commitlint/cli@18.2.0

% npm list @commitlint/config-conventional

└── @commitlint/config-conventional@18.1.0

% npm list cosmiconfig                                                                          
├─┬ @commitlint/cli@18.2.0
│ └─┬ @commitlint/load@18.4.1
│   ├─┬ cosmiconfig-typescript-loader@5.0.0
│   │ └── cosmiconfig@8.3.6 deduped
│   └── cosmiconfig@8.3.6
└─┬ @svgr/rollup@8.1.0
  ├─┬ @svgr/core@8.1.0
  │ └── cosmiconfig@8.3.6 deduped
  └─┬ @svgr/plugin-svgo@8.1.0
    └── cosmiconfig@8.3.6 deduped

The problem seems to be with @commitlint/load