Skip to content
This repository was archived by the owner on Dec 1, 2019. It is now read-only.

Commit 2cdb8f4

Browse files
author
Stanislav Panferov
committed
feat(*): now we can start ckecker in a separate process
1 parent ec359cb commit 2cdb8f4

File tree

9 files changed

+252
-25
lines changed

9 files changed

+252
-25
lines changed

README.md

+8
Original file line numberDiff line numberDiff line change
@@ -111,6 +111,14 @@ with pure TS files inside your app.
111111

112112
Common-separated list of paths to .d.ts files that must be included in program. Useful with `rewriteImports`.
113113

114+
### doTypeCheck *(string) (default=true)*
115+
116+
Use this setting to disable type checking if you want.
117+
118+
### forkChecker *experimental!* *(string) (default=false)*
119+
120+
Do type checking in a separate process, so webpack don't need to wait. **Significantly** development workflow.
121+
114122
## Using with --watch or webpack-dev-server
115123

116124
This loader has support of both `--watch` and `webpack-dev-server` modes. It handles file dependencies

package.json

+2-1
Original file line numberDiff line numberDiff line change
@@ -29,7 +29,8 @@
2929
"lodash": "^3.10.0",
3030
"ntypescript": "1.201507141013.1",
3131
"object-assign": "^2.0.0",
32-
"typescript": "1.5.0-beta"
32+
"typescript": "1.5.0-beta",
33+
"colors": "^1.1.2"
3334
},
3435
"devDependencies": {
3536
"git-hooks": "0.0.10",

src/checker.ts

+112
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,112 @@
1+
import { CompilerOptions, CompilerInfo, File } from './host';
2+
import * as colors from 'colors';
3+
4+
export enum MessageType {
5+
Init = <any>'init',
6+
Compile = <any>'compile'
7+
}
8+
9+
export interface IMessage {
10+
messageType: MessageType,
11+
payload: any
12+
}
13+
14+
export interface IInitPayload {
15+
compilerOptions: CompilerOptions;
16+
compilerInfo: CompilerInfo
17+
}
18+
19+
export interface ICompilePayload {
20+
files: {[fileName: string]: File};
21+
}
22+
23+
export interface IEnv {
24+
options?: CompilerOptions;
25+
compiler?: typeof ts;
26+
compilerInfo?: CompilerInfo;
27+
host?: Host;
28+
files?: {[fileName: string]: File};
29+
program?: ts.Program;
30+
service?: ts.LanguageService;
31+
}
32+
33+
let env: IEnv = {};
34+
35+
export class Host implements ts.LanguageServiceHost {
36+
37+
getScriptFileNames() {
38+
return Object.keys(env.files);
39+
}
40+
41+
getScriptVersion(fileName: string) {
42+
if (env.files[fileName]) {
43+
return env.files[fileName].version.toString();
44+
}
45+
}
46+
47+
getScriptSnapshot(fileName) {
48+
var file = env.files[fileName];
49+
if (file) {
50+
return env.compiler.ScriptSnapshot.fromString(file.text);
51+
}
52+
}
53+
54+
getCurrentDirectory() {
55+
return process.cwd();
56+
}
57+
58+
getScriptIsOpen() {
59+
return true;
60+
}
61+
62+
getCompilationSettings() {
63+
return env.options;
64+
}
65+
66+
getDefaultLibFileName(options) {
67+
return options.target === ts.ScriptTarget.ES6 ?
68+
env.compilerInfo.lib6.fileName :
69+
env.compilerInfo.lib5.fileName;
70+
}
71+
72+
log(message) {
73+
//console.log(message);
74+
}
75+
76+
}
77+
78+
function processInit(payload: IInitPayload) {
79+
env.compiler = require(payload.compilerInfo.compilerName);
80+
env.host = new Host();
81+
env.compilerInfo = payload.compilerInfo;
82+
env.options = payload.compilerOptions;
83+
env.service = this.ts.createLanguageService(env.host, env.compiler.createDocumentRegistry());
84+
}
85+
86+
function processCompile(payload: ICompilePayload) {
87+
env.files = payload.files;
88+
let program = env.program = env.service.getProgram();
89+
var allDiagnostics = env.compiler.getPreEmitDiagnostics(program);
90+
if (allDiagnostics.length) {
91+
console.error(colors.yellow('Checker diagnostics:'))
92+
allDiagnostics.forEach(diagnostic => {
93+
var { line, character } = diagnostic.file.getLineAndCharacterOfPosition(diagnostic.start);
94+
var message = ts.flattenDiagnosticMessageText(diagnostic.messageText, '\n');
95+
console.error(`${colors.cyan(diagnostic.file.fileName)} (${line + 1},${character + 1}):\n ${colors.red(message)}`);
96+
});
97+
} else {
98+
console.error(colors.green('Your program is fine!'))
99+
}
100+
101+
}
102+
103+
process.on('message', function(msg: IMessage) {
104+
switch (msg.messageType) {
105+
case MessageType.Init:
106+
processInit(msg.payload);
107+
break;
108+
case MessageType.Compile:
109+
processCompile(msg.payload);
110+
break;
111+
}
112+
});

src/host.ts

+4-1
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@ export interface File {
1818

1919
export interface CompilerInfo {
2020
compilerName: string;
21+
compilerPath: string;
2122
tsImpl: typeof ts;
2223
lib5: { fileName: string, text: string };
2324
lib6: { fileName: string, text: string };
@@ -34,7 +35,9 @@ export interface CompilerOptions extends ts.CompilerOptions {
3435
tsconfig?: string;
3536
useWebpackText?: boolean;
3637
rewriteImports?: string;
37-
externals?: string
38+
externals?: string;
39+
doTypeCheck?: boolean;
40+
forkChecker?: boolean;
3841
}
3942

4043
export class Host implements ts.LanguageServiceHost {

src/index.ts

+84-23
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@ import * as Promise from 'bluebird';
55
import * as path from 'path';
66
import * as fs from 'fs';
77
import * as _ from 'lodash';
8+
import * as childProcess from 'child_process';
89

910
import { CompilerOptions, TypeScriptCompilationError, State, CompilerInfo } from './host';
1011
import { Resolver, ResolutionError } from './deps';
@@ -40,6 +41,7 @@ interface CompilerInstance {
4041
compiledFiles: {[key:string]: boolean};
4142
options: CompilerOptions;
4243
externalsInvoked: boolean;
44+
checker: any;
4345
}
4446

4547
function getRootCompiler(compiler) {
@@ -85,6 +87,20 @@ function createResolver(compiler: ICompiler, webpackResolver: any): Resolver {
8587
return resolve;
8688
}
8789

90+
function createChecker(compilerInfo: CompilerInfo, compilerOptions: CompilerOptions) {
91+
var checker = childProcess.fork(path.join(__dirname, 'checker.js'));
92+
93+
checker.send({
94+
messageType: 'init',
95+
payload: {
96+
compilerInfo: _.omit(compilerInfo, 'tsImpl'),
97+
compilerOptions
98+
}
99+
}, null)
100+
101+
return checker;
102+
}
103+
88104
/**
89105
* Creates compiler instance
90106
*/
@@ -108,6 +124,7 @@ function ensureInstance(webpack: WebPack, options: CompilerOptions, instanceName
108124

109125
let compilerInfo: CompilerInfo = {
110126
compilerName,
127+
compilerPath,
111128
tsImpl,
112129
lib5: loadLib(path.join(compilerPath, 'bin', 'lib.d.ts')),
113130
lib6: loadLib(path.join(compilerPath, 'bin', 'lib.es6.d.ts'))
@@ -141,6 +158,22 @@ function ensureInstance(webpack: WebPack, options: CompilerOptions, instanceName
141158
}
142159
}
143160

161+
if (typeof options.doTypeCheck === 'undefined') {
162+
options.doTypeCheck = true;
163+
} else {
164+
if (typeof options.doTypeCheck === 'string') {
165+
options.doTypeCheck = (<any>options.doTypeCheck) === 'true'
166+
}
167+
}
168+
169+
if (typeof options.forkChecker === 'undefined') {
170+
options.forkChecker = false;
171+
} else {
172+
if (typeof options.forkChecker === 'string') {
173+
options.forkChecker = (<any>options.forkChecker) === 'true'
174+
}
175+
}
176+
144177
if (typeof options.useWebpackText === 'undefined') {
145178
options.useWebpackText = false;
146179
} else {
@@ -184,37 +217,60 @@ function ensureInstance(webpack: WebPack, options: CompilerOptions, instanceName
184217
.catch((err) => callback(err))
185218
});
186219

187-
compiler.plugin('after-compile', function(compilation, callback) {
188-
189-
var instance: CompilerInstance = resolveInstance(compilation.compiler, instanceName);
190-
var state = instance.tsState;
191-
var diagnostics = state.ts.getPreEmitDiagnostics(state.program);
192-
var emitError = (err) => {
193-
compilation.errors.push(new Error(err))
194-
};
195-
196-
var phantomImports = [];
197-
Object.keys(state.files).forEach((fileName) => {
198-
if (!instance.compiledFiles[fileName]) {
199-
phantomImports.push(fileName)
220+
if (options.doTypeCheck) {
221+
compiler.plugin('after-compile', function(compilation, callback) {
222+
let instance: CompilerInstance = resolveInstance(compilation.compiler, instanceName);
223+
let state = instance.tsState;
224+
225+
if (options.forkChecker) {
226+
let payload = {
227+
files: state.files
228+
};
229+
230+
console.time('\nSending files to the checker');
231+
instance.checker.send({
232+
messageType: 'compile',
233+
payload
234+
})
235+
console.timeEnd('\nSending files to the checker');
236+
} else {
237+
let diagnostics = state.ts.getPreEmitDiagnostics(state.program);
238+
let emitError = (err) => {
239+
if (compilation.bail) {
240+
console.error('Error in bail mode:', err);
241+
process.exit(1);
242+
}
243+
compilation.errors.push(new Error(err))
244+
};
245+
246+
var errors = helpers.formatErrors(diagnostics);
247+
errors.forEach(emitError);
248+
callback();
200249
}
201-
});
202250

203-
instance.compiledFiles = {};
204-
compilation.fileDependencies.push.apply(compilation.fileDependencies, phantomImports);
205-
compilation.fileDependencies = _.uniq(compilation.fileDependencies);
251+
let phantomImports = [];
252+
Object.keys(state.files).forEach((fileName) => {
253+
if (!instance.compiledFiles[fileName]) {
254+
phantomImports.push(fileName)
255+
}
256+
});
206257

207-
var errors = helpers.formatErrors(diagnostics);
208-
errors.forEach(emitError);
209-
callback();
210-
});
258+
instance.compiledFiles = {};
259+
compilation.fileDependencies.push.apply(compilation.fileDependencies, phantomImports);
260+
compilation.fileDependencies = _.uniq(compilation.fileDependencies);
261+
callback();
262+
});
263+
}
211264

212265
return getInstanceStore(webpack._compiler)[instanceName] = {
213266
tsFlow,
214267
tsState,
215268
compiledFiles: {},
216269
options,
217-
externalsInvoked: false
270+
externalsInvoked: false,
271+
checker: options.forkChecker
272+
? createChecker(compilerInfo, options)
273+
: null
218274
}
219275
}
220276

@@ -294,7 +350,12 @@ function compiler(webpack: WebPack, text: string): void {
294350

295351
applyDeps();
296352

297-
callback(null, result.text, sourceMap);
353+
try {
354+
callback(null, result.text, sourceMap);
355+
} catch (e) {
356+
console.error('Error in bail mode:', e);
357+
process.exit(1);
358+
}
298359
})
299360
.finally(() => {
300361
applyDeps();

src/tsconfig.json

+1
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@
1616
"!./node_modules/**/*.ts"
1717
],
1818
"files": [
19+
"./checker.ts",
1920
"./deps.ts",
2021
"./helpers.ts",
2122
"./host.ts",

tsd.json

+3
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,9 @@
1313
},
1414
"lodash/lodash.d.ts": {
1515
"commit": "2272849a06f2b68205611665e6b86ffec58c1e10"
16+
},
17+
"colors/colors.d.ts": {
18+
"commit": "73ef8a2ccd832c9dd8600947238ac8723584cb10"
1619
}
1720
}
1821
}

typings/colors/colors.d.ts

+37
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,37 @@
1+
// Type definitions for Colors.js 0.6.0-1
2+
// Project: https://github.com/Marak/colors.js
3+
// Definitions by: Bart van der Schoor <https://github.com/Bartvds>
4+
// Definitions: https://github.com/borisyankov/DefinitelyTyped
5+
6+
declare module "colors" {
7+
export function setTheme(theme:any):any;
8+
9+
export function black(text: string): string;
10+
export function red(text: string): string;
11+
export function green(text: string): string;
12+
export function yellow(text: string): string;
13+
export function blue(text: string): string;
14+
export function magenta(text: string): string;
15+
export function cyan(text: string): string;
16+
export function white(text: string): string;
17+
export function gray(text: string): string;
18+
export function grey(text: string): string;
19+
}
20+
21+
interface String {
22+
bold:string;
23+
italic:string;
24+
underline:string;
25+
inverse:string;
26+
yellow:string;
27+
cyan:string;
28+
white:string;
29+
magenta:string;
30+
green:string;
31+
red:string;
32+
grey:string;
33+
blue:string;
34+
rainbow:string;
35+
zebra:string;
36+
random:string;
37+
}

typings/tsd.d.ts

+1
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
11
/// <reference path="node/node.d.ts" />
22
/// <reference path="bluebird/bluebird.d.ts" />
33
/// <reference path="lodash/lodash.d.ts" />
4+
/// <reference path="colors/colors.d.ts" />

0 commit comments

Comments
 (0)