Fork-ts-checker-webpack-plugin: TypeError: Cannot read property '0' of undefined

Created on 27 Nov 2017  路  20Comments  路  Source: TypeStrong/fork-ts-checker-webpack-plugin

The plugin crashed right after rebuilding (in watch mode), with below message

/~/node_modules/fork-ts-checker-webpack-plugin/lib/index.js:323
            var elapsed = Math.round(_this.elapsed[0] * 1E9 + _this.elapsed[1]);
                                                  ^

TypeError: Cannot read property '0' of undefined
    at ForkTsCheckerWebpackPlugin.doneCallback (~node_modules/fork-ts-checker-webpack-plugin/lib/index.js:323:51)
    at ForkTsCheckerWebpackPlugin.handleServiceMessage (/~/node_modules/fork-ts-checker-webpack-plugin/lib/index.js:273:52)
    at ChildProcess.<anonymous> (/Users/rok/GitHub/sinicompany/closer-www/node_modules/fork-ts-checker-webpack-plugin/lib/index.js:231:70)
    at emitTwo (events.js:126:13)
    at ChildProcess.emit (events.js:214:7)
    at emit (internal/child_process.js:772:12)
    at _combinedTickCallback (internal/process/next_tick.js:141:11)
    at process._tickDomainCallback (internal/process/next_tick.js:218:9)

version

webpack 3.8.1
webpack-dev-server 2.9.4
fork-ts-checker-plugin 0.2.9
typescirpt 2.6.1
tslint 5.8.0
tslint-microsoft-contrib 5.0.1

options

fork-ts-checker-plugin

{
  "tsconfig": "../tsconfig.json",
  "tslint": "../tslint.json",
  "checkSyntacticErrors": true,
}

tsconfig

{
  "compilerOptions": {
    "sourceMap": true,
    "target": "es5",
    "jsx": "react",
    "module": "esnext",
    "moduleResolution": "node",
    "allowJs": false,
    "importHelpers": true,
    "emitDecoratorMetadata": false,
    "experimentalDecorators": true,
    "forceConsistentCasingInFileNames": true,
    "downlevelIteration": true,
    "pretty": true,
    "declaration": false,
    "noUnusedLocals": true,
    "noUnusedParameters": false,
    "noImplicitAny": false,
    "noImplicitReturns": false,
    "removeComments": false,
    "strictNullChecks": false,
    "outDir": "dist",
    "baseUrl": ".",
    "paths": {
      "*": ["src/*", "*"]
    },
    "lib": [
      "es6",
      "es7",
      "dom"
    ]
  },
  "exclude": [
    "dist",
    "node_modules"
  ]
}

tslint

{
  "rulesDirectory": [
    "node_modules/tslint-microsoft-contrib"
  ],
  ...
}

it works well with [email protected].

Most helpful comment

@johnnyreilly I'm using the Chrome inspector to walk through some of the code. It looks like this.elapsed _is_ initially set. However, when createDoneCallback() is called, elapsed is not defined. In other words, handleServiceMessage() is called after createDoneCallback() and I believe after a child process is spun off. handleServiceMessage() does define elapsed on this, but _this in createDoneCallback() is never updated.

Presumably, createDoneCallback()'s _this and handleServiceMessage()'s this refer to different this objects. I wonder if that has anything to do with child-process. Perhaps handleServiceMessage() is being called in a child process and not modifying the same this?

However, this _does_ have elapsed defined within the done callback defined by createDoneCallback() (but not _this).

The solution I found was to use this instead of _this in the callback created by createDoneCallback().

All 20 comments

Can you provide a minimal reproduction repo please?

I'm getting this error, too. Although my error message isn't as nice and I had to use the Chrome inspector to find the problem. I only see this bug when I use the watch option for WebPack set to true. If I set it to false, everything works perfectly.

@rokoroku Is that the case for you?

I might be willing to see if I can create a minimal reproduction if you can't duplicate this @johnnyreilly. Is there some basic project I can piggy-back off of so I don't have to create a separate setup just for this?

Hey @c1moore,

Thanks for that - this is probably a good basis for a minimal repro: https://github.com/TypeStrong/ts-loader/tree/master/examples/fork-ts-checker

@johnnyreilly I can only reproduce this when using this plugin in conjunction with Grunt. I'm not sure if @rokoroku has the same setup.

You can see how I reproduced it here. My changes were extremely simple:

  • Add watch: true to the webpack config file
  • Add grunt
  • Add and register grunt-webpack
  • Run grunt run

Seems odd that grunt would be what affects _this.elapsed...

It does - the issue appears to happen in the done callback here: https://github.com/Realytics/fork-ts-checker-webpack-plugin/blob/master/src/index.ts#L465

@piotr-oles can you think why grunt wouldn't play nice with fork-ts-checker-webpack-plugin? I had 1 idea. The plugin looks like it has some global variables in the form of node's process.env.:

        env: Object.assign(
          {},
          process.env,
          {
            TSCONFIG: this.tsconfigPath,
            TSLINT: this.tslintPath || '',
            WATCH: this.isWatching ? this.watchPaths.join('|') : '',
            WORK_DIVISION: Math.max(1, this.workersNumber),
            MEMORY_LIMIT: this.memoryLimit,
            CHECK_SYNTACTIC_ERRORS: this.checkSyntacticErrors
          }
        ),

Perhaps these are colliding with similar Grunt variables? Does that make sense as a potential issue?

Essentially the problem seems to be that this code is not running: https://github.com/Realytics/fork-ts-checker-webpack-plugin/blob/master/src/index.ts#L379

this.elapsed = process.hrtime(this.started)

https://github.com/Realytics/fork-ts-checker-webpack-plugin/blob/master/src/index.ts#L313

Not sure why grunt would cause that though

@johnnyreilly I'm using the Chrome inspector to walk through some of the code. It looks like this.elapsed _is_ initially set. However, when createDoneCallback() is called, elapsed is not defined. In other words, handleServiceMessage() is called after createDoneCallback() and I believe after a child process is spun off. handleServiceMessage() does define elapsed on this, but _this in createDoneCallback() is never updated.

Presumably, createDoneCallback()'s _this and handleServiceMessage()'s this refer to different this objects. I wonder if that has anything to do with child-process. Perhaps handleServiceMessage() is being called in a child process and not modifying the same this?

However, this _does_ have elapsed defined within the done callback defined by createDoneCallback() (but not _this).

The solution I found was to use this instead of _this in the callback created by createDoneCallback().

Sorry for late, and thanks @c1moore for reproducing example.

In my case, I use gulp, not grunt. It seems like this issue is related to such build tools.

The solution I found was to use this instead of _this in the callback created by createDoneCallback().

That's absolute gold @c1moore - thanks for digging into it. Let me have a little play and report back

Okay I've made a propective fix; I haven't had time to test it properly but I'm fairly confident this should resolve the issue. My fix can be viewed here: https://github.com/johnnyreilly/fork-ts-checker-webpack-plugin

We're using https://github.com/typestrong/fork-ts-checker-webpack-plugin as an __@next__ channel for the plugin. I've get this pushed up there so you can have a test.

Can you advise if this resolves the issue? If so I'll look to submit a PR for @piotr-oles to review

@johnnyreilly It might be worth testing outside of the context of Grunt/Gulp, but I'll give it a try. I don't understand how I can get this update, though. Should I use your fork, pull directly from the typestrong repo, or do something like npm install fork-ts-checker-webpack-plugin@next? It sounds like I should use the typestrong repo.

That's absolute gold @c1moore - thanks for digging into it

I forgot I was messing around with the compiled version of the TypeScript you guys are looking at. Glad in helped, though.

Hey @c1moore

The typestrong repo contains the compiled code in a github repo that you can reference in your package.json.

Use the instructions in the readme here: https://github.com/typestrong/fork-ts-checker-webpack-plugin

It was me that ported the plugin to Typescript and my change reverts a change I made to do with the lexical binding of this. It's now more in line with the original is codebase

Did you get chance to test this @c1moore?

@johnnyreilly Sorry, I've been busy. That seems to work for me.

@johnnyreilly it seems work for me too. 馃憤

Great - I'll submit a PR. Thanks!

Merged - will be released as v0.2.10 :)

@piotr-oles I don't see v0.2.10 available on npmjs yet, but it seems to be available on GitHub. Is there some delay for the npm registry to update or are you holding off on releasing to npm for the time being? If the latter, is there an ETA for its release?

Hey @c1moore,

Hopefully should be out soon - see: https://github.com/Realytics/fork-ts-checker-webpack-plugin/issues/83

@c1moore v0.2.10 released :)

Yay!

Was this page helpful?
0 / 5 - 0 ratings