import-js / eslint-plugin-import

ESLint plugin with rules that help validate proper imports.
MIT License
5.45k stars 1.56k forks source link

eslint performance drops ~7x when upgrading from `2.26.0` to `2.27.5` #2705

Closed LucasLemanowicz closed 5 days ago

LucasLemanowicz commented 1 year ago

I was looking at upgrading our eslint-plugin-import package from 2.26.0 to 2.27.5 but when I run eslint after the upgrade, our lint time goes up from ~90 seconds to ~600 seconds.

Relevant sections from our package.json:

{
  "scripts": {
    "lint": "eslint .",
  },
  "dependencies": {
    "next": "^12.3.4",
  },
  "devDependencies": {
    "@graphql-codegen/add": "^4.0.0",
    "@graphql-codegen/cli": "^3.0.0",
    "@graphql-codegen/introspection": "^3.0.0",
    "@graphql-codegen/near-operation-file-preset": "^2.5.0",
    "@graphql-codegen/typescript": "^3.0.0",
    "@graphql-codegen/typescript-operations": "^3.0.0",
    "@graphql-codegen/typescript-urql": "^3.7.3",
    "@graphql-eslint/eslint-plugin": "^3.15.0",
    "@typescript-eslint/eslint-plugin": "^5.50.0",
    "@typescript-eslint/parser": "^5.50.0",
    "eslint": "^8.33.0",
    "eslint-config-next": "^12.3.4",
    "eslint-config-prettier": "^8.6.0",
    "eslint-plugin-implicit-dependencies": "^1.1.1",
    "eslint-plugin-import": "^2.27.5",
    "eslint-plugin-prettier": "^4.2.1",
    "eslint-plugin-simple-import-sort": "^10.0.0",
    "eslint-plugin-testing-library": "^5.10.0",
    "prettier": "^2.8.3",
    "typescript": "^4.9.5",
  }
}

Here's an excerpt of a run of eslint --debug .

2.26.0:

  eslintrc:ignore-pattern Check {
  filePath: '/Users/(...)/src/pages/contact-us.tsx',
  dot: false,
  relativePath: 'src/pages/contact-us.tsx',
  result: false
} +8ms
  eslint:file-enumerator Yield: contact-us.tsx +0ms
  eslintrc:cascading-config-array-factory Load config files for /Users/(...)/src/pages. +8ms
  eslintrc:cascading-config-array-factory Cache hit: /Users/(...)/src/pages. +0ms
  eslint:cli-engine Lint /Users/(...)/src/pages/contact-us.tsx +8ms
  eslint:linter Linting code for /Users/(...)/src/pages/contact-us.tsx (pass 1) +0ms
  eslint:linter Verify +5ms
  eslint:linter With ConfigArray: /Users/(...)/src/pages/contact-us.tsx +0ms
  eslint:linter Parsing: /Users/(...)/src/pages/contact-us.tsx +1ms
  eslint:linter Parsing successful: /Users/(...)/src/pages/contact-us.tsx +1ms
  eslint:linter Scope analysis: /Users/(...)/src/pages/contact-us.tsx +0ms
  eslint:linter Scope analysis successful: /Users/(...)/src/pages/contact-us.tsx +0ms
  eslint:linter Generating fixed text for /Users/(...)/src/pages/contact-us.tsx (pass 1) +58ms
  eslint:source-code-fixer Applying fixes +65ms
  eslint:source-code-fixer shouldFix parameter was false, not attempting fixes +0ms
  eslintrc:ignore-pattern Check {
  filePath: '/Users/(...)/src/pages/historical-rates.tsx',
  dot: false,
  relativePath: 'src/pages/historical-rates.tsx',
  result: false
} +65ms
  eslint:file-enumerator Yield: historical-rates.tsx +65ms
  eslintrc:cascading-config-array-factory Load config files for /Users/(...)/src/pages. +65ms
  eslintrc:cascading-config-array-factory Cache hit: /Users/(...)/src/pages. +0ms
  eslint:cli-engine Lint /Users/(...)/src/pages/historical-rates.tsx +65ms
  eslint:linter Linting code for /Users/(...)/src/pages/historical-rates.tsx (pass 1) +0ms
  eslint:linter Verify +0ms
  eslint:linter With ConfigArray: /Users/(...)/src/pages/historical-rates.tsx +0ms
  eslint:linter Parsing: /Users/(...)/src/pages/historical-rates.tsx +0ms
  eslint:linter Parsing successful: /Users/(...)/src/pages/historical-rates.tsx +2ms
  eslint:linter Scope analysis: /Users/(...)/src/pages/historical-rates.tsx +0ms
  eslint:linter Scope analysis successful: /Users/(...)/src/pages/historical-rates.tsx +0ms
  eslint:linter Generating fixed text for /Users/(...)/src/pages/historical-rates.tsx (pass 1) +68ms
  eslint:source-code-fixer Applying fixes +71ms
  eslint:source-code-fixer shouldFix parameter was false, not attempting fixes +0ms

2.27.5:

  eslintrc:ignore-pattern Check {
  filePath: '/Users/(...)/src/pages/contact-us.tsx',
  dot: false,
  relativePath: 'src/pages/contact-us.tsx',
  result: false
} +32ms
  eslint:file-enumerator Yield: contact-us.tsx +1ms
  eslintrc:cascading-config-array-factory Load config files for /Users/(...)/src/pages. +32ms
  eslintrc:cascading-config-array-factory Cache hit: /Users/(...)/src/pages. +0ms
  eslint:cli-engine Lint /Users/(...)/src/pages/contact-us.tsx +32ms
  eslint:linter Linting code for /Users/(...)/src/pages/contact-us.tsx (pass 1) +1ms
  eslint:linter Verify +0ms
  eslint:linter With ConfigArray: /Users/(...)/src/pages/contact-us.tsx +0ms
  eslint:linter Parsing: /Users/(...)/src/pages/contact-us.tsx +0ms
  eslint:linter Parsing successful: /Users/(...)/src/pages/contact-us.tsx +6ms
  eslint:linter Scope analysis: /Users/(...)/src/pages/contact-us.tsx +0ms
  eslint:linter Scope analysis successful: /Users/(...)/src/pages/contact-us.tsx +0ms
  eslint:linter Generating fixed text for /Users/(...)/src/pages/contact-us.tsx (pass 1) +20s
  eslint:source-code-fixer Applying fixes +20s
  eslint:source-code-fixer shouldFix parameter was false, not attempting fixes +0ms
  eslintrc:ignore-pattern Check {
  filePath: '/Users/(...)/src/pages/historical-rates.tsx',
  dot: false,
  relativePath: 'src/pages/historical-rates.tsx',
  result: false
} +20s
  eslint:file-enumerator Yield: historical-rates.tsx +20s
  eslintrc:cascading-config-array-factory Load config files for /Users/(...)/src/pages. +20s
  eslintrc:cascading-config-array-factory Cache hit: /Users/(...)/src/pages. +0ms
  eslint:cli-engine Lint /Users/(...)/src/pages/historical-rates.tsx +20s
  eslint:linter Linting code for /Users/(...)/src/pages/historical-rates.tsx (pass 1) +15ms
  eslint:linter Verify +0ms
  eslint:linter With ConfigArray: /Users/(...)/src/pages/historical-rates.tsx +0ms
  eslint:linter Parsing: /Users/(...)/src/pages/historical-rates.tsx +4ms
  eslint:linter Parsing successful: /Users/(...)/src/pages/historical-rates.tsx +61ms
  eslint:linter Scope analysis: /Users/(...)/src/pages/historical-rates.tsx +0ms
  eslint:linter Scope analysis successful: /Users/(...)/src/pages/historical-rates.tsx +0ms
  eslint:linter Generating fixed text for /Users/(...)/src/pages/historical-rates.tsx (pass 1) +3s
  eslint:source-code-fixer Applying fixes +3s
  eslint:source-code-fixer shouldFix parameter was false, not attempting fixes +0ms

Happy to provide additional logs or configs in case it would be helpful in reproing and debugging.

ljharb commented 1 year ago

Hopefully #2755 and #2756 will help, in the next release of eslint-module-utils and eslint-plugin-import.

LucasLemanowicz commented 1 year ago

Thanks @ljharb - any idea when the next release will be cut?

(btw - looks like while the code changes for #2755 merged in to main, I can't seem to find the corresponding CHANGELOG entry)

ljharb commented 1 year ago

Nope, no idea, but hopefully soon.

2755 only changed eslint-module-utils, and that's been published.

LucasLemanowicz commented 10 months ago

I upgraded my NextJS version which also upgraded eslint-plugin-import from 2.26.0 to 2.28.1 and I am seeing approximately 3x increase in linting time on Vercel. Pinning the eslint-plugin-import to 2.26.0 reduced it back down to normal, as seen in the screenshots here:

Screenshot 2023-10-19 at 6 29 49 PM

main branch on 2.26.0 (focus on time since previous line):

Screenshot 2023-10-19 at 6 33 42 PM

next-13.5 branch after package was updated to 2.28.1 (focus on time since previous line):

Screenshot 2023-10-19 at 6 35 24 PM

next-13.5 branch after pinning package back to 2.26.0 (focus on time since previous line):

Screenshot 2023-10-19 at 6 36 39 PM

Any idea what could be going on?

LucasLemanowicz commented 10 months ago

I tried upgrading to 2.29.0 and still seeing performance issues. It seems like it might be related to a bew dependency on eslint-import-resolver-typescript. Attaching a dump of the logs when running eslint --debug on a single file on 2.26.0 and 2.29.0:

2.26.0.txt 2.29.0.txt

The main time differences are below. This is 2.26.0:

eslint:linter Generating fixed text for /Users/(...)/src/pages/contact-us.tsx (pass 1) +2s
(...)
eslint:file-enumerator Complete iterating files: ["./src/pages/contact-us.tsx"] +7s

and this is 2.29.0:

eslint:linter Generating fixed text for /Users/(...)/src/pages/contact-us.tsx (pass 1) +13s
(...)
eslint:file-enumerator Complete iterating files: ["./src/pages/contact-us.tsx"] +17s

There's a new dependency on eslint-import-resolver-typescript, which might be related to the slowness above, as there seem to be a few issues about performance on that repo's issue tracker: https://github.com/import-js/eslint-import-resolver-typescript/issues?q=is%3Aissue+performance, including one open issue showing that perf has degraded as of 3.1.0: https://github.com/import-js/eslint-import-resolver-typescript/issues/176

kthksgy commented 10 months ago

I have updated from 2.26.0 to 2.28.x and the same problem occurred to me. Also, I found a new circular import warning which did not occur in 2.26.0.

After I have turned off import/no-cycle rule, my ESLint's performance has been good enough (almost same performance as 2.26.0). I also discovered that limiting the depth of circular import check leads to improved performance.

/** .eslintrc.cjs */
// All but the most important parts have been omitted.
module.exports = {
  rules: {
    'import/no-cycle': 'off', // Turned off to prevent circular import check.
  }
}

This may not be a solution for those who require import/no-cycle rule, but I hope it can be of some help.

soryy708 commented 5 days ago

Try 2.30.0, an optimization to no-cycle was added.

This issue looks very similar to:

ljharb commented 5 days ago

Closing; please file a new issue if you're still seeing perf issues in v2.30+.