-
-
Notifications
You must be signed in to change notification settings - Fork 1.6k
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
no-unused-modules hangs & overflows memory #1364
Comments
Similar issue here on last released version (2.17.3). Actually eslint does work but it takes an insane amount of time to complete, more than 10min on my current react-native project while downgrading the plugin to version 2.17.2 get things back to normal (~25sec) |
Could you please provide a demo repo for this case? |
@rfermann (But many thanks for the great rule, its been almost impossible to find dead code before this) |
@lukeapage thanks for the context. I guess, reading files from the src folder multiple times (once per linted file) causes your issue. The time for this task seems to increase overproportional when having more files to lint. I will try to find a solution for this issue within the next days. |
What's the current algorithm? What's its time complexity? Opening files is an expensive operation; maybe open them for reading & don't close until done linting? |
@soryy708 the rule is building up a list of all files within the specified Currently this list is getting refreshed on each lint, e.g for 1000 linted files, this list is refreshed 1000 times. One solution could be to only reread the So, instead of using this logic: // refresh list of source files
const srcFiles = resolveFiles(getSrc(src), ignoreExports)
// make sure file to be linted is included in source files
if (!srcFiles.has(file)) {
return
} we could use this logic: // refresh list of source files
// const srcFiles = resolveFiles(getSrc(src), ignoreExports)
// make sure file to be linted is included in source files
if (!srcFiles.has(file)) {
srcFiles = resolveFiles(getSrc(src), ignoreExports)
if (!srcFiles.has(file)) {
return
}
} Tests are still passing with this logic, so there is no change in the logic of the rule. Benchmarking this change brings down the execution time of this rule from more than 830ms to approx. 115ms using the files of our tests. This change takes the biggest effect, if the @lukeapage could you implement my change in your local version of this plugin and lint your project? @ljharb what do you think about my suggested change? |
Your change sounds great. Separately, I don't think we have to be concerned with the files changing during the same eslint run - so perhaps just reading it once is sufficient? |
Reading these files not only on the startup of ESLint is basically to make this rule work in code editors. When ESLint is started as a plugin in e.g. VS Code, it reads the files once and does not refresh the list of files while the plugin is running. When creating some new files, this rule will not consider the new files, possibly reporting some exports as unused although they are used in one of the new files. |
hmm, are you sure they don't invoke eslint fresh for each run? if they use something like |
@ljharb That depends on the editor, and I imagine eslint wants to support as many as possible. While a naive implementation (like you suggested) exists, I'm sure there are editors out there that will go the extra mile for a more optimal but sophisticated solution. |
I wonder if we could maybe shasum the file, and only refresh the file list when it’s changed, not just when it’s outside the src? |
I don't know how expensive this will be and if it is even more expensive than rereading the file system under some circumstances. And I never worked with checksums before, so I would need support in implementing this. Another possibility of not refreshing the file list too often could be a second // refresh list of source files
// const srcFiles = resolveFiles(getSrc(src), ignoreExports)
// make sure file to be linted is included in source files
if (filesOutsideSource.has(file)) {
return
}
if (!srcFiles.has(file)) {
srcFiles = resolveFiles(getSrc(src), ignoreExports)
if (!srcFiles.has(file)) {
filesOutsideSource.add(file)
return
}
} This way we would only refresh the file list once per file outside the source folder. |
I like that approach; that would work for long-running tasks as well, unless you’d changed the eslint config which generally requires an editor restart anyways. |
In version 2.4.0
Running with the following rule:
eslint hangs for a minute, and then node prints a dump:
The log from npm-cache is:
The text was updated successfully, but these errors were encountered: