fork-ts-checker-webpack-plugin: Strange "Cannot find module" error when using with TSLint and the no-unused-variable rule

This is a very weird bug which took me hours to whittle down to a minimal example, so I hope it’s of use. Steps to reproduce:

  1.  git clone https://github.com/pelotom/fork-ts-checker-bug
     cd fork-ts-checker-bug
     npm install
     npm start
    
  2. Everything should compile fine on the first run. Now open the file foo.ts, add a newline or some other innocuous change, and save it.
  3. Now there is an error in a completely different file:
    ERROR in /Users/tom/code/fork-ts-checker-bug/index.ts
    (1,25): Cannot find module 'moment'.
    

What the hey!?

Some observations:

  • Undoing the change has no effect; the error remains. However modifying index.ts and saving it fixes the problem somehow.
  • Killing the watch process and restarting fixes the problem; first builds always work
  • The problem only occurs with the no-unused-variable TSLint rule enabled
  • If another library besidesmoment is imported in index.ts, it may or may not exhibit the problem. For example, typestyle exhibits the problem but rxjs doesn’t. I’m not sure what the commonality is among packages that run afoul of this.

About this issue

  • Original URL
  • State: closed
  • Created 7 years ago
  • Reactions: 33
  • Comments: 18 (6 by maintainers)

Most upvoted comments

@andrewbranch I changed the title

realized the project I was working with extended a few different configs, so I put no-unused-variable in as false and its working.

I stepped through the code and it looks like it happens for packages that specify typings in their package.json. Because no-unused-variable pollutes the module resolution cache in SourceFile instances, if they are reused after linting, and if the set of changed files does not cause typescript to re-resolve these packages, it fails to resolve them altogether.

A quick workaround is to do this:

diff --git src/IncrementalChecker.ts src/IncrementalChecker.ts
index 56fdb70..ca69bda 100644
--- src/IncrementalChecker.ts
+++ src/IncrementalChecker.ts
@@ -115,6 +115,11 @@ class IncrementalChecker {
       return files.getData(filePath).source;
     };
 
+    // after linting, cached `SourceFile` instances may not be safely reused
+    files.keys().forEach(filePath => {
+      files.remove(filePath);
+    });
+
     return ts.createProgram(
       programConfig.fileNames,
       programConfig.options,

But obviously this has some perf impacts. I’m not sure how this can be properly fixed.