Problem with eslint extends

Created on 5 April 2024, 3 months ago
Updated 25 June 2024, 3 days ago

Problem/Motivation

Projects that their own .eslintrc.json file may be extending other pre-defined named configurations, not just extending by path to the file. The Drupal documentation for ESLint β†’ has the following (which incidently has mal-formed json syntax!)

{
  extends: [ 
    "drupal" 
  ],
  "globals": {
    "ga": true
  }
}

But when trying to use this the log gives
ESLint couldn't find the config "drupal" to extend from. Please check that the name of the config is correct.

The G2 project πŸ“Œ Fix ESLint on CI Active has js/.eslintrc.json containing

{
  "extends": [
    "../../../../core/.eslintrc.json",
    "airbnb-base",
    "airbnb-typescript/base",
    "prettier"
  ],

This produces ESLint couldn't find the config "airbnb-base" to extend from.

Steps to reproduce

Proposed resolution

Testing

To test MR 223 use:

include:
  - project: issue/gitlab_templates-3438843
    ref: 3438843-eslint-extends

Remaining tasks

User interface changes

API changes

Data model changes

πŸ› Bug report
Status

Needs work

Component

gitlab-ci

Created by

πŸ‡¬πŸ‡§United Kingdom jonathan1055

Live updates comments and jobs are added and updated live.
Sign in to follow issues

Merge Requests

Comments & Activities

  • Issue created by @jonathan1055
  • πŸ‡¬πŸ‡§United Kingdom jonathan1055

    We can also test this with ckeditor5_paste_filter which has a simpler .eslintrc.json compared to G2.

    We have a dedicated issue and MR for gitlab testing
    πŸ“Œ [ignore] Test gitlab phpunit job Active
    https://git.drupalcode.org/project/ckeditor5_paste_filter/-/merge_reques...

  • πŸ‡¨πŸ‡¦Canada m4olivei Grimsby, ON

    We've noticed this in the navigation module as well. In our case we have a full copy of the core eslint configuration files, with small adjustments on top. We get the following error in CI:

    Oops! Something went wrong! :(
    ESLint: 8.55.0
    ESLint couldn't find the config "airbnb-base" to extend from. Please check that the name of the config is correct.
    The config "airbnb-base" was referenced from the config file in "/builds/project/navigation/web/modules/custom/navigation/.eslintrc.json".

    It's unclear what we can do to remedy this. If I run it from our module directory, all is well πŸ˜•.

  • πŸ‡ͺπŸ‡ΈSpain fjgarlin

    Thanks for sharing @m4olivei. I think that that's a great example for us to work on in this issue, as the reported problem is the same. If you are ok waiting on us to fix it, we can help you with that. Is there an existing issue in your module for this already? If there is please link it, if there isn't we can create it.

  • πŸ‡¨πŸ‡¦Canada m4olivei Grimsby, ON

    Thanks for the quick response.

    I was working in πŸ“Œ Cleanup all the code quality remaining issues Fixed when I relaized we were running into this. That is a general issue to clean up our coding standards job. However, I've spun off an issue specific to ESlint to unblock that issue, and give us a dedicated space to collaborate on: πŸ› Eslint is failing with ESLint couldn't find the config "airbnb-base" to extend from Active .

  • πŸ‡ͺπŸ‡ΈSpain fjgarlin

    Oh great! Thanks for isolating the issue. This makes things much easier to work on.

  • πŸ‡¬πŸ‡§United Kingdom jonathan1055

    That's a great find. I might try to ask Brian Perry to come here and help on this issue.

  • πŸ‡ΊπŸ‡ΈUnited States brianperry

    Thanks for summoning me :) Will try to take a look at this and see if I can provide any suggestions.

  • πŸ‡ΊπŸ‡ΈUnited States brianperry

    I think there are a couple of different related problems here. The main one is that while the eslint job will install node modules defined in core's package.json (this happens using yarn in the composer-base job I believe,) it doesn't install node dependencies from the module project's package.json. So given this .eslintrc

    {
      "extends": [
        "drupal"
      ]
    }

    You'll always end up with "ESLint couldn't find the config "drupal" to extend from". The Drupal eslint docs β†’ mention this in a later paragraph, but extending 'drupal' requires first installing https://www.npmjs.com/package/eslint-config-drupal. Core doesn't have this dependency, so the contrib project will have installed it. But project node dependencies aren't installed by the Gitlab eslint job currently.

    So why are people seeing "ESLint couldn't find the config "airbnb-base" to extend from"? Core does have this as a dependency. It is essentially the same problem. From https://eslint.org/docs/v8.x/use/configure/configuration-files#extending...

    Relative paths and shareable config names in an extends property are resolved from the location of the config file where they appear.

    In this case, that is the contrib project directory, which won't have this dependency installed. And this is even considering that the CI job uses '--resolve-plugins-relative-to=$CI_PROJECT_DIR/$_WEB_ROOT/core' Unfortunately the extends property ignores that flag when resolving.

    So without installing additional dependencies, you need to explicitly reference the plugin in Core's dependences (similar to how the CI job runs eslint from core's node_modules/bin) This .eslintrc should work:

    {
      "extends": [
        "../../../core/node_modules/eslint-config-airbnb-base/index.js"
      ]
    }

    But projects that rely on dependencies that aren't in core will be out of luck. I think the only way to resolve that would be to install project node dependencies during the eslint job. I'll try to take a quick look to see if I can open an MR with initial changes for that.

  • Pipeline finished with Failed
    15 days ago
    Total: 54s
    #198199
  • Status changed to Needs review 15 days ago
  • πŸ‡ΊπŸ‡ΈUnited States brianperry

    I opened a draft MR that installs project dependencies via yarn at the start of the eslint job. I didn't test this. If someone could provide guidance on how I could test this branch with a contrib project, I'd be happy to do that with same_page_preview.

    Short term, we should probably persist node_modules between jobs to speed up the yarn install. I'll leave that one to someone more experienced with the inner working of these CI templates (I assume something similar is already happening for composer.)

    Longer term, we could:
    * Detect if a package.json exists rather than blindly running yarn install.
    * Use the package manager configured for the project (npm, pnpm, etc) rather than always using yarn.

    But my guess is that this one line change alone could resolve many of the problems reported in this issue.

  • πŸ‡¬πŸ‡§United Kingdom jonathan1055

    This is great analysis, thank you. Lots of good background, and several things to try.

    To test the MR, in the contrib project's .gitlab-ci.yml you need to change the values of the included project and ref as follows:

    include:
      - project: issue/gitlab_templates-3453102
        ref: 3438843-eslint-extends
    
  • πŸ‡¬πŸ‡§United Kingdom jonathan1055

    Fixed typo in project

  • Pipeline finished with Success
    14 days ago
    Total: 52s
    #198673
  • Status changed to Needs work 12 days ago
  • πŸ‡¬πŸ‡§United Kingdom jonathan1055

    I have tested MR223 on ckeditor5_paste_filter β†’ using MR7 from πŸ“Œ [ignore] Test gitlab phpunit job Active

    The project has a simple .eslintrc.json

    {
      "extends": [
        "drupal"
      ],
      "root": true
    }
    

    Here's the existing eslint job says ESLint couldn't find the config "drupal" to extend from
    https://git.drupalcode.org/issue/ckeditor5_paste_filter-3433169/-/jobs/1...

    Testing with MR223 it still failed but the error was different: ESLint couldn't find the plugin "eslint-plugin-jsx-a11y"
    https://git.drupalcode.org/issue/ckeditor5_paste_filter-3433169/-/jobs/1...

    I don't know how to interpret this difference, but hoping the test here helps to make some progress.

  • πŸ‡¨πŸ‡¦Canada Cottser

    I just want to mention that https://www.npmjs.com/package/eslint-config-drupal hasn't been updated since October 15, 2020 but is still recommended in official documentation: https://www.drupal.org/node/1955232 β†’

    https://github.com/theodoreb/eslint-config-drupal/issues/6 seems relevant, because eslint-config-drupal is bringing in dependencies that aren't in core (such as eslint-plugin-jsx-a11y).

  • πŸ‡¨πŸ‡¦Canada Cottser

    Reviewing other comments here, maybe what I should do is adopt https://www.npmjs.com/package/eslint-plugin-drupal-contrib and we should adopt others to do the same?

  • πŸ‡¨πŸ‡¦Canada Cottser

    Having said that, to get this working with eslint-config-drupal, might it just be a matter of running eslint from the project directory rather than core?

  • πŸ‡¬πŸ‡§United Kingdom jonathan1055

    Thanks for the above info and links.
    in #18 you asked

    might it just be a matter of running eslint from the project directory rather than core?

    Just wondering which 'project directory' you mean? ESLint is being run in $CI_PROJECT_DIR/$_WEB_ROOT/modules/custom/$CI_PROJECT_NAME Previously it was running in the default top-level $CI_PROJECT_DIR but was changed in #3359327: ESLINT does not respect the 'ignore' files β†’

  • πŸ‡¨πŸ‡¦Canada Cottser

    Thanks for following up! I see what you mean, the current working directory in that CI job is indeed the module (what I'm calling project in the Drupal.org sense because it could be a theme, or other) directory.

    I was referring to this command:

    $ $CI_PROJECT_DIR/$_WEB_ROOT/core/node_modules/.bin/eslint --no-error-on-unmatched-pattern --ignore-pattern="*.es6.js" --resolve-plugins-relative-to=$CI_PROJECT_DIR/$_WEB_ROOT/core --ext=.js,.yml --format=junit --output-file=$CI_PROJECT_DIR/junit.xml $_ESLINT_EXTRA . || EXIT_CODE_FILE=$?

    What I was suggesting is: Although it would only work with the correct dependencies in place in the module's directory, would running eslint from the node_modules of the module help?

  • πŸ‡¨πŸ‡¦Canada Cottser

    Specifically, and I'm not sure the quickest way to test this myself, but something like:

    $ $CI_PROJECT_DIR/$_WEB_ROOT/modules/custom/$CI_PROJECT_NAME/node_modules/.bin/eslint --no-error-on-unmatched-pattern --ignore-pattern="*.es6.js" --resolve-plugins-relative-to=$CI_PROJECT_DIR/$_WEB_ROOT/core --ext=.js,.yml --format=junit --output-file=$CI_PROJECT_DIR/junit.xml $_ESLINT_EXTRA . || EXIT_CODE_FILE=$?

  • πŸ‡¬πŸ‡§United Kingdom jonathan1055

    Thanks star-szr, I just tried your idea in a custom eslint step, and it failed because there is no .bin in that folder. The newly created node_modules just contains:

    $ cd node_modules && pwd && ls -la || true
    /builds/project/scheduler/web/modules/custom/scheduler/node_modules
    total 4
    drwxr-xr-x 2 root root  60 Jun 22 19:04 .
    drwxr-xr-x 3 root root 860 Jun 22 19:04 ..
    -rw-r--r-- 1 root root 184 Jun 22 19:04 .yarn-integrity
    
  • πŸ‡¨πŸ‡¦Canada Cottser

    Thanks @jonathan1055! If I run `yarn install` from https://git.drupalcode.org/project/ckeditor5_paste_filter then I do get a node_modules/.bin with eslint.

    I am mostly guessing here but wondering if we should have logic to check for node_modules/.bin/eslint inside the module/project and prefer to use that eslint (presumably it will have an easier time resolving dependencies within its own node_modules like eslint-plugin-jsx-a11y), falling back to the core eslint which should be fine for modules/projects that don't bring in a specific eslint via package.json.

Production build 0.69.0 2024