Skip to content

Commit cfdd86a

Browse files
authored
Merge pull request #497 from ivogabe/perf
Fix performance issues
2 parents 161c806 + 489f54c commit cfdd86a

File tree

1 file changed

+70
-43
lines changed

1 file changed

+70
-43
lines changed

lib/compiler.ts

Lines changed: 70 additions & 43 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,16 @@ export interface ICompiler {
1313
inputDone(): void;
1414
}
1515

16+
interface OutputFile {
17+
file: File | undefined;
18+
19+
jsFileName?: string;
20+
dtsFileName?: string;
21+
jsContent?: string;
22+
jsMapContent?: string;
23+
dtsContent?: string;
24+
}
25+
1626
/**
1727
* Compiles a whole project, with full type checking
1828
*/
@@ -61,69 +71,85 @@ export class ProjectCompiler implements ICompiler {
6171
);
6272

6373
this.program = this.project.typescript.createProgram(rootFilenames, this.project.options, this.host, this.program);
64-
const preEmitDiagnostics = this.project.typescript.getPreEmitDiagnostics(this.program);
65-
74+
6675
const result = emptyCompilationResult();
67-
result.optionsErrors = this.program.getOptionsDiagnostics().length;
68-
result.syntaxErrors = this.program.getSyntacticDiagnostics().length;
69-
result.globalErrors = this.program.getGlobalDiagnostics().length;
70-
result.semanticErrors = this.program.getSemanticDiagnostics().length;
76+
result.optionsErrors = this.reportDiagnostics(this.program.getOptionsDiagnostics());
77+
result.syntaxErrors = this.reportDiagnostics(this.program.getSyntacticDiagnostics());
78+
result.globalErrors = this.reportDiagnostics(this.program.getGlobalDiagnostics());
79+
result.semanticErrors = this.reportDiagnostics(this.program.getSemanticDiagnostics());
7180
if (this.project.options.declaration) {
7281
result.declarationErrors = this.program.getDeclarationDiagnostics().length;
7382
}
7483

75-
this.reportDiagnostics(preEmitDiagnostics);
84+
if (this.project.singleOutput) {
85+
const output: OutputFile = {
86+
file: undefined
87+
};
7688

77-
const emitOutput = this.program.emit();
78-
result.emitErrors = emitOutput.diagnostics.length;
79-
result.emitSkipped = emitOutput.emitSkipped;
89+
this.emit(result, (fileName, content) => {
90+
this.attachContentToFile(output, fileName, content);
91+
});
8092

81-
if (this.project.singleOutput) {
82-
this.emitFile(result, currentDirectory);
93+
this.emitFile(output, currentDirectory);
8394
} else {
84-
// Emit files one by one
85-
for (const fileName of this.host.input.getFileNames(true)) {
95+
const output: utils.Map<OutputFile> = {};
96+
97+
const input = this.host.input.getFileNames(true);
98+
99+
for (let i = 0; i < input.length; i++) {
100+
const fileName = utils.normalizePath(input[i]);
86101
const file = this.project.input.getFile(fileName);
87102

88-
this.emitFile(result, currentDirectory, file);
103+
output[fileName] = { file };
104+
}
105+
106+
this.emit(result, (fileName, content, writeByteOrderMark, onError, sourceFiles) => {
107+
if (sourceFiles.length !== 1) {
108+
throw new Error("Failure: sourceFiles in WriteFileCallback should have length 1, got " + sourceFiles.length);
109+
}
110+
111+
const fileNameOriginal = utils.normalizePath(sourceFiles[0].fileName);
112+
const file = output[fileNameOriginal];
113+
if (!file) return;
114+
115+
this.attachContentToFile(file, fileName, content);
116+
});
117+
118+
for (let i = 0; i < input.length; i++) {
119+
const fileName = utils.normalizePath(input[i]);
120+
this.emitFile(output[fileName], currentDirectory);
89121
}
90122
}
91123

92124
this.project.output.finish(result);
93125
}
94126

95-
private emitFile(result: CompilationResult, currentDirectory: string, file?: File) {
96-
let jsFileName: string;
97-
let dtsFileName: string;
98-
let jsContent: string;
99-
let dtsContent: string;
100-
let jsMapContent: string;
101-
102-
const emitOutput = this.program.emit(file && file.ts, (fileName: string, content: string) => {
103-
const [, extension] = utils.splitExtension(fileName, ['d.ts']);
104-
switch (extension) {
105-
case 'js':
106-
case 'jsx':
107-
jsFileName = fileName;
108-
jsContent = content;
109-
break;
110-
case 'd.ts':
111-
dtsFileName = fileName;
112-
dtsContent = content;
113-
break;
114-
case 'map':
115-
jsMapContent = content;
116-
break;
117-
}
118-
});
127+
private attachContentToFile(file: OutputFile, fileName: string, content: string) {
128+
const [, extension] = utils.splitExtension(fileName, ['d.ts']);
129+
switch (extension) {
130+
case 'js':
131+
case 'jsx':
132+
file.jsFileName = fileName;
133+
file.jsContent = content;
134+
break;
135+
case 'd.ts':
136+
file.dtsFileName = fileName;
137+
file.dtsContent = content;
138+
break;
139+
case 'map':
140+
file.jsMapContent = content;
141+
break;
142+
}
143+
}
144+
private emit(result: CompilationResult, callback: ts.WriteFileCallback) {
145+
const emitOutput = this.program.emit(undefined, callback);
119146

120147
result.emitErrors += emitOutput.diagnostics.length;
121148
this.reportDiagnostics(emitOutput.diagnostics);
122149

123-
if (emitOutput.emitSkipped) {
124-
result.emitSkipped = true;
125-
}
126-
150+
result.emitSkipped = emitOutput.emitSkipped;
151+
}
152+
private emitFile({ file, jsFileName, dtsFileName, jsContent, dtsContent, jsMapContent }: OutputFile, currentDirectory: string) {
127153
if (!jsFileName) return;
128154

129155
let base: string;
@@ -163,6 +189,7 @@ export class ProjectCompiler implements ICompiler {
163189
for (const error of diagnostics) {
164190
this.project.output.diagnostic(error);
165191
}
192+
return diagnostics.length;
166193
}
167194

168195
private removeSourceMapComment(content: string): string {

0 commit comments

Comments
 (0)