Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How does gulp-typescript incremental compilation work?

gulp-typescript's README says it supports incremental compilation but doesn't explain what is meant by that term in this context.

There's an issue discussing how gulp-typescript incremental compilation is slower than tsc, but it doesn't explain why, or what the difference is.

What is gulp-typescript doing when it does "incremental compilation"?

What I tried

I'm looking at gulp-typescript's source code and it looks like gulp-typescript isn't doing any incremental compilation at all. When a Project is created, it closes over an instance of ProjectInfo, which has an input member which is a FileCache. A FileCache is pretty much a mapping from file names to source strings. There isn't much other state that is maintained in a gulp-typescript Project.

In order to do actual incremental compilation (reusing products of the compilation process in subsequent builds) using the TS compiler API, I would expect to see one of the following:

  • Using ts.createWatchCompilerHost API
  • Using ts.createLanguageService

But I don't see either of those in the source.

like image 321
Max Heiber Avatar asked Feb 15 '19 20:02

Max Heiber


2 Answers

Gulp-typescript has two different ways to compile your files. The default method compiles the whole project and does type checking. This is implemented in ProjectCompiler in lib/compiler.ts. The other compiles each file separate, and is activated when you set isolatedModules: true. That method is implemented in FileCompiler in lib/compiler.ts.

The FileCompiler only needs to compile the files which are changed. Unchanged files are cached, like Achmedzhanov described in his answer.

Most users however use the ProjectCompiler, as type checking is probably the reason that they are using TypeScript. I think that your question regards this ProjectCompiler. Incremental compilation is handled by the call to ts.createProgram, which the TypeScript API exports. By passing the old program, the TypeScript API would reuse some of the information of the previous compilation. You can find the source code here:

https://github.com/ivogabe/gulp-typescript/blob/ea22fb7fe4295979e32a9d07b007e3f7473be8b5/lib/compiler.ts#L80

That used to be enough to get incremental compilation, but that has changed in newer versions of TypeScript. We will need to switch to a new API, probably using one of the APIs you mentioned, but I'm not familiar with those.

In your question you mentioned the FileCache. This is used to store all files that are passed in the input stream. The gulp API namely gives all files in a stream, whereas the TypeScript API is synchronous. We thus need to wait until we have all input files. Furthermore, we use the FileCache in the FileCompiler to detect whether a file has changed and thus whether we need to recompile it.

like image 123
ivogabe Avatar answered Nov 08 '22 21:11

ivogabe


gulp-typescript caches compiled js files, when some file is changed then it compiles one https://github.com/ivogabe/gulp-typescript/blob/master/lib/compiler.ts#L282

if (this.project.input.getFileChange(file.fileNameOriginal).state === FileChangeState.Equal) {
    // Not changed, re-use old file.

    const old = this.previousOutput[file.fileNameNormalized];
    this.write(file, old.fileName, old.diagnostics, old.content, old.sourceMap);

    return;
}

const output: ts.TranspileOutput = this.project.typescript.transpileModule(file.content, {
    compilerOptions: this.project.options,
    fileName: file.fileNameOriginal,
    reportDiagnostics: true,
    transformers: this.finalTransformers ? this.finalTransformers() : undefined,
});

Even one file compilation causes analysis of imported dependecies so it couldn't be faster then tsc --watch

like image 1
Nail Achmedzhanov Avatar answered Nov 08 '22 20:11

Nail Achmedzhanov