fork-ts-checker-webpack-plugin: types.ts files do not trigger rebuild in webpack-dev-server

First - thanks for the plugin and associated speed improvements!

One issue I’ve seen is that webpack-dev-server will not rebuild when a change is made in a source file that will not emit js. For example, if I have a types.js file that exports nothing but types/interfaces, and I make a change to that file that introduces a type error, I will not see a warning for that error until I change a file that does emit js. Here is an example:

  // types.ts
  export interface Person {
    name:string;
  };

  // mainEntry.ts
  import {Person} from 'types';
  const sally:Person = {name: 'Sally'};

Changes to mainEntry.ts will trigger a rebuild, but updating types.ts with name:number does not trigger a rebuild, and the error is unnoticed.

Relevant webpack config is as follows:

var threadLoader = {
    loader: 'thread-loader',
    options: {
        // leave one cpu for the fork-ts-plugin
        workers: require('os').cpus().length - 1,
    },
};

var babelLoader = {
    // XXX: .babelrc doesn't seem to be respected so we specify options here
    loader: 'babel-loader',
    options: {
        cacheDirectory: true,
        presets: ['es2015'],
    },
};

<snip>
    modules: {
        rules: [
            {
                test: tsSrc,
                exclude: babelExcludes,
                use: [
                    { loader: 'cache-loader' },
                    threadLoader,
                    babelLoader,
                    { loader: 'ts-loader', options: { happyPackMode: true } },
                ],
            },
<snip>
    plugins: [
        new ForkTsCheckerWebpackPlugin({
            tslint: true,
            watch: ['./src', './test', './test_util'], // optional but improves performance (less stat calls)
        }),
<snip>

About this issue

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

Most upvoted comments

Bump 😃

I’ve released a new version on the alpha channel - ’6.0.0-alpha.1’. It should detect changes in type-only files without additional TypeScript/Babel configuration 😃

I think I will be able to resolve it with 5.0.0 release - so stay tuned 😃

I’m closing this as it seems to be resolved with the 6.0.0 release 😃

With Microsoft/TypeScript#17493 now being resolved, is there a chance of seeing a fix for this now?

I’m working on a fix, there is progress 😃 Unfortunately, I’m not able to give you time frame when it will be fixed

Fantastic! For future reference, what was breaking it for us was this line, which was once recommended as part of the css-modules-typescript-loader instructions:

new webpack.WatchIgnorePlugin([/scss\.d\.ts$/]),

That was disabling Webpack’s watcher which meant your fix wasn’t able to run.

Thank you @oviava for the comment about importsNotUsedAsValues: preserve - I documented it in the README.md in the new alpha release 😃 I will close this issue as this configuration solves the problem 😃

@bhollis Your reproduction repo uses fork-ts-checker-webpack-plugin@^5.0.5 - switching to ^6.0.0-alpha.1 resolves the issue 😃

A little more info: I’m using babel-loader and it’s definitely skipping over the d.ts files since they only include types. That’s unrelated to the v4->v5 upgrade for this plugin.

In both v4 and v5, updating a d.ts wouldn’t trigger a rebuild. However, I could go to the .tsx file that was importing the d.ts file, re-save it, and webpack would then rebuild successfully, with this plugin recognizing the updated types.

In v5, re-saving the .tsx file triggers a rebuild, but the rebuild fails with a type error (for example, if I add property bar to type Foo and try to reference it, it’ll still say TS2339: Property 'bar' does not exist on type 'Foo' until I fully restart webpack). So it seems that the d.ts file isn’t being re-read even though it has been changed; instead, it’s using a cached version from a previous run.

Here you go! I hope it’s minimal enough: https://github.com/bhollis/fork-ts-checker-repro

It seems like an issue with the babel-loader - it works with ts-loader as far as I know (we have e2e tests for it - but only for ts-loader). I have to check some ideas on why it might not work.

Here is how I solved this. Maybe will be helpful for someone else 😃

webpack.config.js:

const glob = require("glob");
const tsConfigEditorJson = require("./tsconfig.editor.json");
const tsIncludePatterns = tsConfigEditorJson.include;

const addToFileDeps = {
  apply(compiler) {
    compiler.hooks.afterCompile.tap("AddToFileDepsPlugin", compilation => {
      tsIncludePatterns
      .reduce(
        (filePaths, pattern) => filePaths.concat(glob.sync(pattern)),
        []
      )
      .forEach(filePath => {
        compilation.fileDependencies.add(path.resolve(filePath));
      });
    });
  }
};

module.exports = env => {
  return {
    ...
    module: {
      rules: [
        {
          test: /\.ts$/,
          loader: "ts-loader",
          options: {
            configFile: "tsconfig.editor.json",
            transpileOnly: true
          }
        }
      ]
    },
    plugins: [
      new ForkTsCheckerWebpackPlugin({
        tsconfig: "tsconfig.editor.json"
      }),
      addToFileDeps
    ]
  }
}

tsconfig.editor.json:

{
  ...
  "include": [
    "src/dir1/**/*.ts",
    "src/dir2/**/dir3/**/*.ts",
    "src/dir2/**/dir4/**/*.ts"
  ]
}

There is an interesting proposal in TypeScript project (thanks @johnnyreilly for cc 😉 ): https://github.com/Microsoft/TypeScript/issues/17493 so I think the best idea is to wait for it and implement when it will be ready 😃 Another solution would be to just watch files from fork-ts-checker plugin but it would add another watcher 😕 The hard part would be to make sure it watches all files it should and to be consistent with TypeScript or WebPack. The proposal I’ve mentioned makes WebPack, TypeScript and fork-ts-checker consistent.

fork-ts-checker-webpack-plugin is hooked to the compilation run and if compilation doesn’t run after file change, it will not run checker. I think it doesn’t run because of some optimization in loader in transpileOnly mode - there is no need to recompile project if only typings have been changed.

Maybe it’s bad design to rely on compilation run in async mode - maybe I should make it totally async… It can check files that are not a part of webpack’s compilation so maybe it will be better behavior 😃