Skip to content

Commit

Permalink
Merge pull request #8 from Realytics/fix/stats-error-on-remove
Browse files Browse the repository at this point in the history
Fix/stats error on remove
  • Loading branch information
piotr-oles authored May 21, 2017
2 parents 7c64f03 + bd01eba commit f49e5bd
Show file tree
Hide file tree
Showing 7 changed files with 84 additions and 45 deletions.
17 changes: 17 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
## v0.1.4
* Fix send to closed channel case
* Fix removed files case
* Add `fork-ts-checker-service-start-error` hook

## v0.1.3
* Fix "Cannot read property 'mtime' of undefined on OSX"

## v0.1.2
* Workers mode works correctly (fixed typo)

## v0.1.1
* Support memory limit in multi-process mode
* Handle already closed channel case on sending ipc message

## v0.1.0
* Initial release - not production ready.
35 changes: 17 additions & 18 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,12 +2,12 @@
[![Npm version](https://img.shields.io/npm/v/fork-ts-checker-webpack-plugin.svg?style=flat-square)](https://www.npmjs.com/package/fork-ts-checker-webpack-plugin)
[![Build Status](https://travis-ci.org/Realytics/fork-ts-checker-webpack-plugin.svg?branch=master)](https://travis-ci.org/realytics/fork-ts-checker-webpack-plugin)

Webpack plugin that runs typescript type checker (with optional linter) on separate processes.
Webpack plugin that runs typescript type checker on a separate process.

## Installation ##
This plugin requires minimum **webpack 2**, **typescript 2.1** and optionally **tslint 5.0**
```sh
npm install --save fork-ts-checker-webpack-plugin
npm install --save-dev fork-ts-checker-webpack-plugin
```
Basic webpack config (with [ts-loader](https://github.com/TypeStrong/ts-loader))
```js
Expand Down Expand Up @@ -43,18 +43,17 @@ var webpackConfig = {

## Motivation ##
There is already similar solution - [awesome-typescript-loader](https://github.com/s-panferov/awesome-typescript-loader). You can
add `CheckerPlugin` and delegate checker to the separate process. The problem with `awesome-typescript-loader` is that it's a lot slower
than [ts-loader](https://github.com/TypeStrong/ts-loader) on incremental build in our case (~20s vs ~3s).
Secondly, we use [tslint](https://palantir.github.io/tslint/) and we wanted to run this also on separate process.
This is why we've created this plugin. The performance is great because of reusing Abstract Syntax Trees between compilations and sharing
these trees with tslint. We can also scale checker with multi-process mode - it will split work between processes to utilize maximum cpu
power.
add `CheckerPlugin` and delegate checker to the separate process. The problem with `awesome-typescript-loader` was that, in our case,
it was a lot slower than [ts-loader](https://github.com/TypeStrong/ts-loader) on an incremental build (~20s vs ~3s).
Secondly, we use [tslint](https://palantir.github.io/tslint/) and we wanted to run this, along with type checker, in a separate process.
This is why we've created this plugin. To provide better performance, plugin reuses Abstract Syntax Trees between compilations and shares
these trees with tslint. It can be scaled with a multi-process mode to utilize maximum CPU power.

## Options ##
**tsconfig** `string` - Path to tsconfig.json file. If not set, plugin will use `path.resolve(compiler.options.context, './tsconfig.json')`.

**tslint** `string | false` - Path to tslint.json file. If not set, plugin will use `path.resolve(compiler.options.context, './tslint.json')`.
If `false`, disables tslint.
If `false`, disables tslint.

**watch** `string | string[]` - Directories or files to watch by service. Not necessary but improves performance
(reduces number of `fs.stat` calls).
Expand All @@ -72,18 +71,17 @@ power.

**silent** `boolean` - If `true`, logger will not be used. Default: `false`.

**workers** `number` - You can split type checking to few workers to speed-up on increment build.
**Be careful** - if you don't want to increase build time, you should keep 1 core for *build* and 1 core for
*system* free *(for example system with 4 cpu threads should use max 2 workers)*.
Second thing - node doesn't share memory between workers so keep in mind that memory usage will increase
linearly. If you want to use workers, please experiment with workers number. In some scenarios increasing this number
**can increase check time** (and of course memory consumption).
**workers** `number` - You can split type checking to a few workers to speed-up increment build.
**Be careful** - if you don't want to increase build time, you should keep free 1 core for *build* and 1 core for
a *system* *(for example system with 4 CPUs should use max 2 workers)*.
Second thing - node doesn't share memory between workers - keep in mind that memory usage will increase.
Be aware that in some scenarios increasing workers number **can increase checking time**.
Default: `ForkTsCheckerWebpackPlugin.ONE_CPU`.

Pre-computed consts:
* `ForkTsCheckerWebpackPlugin.ONE_CPU` - always use one cpu (core)
* `ForkTsCheckerWebpackPlugin.ONE_CPU_FREE` - leave only one cpu for build (probably will increase build time)
* `ForkTsCheckerWebpackPlugin.TWO_CPUS_FREE` - leave two cpus free (one for build, one for system)
* `ForkTsCheckerWebpackPlugin.ONE_CPU` - always use one CPU
* `ForkTsCheckerWebpackPlugin.ONE_CPU_FREE` - leave only one CPU for build (probably will increase build time)
* `ForkTsCheckerWebpackPlugin.TWO_CPUS_FREE` - leave two CPUs free (one for build, one for system)

**memoryLimit** `number` - Memory limit for service process in MB. If service exits with allocation failed error, increase this number.
Default: `2048`.
Expand All @@ -96,6 +94,7 @@ This plugin provides some custom webpack hooks (all are sync):
|`fork-ts-checker-cancel`| Cancellation has been requested | `cancellationToken` |
|`fork-ts-checker-waiting`| Waiting for results | `hasTsLint` |
|`fork-ts-checker-service-start`| Service will be started | `tsconfigPath`, `tslintPath`, `watchPaths`, `workersNumber`, `memoryLimit` |
|`fork-ts-checker-service-start-error` | Cannot start service | `error` |
|`fork-ts-checker-service-out-of-memory`| Service is out of memory | - |
|`fork-ts-checker-receive`| Plugin receives diagnostics and lints from service | `diagnostics`, `lints` |
|`fork-ts-checker-emit`| Service will add errors and warnings to webpack compilation (`blockEmit: true`) | `diagnostics`, `lints`, `elapsed` |
Expand Down
20 changes: 16 additions & 4 deletions lib/IncrementalChecker.js
Original file line number Diff line number Diff line change
Expand Up @@ -47,9 +47,14 @@ IncrementalChecker.createProgram = function (programConfig, files, watcher, oldP
host.getSourceFile = function (filePath, languageVersion, onError) {
// first check if watcher is watching file - if not - check it's mtime
if (!watcher.isWatchingFile(filePath)) {
var stats = fs.statSync(filePath);

files.setMtime(filePath, stats.mtime.valueOf());
try {
var stats = fs.statSync(filePath);

files.setMtime(filePath, stats.mtime.valueOf());
} catch (e) {
// probably file does not exists
files.remove(filePath);
}
}

// get source file only if there is no source in files register
Expand Down Expand Up @@ -145,7 +150,14 @@ IncrementalChecker.prototype.getLints = function (cancellationToken) {
workSet.forEach(function (fileName) {
cancellationToken.throwIfCancellationRequested();

this.linter.lint(fileName, undefined, this.linterConfig);
try {
this.linter.lint(fileName, undefined, this.linterConfig);
} catch (e) {
if (fs.existsSync(fileName)) {
// it's not because file doesn't exist - throw error
throw e;
}
}
}.bind(this));

// set lints in files register
Expand Down
7 changes: 6 additions & 1 deletion lib/cluster.js
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,12 @@ var result = new WorkResult(pids);
process.on('message', function (message) {
// broadcast message to all workers
workers.forEach(function (worker) {
worker.send(message);
try {
worker.send(message);
} catch (e) {
// channel closed - something went wrong - close cluster...
process.exit();
}
});

// clear previous result set
Expand Down
13 changes: 11 additions & 2 deletions lib/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -156,7 +156,16 @@ ForkTsCheckerWebpackPlugin.prototype.pluginCompile = function () {
if (!this.service || !this.service.connected) {
this.spawnService();
}
this.service.send(this.cancellationToken);

try {
this.service.send(this.cancellationToken);
} catch (error) {
if (!this.options.silent && this.logger) {
this.logger.error(this.colors.red('Cannot start checker service: ' + (error ? error.toString() : 'Unknown error')));
}

this.compiler.applyPlugins('fork-ts-checker-service-start-error', error);
}
}.bind(this));
};

Expand Down Expand Up @@ -234,7 +243,7 @@ ForkTsCheckerWebpackPlugin.prototype.spawnService = function () {
}
if (this.tslint && !this.options.tslint) {
// auto-detect tslint path - print to the user to be sure that it's proper file
lines.push(this.colors.grey(this.tslint));
lines.push(this.colors.grey(this.tslintPath));
}

this.logger.info(lines.join('\n'));
Expand Down
13 changes: 5 additions & 8 deletions package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "fork-ts-checker-webpack-plugin",
"version": "0.1.3",
"version": "0.1.4",
"description": "Runs typescript type checker and linter on separate process.",
"main": "lib/index.js",
"scripts": {
Expand Down Expand Up @@ -34,11 +34,11 @@
"chai": "^3.5.0",
"eslint": "^3.19.0",
"istanbul": "^0.4.5",
"mocha": "^3.2.0",
"mock-fs": "^4.2.0",
"mocha": "^3.4.1",
"mock-fs": "^4.3.0",
"mock-require": "^2.0.2",
"rimraf": "^2.5.4",
"sinon": "^2.1.0",
"sinon": "^2.2.0",
"typescript": "^2.1.0"
},
"peerDependencies": {
Expand All @@ -47,12 +47,9 @@
},
"dependencies": {
"chalk": "^1.1.3",
"chokidar": "^1.6.1",
"chokidar": "^1.7.0",
"lodash.endswith": "^4.2.1",
"lodash.isstring": "^4.0.1",
"lodash.startswith": "^4.2.1"
},
"optionalDependencies": {
"tslint": "^5.0.0"
}
}
24 changes: 12 additions & 12 deletions yarn.lock
Original file line number Diff line number Diff line change
Expand Up @@ -249,9 +249,9 @@ chalk@^1.0.0, chalk@^1.1.0, chalk@^1.1.1, chalk@^1.1.3:
strip-ansi "^3.0.0"
supports-color "^2.0.0"

chokidar@^1.6.1:
version "1.6.1"
resolved "https://registry.yarnpkg.com/chokidar/-/chokidar-1.6.1.tgz#2f4447ab5e96e50fb3d789fd90d4c72e0e4c70c2"
chokidar@^1.7.0:
version "1.7.0"
resolved "https://registry.yarnpkg.com/chokidar/-/chokidar-1.7.0.tgz#798e689778151c8076b4b360e5edd28cda2bb468"
dependencies:
anymatch "^1.3.0"
async-each "^1.0.0"
Expand Down Expand Up @@ -1232,9 +1232,9 @@ [email protected], [email protected], "mkdirp@>=0.5 0", mkdirp@^0.5.0, mkdirp@^0.5.1:
dependencies:
minimist "0.0.8"

mocha@^3.2.0:
version "3.3.0"
resolved "https://registry.yarnpkg.com/mocha/-/mocha-3.3.0.tgz#d29b7428d3f52c82e2e65df1ecb7064e1aabbfb5"
mocha@^3.4.1:
version "3.4.1"
resolved "https://registry.yarnpkg.com/mocha/-/mocha-3.4.1.tgz#a3802b4aa381934cacb38de70cf771621da8f9af"
dependencies:
browser-stdout "1.3.0"
commander "2.9.0"
Expand All @@ -1248,9 +1248,9 @@ mocha@^3.2.0:
mkdirp "0.5.1"
supports-color "3.1.2"

mock-fs@^4.2.0:
version "4.2.0"
resolved "https://registry.yarnpkg.com/mock-fs/-/mock-fs-4.2.0.tgz#ef53ae17b77e64f67816dd0467f29208a3b26e19"
mock-fs@^4.3.0:
version "4.3.0"
resolved "https://registry.yarnpkg.com/mock-fs/-/mock-fs-4.3.0.tgz#c2fab8d784283287e9b6ae7538f2dc56c1a05ed7"

mock-require@^2.0.2:
version "2.0.2"
Expand Down Expand Up @@ -1638,9 +1638,9 @@ signal-exit@^3.0.0:
version "3.0.2"
resolved "https://registry.yarnpkg.com/signal-exit/-/signal-exit-3.0.2.tgz#b5fdc08f1287ea1178628e415e25132b73646c6d"

sinon@^2.1.0:
version "2.1.0"
resolved "https://registry.yarnpkg.com/sinon/-/sinon-2.1.0.tgz#e057a9d2bf1b32f5d6dd62628ca9ee3961b0cafb"
sinon@^2.2.0:
version "2.2.0"
resolved "https://registry.yarnpkg.com/sinon/-/sinon-2.2.0.tgz#3b1b42ff5defcbf51a52a62aca6d61171b9fd262"
dependencies:
diff "^3.1.0"
formatio "1.2.0"
Expand Down

0 comments on commit f49e5bd

Please sign in to comment.