Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Bug: Imports fail in flat config file when ESLint installed elsewhere #18465

Closed
1 task
adamchainz opened this issue May 17, 2024 · 6 comments
Closed
1 task
Labels
bug ESLint is working incorrectly repro:needed

Comments

@adamchainz
Copy link

adamchainz commented May 17, 2024

Environment

Node version: v20.12.0
npm version: 10.8.0
Local ESLint version: v9.2.0
Global ESLint version: n/a
Operating System: macOS

What parser are you using?

Default (Espree)

What did you do?

An empty directory with just this eslint.config.js:

const js = require("@eslint/js");

module.exports = [
  js.configs.recommended,
]

Run the CLI with npx as documented:

$ npx eslint

What did you expect to happen?

The require / import statements resolve. @eslint/js is installed with ESLint:

"@eslint/js": "9.2.0",
.

What actually happened?

Crash:

$ npx eslint
Oops! Something went wrong! :(

ESLint: 9.2.0

Error: Cannot find module '@eslint/js'
Require stack:
- /Users/chainz/tmp/test-eslint/eslint.config.js
    at Module._resolveFilename (node:internal/modules/cjs/loader:1143:15)
    at Module._load (node:internal/modules/cjs/loader:984:27)
    at Module.require (node:internal/modules/cjs/loader:1231:19)
    at require (node:internal/modules/helpers:179:18)
    at Object.<anonymous> (/Users/chainz/tmp/test-eslint/eslint.config.js:1:12)
    at Module._compile (node:internal/modules/cjs/loader:1369:14)
    at Module._extensions..js (node:internal/modules/cjs/loader:1427:10)
    at Module.load (node:internal/modules/cjs/loader:1206:32)
    at Module._load (node:internal/modules/cjs/loader:1022:12)
    at cjsLoader (node:internal/modules/esm/translators:366:17)

The way ESLint loads the config file means that its import statements aren’t resolved.

(The bug also occurs with ESM config in eslint.config.mjs, with a slightly different error message: Cannot find package '@eslint/js' imported from /Users/chainz/tmp/test-eslint/eslint.config.mjs.)

Link to Minimal Reproducible Example

Open https://stackblitz.com/edit/stackblitz-starters-jycfg3?file=eslint.config.js and run npx eslint:

Screenshot 2024-05-20 at 13-29-33 eslint #18465 - StackBlitz

Participation

  • I am willing to submit a pull request for this issue.

Additional comments

It seems that to use flat config, you must install ESLint in the same directory as configuration? If so, that really breaks using tool managers—I found this out when using ESLint under pre-commit, which manages tools in its own directory outside of your project.

@adamchainz adamchainz added bug ESLint is working incorrectly repro:needed labels May 17, 2024
@adamchainz adamchainz changed the title Bug: Flat config file imports fail Bug: Imports fail in flat config file when ESLint installed elsewhere May 17, 2024
@nzakas
Copy link
Member

nzakas commented May 17, 2024

As the issue template says, we can't investigate any bug reports without a repro case. If you can please create a StackBlitz showing this behavior we can take a look.

@adamchainz
Copy link
Author

Link: https://stackblitz.com/edit/stackblitz-starters-jycfg3?file=eslint.config.js

Screenshot of repro on stackblitz:

Screenshot 2024-05-20 at 13-29-33 eslint #18465 - StackBlitz

@nzakas
Copy link
Member

nzakas commented May 20, 2024

Ah okay, I see what's happening.

Yes, you still need to install @eslint/js into your project manually (as you would any other import that you have in a config file). Even though @eslint/js is a dependency of ESLint, that doesn't mean you can use it directly without installing it first.

@nzakas nzakas closed this as not planned Won't fix, can't repro, duplicate, stale May 29, 2024
@sritchie
Copy link

@nzakas, I have hit this issue as well when trying to use eslint with https://pre-commit.ci/. The issue here is that pre-commit.ci installs eslint "globally" and won't run npm install. The plugin takes a list of extra dependencies and installs them into npm's virtual environment. If eslint used this global node_modules folder all would work, but eslint fails to find any dependencies in the local folder on pre-commit.ci because npm install was never run.

Is there some way to tell eslint to look for dependencies elsewhere? I know that in normal use you don't want to support this, but I think for a CI environment being able to somehow add another source of node_modules is essential.

It seems that eslint used to take a --resolve-plugins-relative-to flag, but no longer does; is there some way to get behavior like this back, even if's hacky?

Thank you!

@nzakas
Copy link
Member

nzakas commented May 31, 2024

@sritchie use NODE_PATH

@sritchie
Copy link

@nzakas I tried this again and confirmed that NODE_PATH is set correctly. I created a reproduction here with details:

https://github.com/sritchie/eslint-repro

Here are the details, also in the repro README. (The implicit question here is, is this

  • a bug,
  • working as expected, and I'm missing some obvious detail, or
  • am I doing something that's not allowed, by trying to import "globals" or other dependencies in eslint.config.mjs?

In the repro, .pre-commit-config.yaml looks like this:

repos:
  - repo: local
    hooks:
    - id: eslint
      name: eslint
      language: node
      additional_dependencies:
      - eslint@9.3.0
      - globals@15.3.0
      entry: ./run_eslint.sh

This will install a node environment with the listed "additional dependencies"
(installed via npm install), and then trigger the entry point.

I used a shell script here, run_eslint.sh, so I could show that the
environment variables are set correctly, and that the NODE_PATH does indeed
have eslint and globals installed into it.

However, when I either run the script explicitly:

./run_eslint.sh

Or run it through pre-commit:

pre-commit run eslint --all

I see the following output:

NODE_PATH:
/Users/sritchie/.cache/pre-commit/repoxz3rawvg/node_env-default/lib/node_modules
NPM_CONFIG_PREFIX:
/Users/sritchie/.cache/pre-commit/repoxz3rawvg/node_env-default
contents of NODE_PATH:
corepack eslint globals npm pre_commit_placeholder_package

Oops! Something went wrong! :(

ESLint: 9.3.0

Error [ERR_MODULE_NOT_FOUND]: Cannot find package 'globals' imported from /Users/sritchie/code/mit/eslint-repro/eslint.config.mjs
Did you mean to import "globals/index.js"?
    at packageResolve (node:internal/modules/esm/resolve:841:9)
    at moduleResolve (node:internal/modules/esm/resolve:914:18)
    at defaultResolve (node:internal/modules/esm/resolve:1119:11)
    at ModuleLoader.defaultResolve (node:internal/modules/esm/loader:542:12)
    at ModuleLoader.resolve (node:internal/modules/esm/loader:511:25)
    at ModuleLoader.getModuleJob (node:internal/modules/esm/loader:241:38)
    at ModuleJob._link (node:internal/modules/esm/module_job:126:49)

telling me that NODE_PATH is set to a directory containing globals, but
eslint can't find the import in eslint.config.mjs.

I would have expected that this eslint.config.mjs should work fine, given that
globals is installed:

import globals from "globals";

export default [
  {
    languageOptions: { globals: globals.browser },
    files: ["src/**/*.js"],
  },
];

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
bug ESLint is working incorrectly repro:needed
Projects
Status: Complete
Development

No branches or pull requests

3 participants